from __future__ import annotations

from pathlib import Path

import pandas as pd


OUT = Path(r"C:\Users\yauki\Documents\Codex\2026-06-27\codex-codex-remaining-k-chain-64\outputs")
TRANSITIONS = ["96-127 -> 64-95", "64-95 -> 32-63", "32-63 -> 16-31"]


def fmt(x) -> str:
    try:
        v = float(x)
    except (TypeError, ValueError):
        return str(x)
    if pd.isna(v):
        return "nan"
    return f"{v:.6g}"


def top_patterns(features: pd.DataFrame, transition: str, positive: bool = True, n: int = 8) -> pd.DataFrame:
    sub = features[
        (features["transition"] == transition)
        & (
            features["feature_type"].isin(
                [
                    "transition_k",
                    "pre_k_window_3",
                    "pre_k_window_5",
                    "k_prefix_3",
                    "k_prefix_5",
                    "local_rolling_k_window_3",
                    "local_rolling_k_window_4",
                ]
            )
        )
    ].copy()
    sub["pass_share_delta_num"] = sub["pass_share_delta"].astype(float)
    sub = sub[sub["pass_share_delta_num"] > 0] if positive else sub[sub["pass_share_delta_num"] < 0]
    return sub.sort_values("pass_share_delta_num", ascending=not positive).head(n)


def route_lines(route: pd.DataFrame, transition: str) -> list[str]:
    sub = route[route["transition"] == transition].copy()
    all_row = sub[sub["entry_route"] == "ALL"].iloc[0]
    actual_total = float(all_row["actual_from_mass"])
    iid_total = float(all_row["iid_from_mass"])
    lines = [
        f"- ALL: actual from `{fmt(all_row['actual_from_mass'])}`, iid from `{fmt(all_row['iid_from_mass'])}`, mass Δ `{fmt(all_row['mass_delta'])}`, actual pass `{fmt(all_row['actual_pass_rate'])}`, iid pass `{fmt(all_row['iid_pass_rate'])}`, conditional Δ `{fmt(all_row['conditional_delta'])}`."
    ]
    for r in sub[sub["entry_route"] != "ALL"].itertuples(index=False):
        actual_share = float(r.actual_from_mass) / actual_total if actual_total else float("nan")
        iid_share = float(r.iid_from_mass) / iid_total if iid_total else float("nan")
        lines.append(
            f"- `{r.entry_route}`: actual route share `{fmt(actual_share)}`, iid route share `{fmt(iid_share)}`, actual pass `{fmt(r.actual_pass_rate)}`, iid pass `{fmt(r.iid_pass_rate)}`, conditional Δ `{fmt(r.conditional_delta)}` ({r.support_note} support)."
        )
    return lines


def focus_lines(focus: pd.DataFrame, transition: str) -> list[str]:
    sub = focus[(focus["transition"] == transition) & (focus["focus_state"] == "late_growth|deep_32_63|even")].copy()
    if sub.empty:
        return ["- `late_growth|deep_32_63|even`: no supported row for this transition in the sampled universe."]
    lines = []
    for r in sub.itertuples(index=False):
        lines.append(
            f"- route `{r.entry_route}`: actual from `{fmt(r.actual_from_mass)}`, iid from `{fmt(r.iid_from_mass)}`, mass Δ `{fmt(r.mass_delta)}`, actual pass `{fmt(r.actual_pass_rate)}`, iid pass `{fmt(r.iid_pass_rate)}`, conditional Δ `{fmt(r.conditional_delta)}` ({r.support_note} support)."
        )
    return lines


def pattern_lines(features: pd.DataFrame, transition: str) -> list[str]:
    pos = top_patterns(features, transition, positive=True, n=6)
    neg = top_patterns(features, transition, positive=False, n=4)
    lines = ["Positive pass-side concentrations:"]
    for r in pos.itertuples(index=False):
        lines.append(
            f"- `{r.feature_type}` `{r.pattern}`: pass-share Δ `{fmt(r.pass_share_delta)}`, support `{fmt(r.support)}` ({r.support_note})."
        )
    lines.append("Negative/depleted pass-side concentrations:")
    for r in neg.itertuples(index=False):
        lines.append(
            f"- `{r.feature_type}` `{r.pattern}`: pass-share Δ `{fmt(r.pass_share_delta)}`, support `{fmt(r.support)}` ({r.support_note})."
        )
    return lines


def main() -> None:
    route = pd.read_csv(OUT / "paradoxical_sequence_entry_route.csv")
    focus = pd.read_csv(OUT / "paradoxical_sequence_by_focus_state.csv")
    features = pd.read_csv(OUT / "paradoxical_sequence_k_window_delta.csv")
    examples = pd.read_csv(OUT / "paradoxical_sequence_transition_examples.csv")

    lines: list[str] = [
        "# Paradoxical Sequence Analysis",
        "",
        "## 目的",
        "",
        "`remaining_K` chain で確認された、同じ帯の mass deficit と下流 conditional excess が同時に立つ逆符号現象を、sequence / k-pattern / state / entry route に分解する。これは観測解析であり、原因や生成機構の証明ではない。",
        "",
        "## 対象遷移",
        "",
        "- `96-127 -> 64-95`",
        "- `64-95 -> 32-63`",
        "- `32-63 -> 16-31`",
        "",
        "## 全体結果",
        "",
    ]
    all_route = route[route["entry_route"] == "ALL"].set_index("transition").loc[TRANSITIONS].reset_index()
    for r in all_route.itertuples(index=False):
        lines.append(
            f"- `{r.transition}`: from mass Δ `{fmt(r.mass_delta)}`, actual pass率 `{fmt(r.actual_pass_rate)}`, iid pass率 `{fmt(r.iid_pass_rate)}`, conditional Δ `{fmt(r.conditional_delta)}`, support `{fmt(r.support)}`."
        )
    lines.extend(
        [
            "",
            "3対象すべてで、from-bin mass は actual 側が薄い一方、pass率は actual 側が高い。conditional excess 自体は `96-127 -> 64-95` が最大だが、support は小さい。質量差の大きさは `32-63 -> 16-31` と `64-95 -> 32-63` の方が安定して読むべき対象になる。",
            "",
            "## Transition ごとの解析",
            "",
        ]
    )
    for transition in TRANSITIONS:
        lines.append(f"### {transition}")
        lines.append("")
        lines.append("Pass vs Stay / Entry Route:")
        lines.extend(route_lines(route, transition))
        lines.append("")
        lines.append("Focus State (`late_growth|deep_32_63|even`):")
        lines.extend(focus_lines(focus, transition))
        lines.append("")
        lines.extend(pattern_lines(features, transition))
        lines.append("")

    example_counts = examples.groupby(["transition", "source", "group"]).size().reset_index(name="rows")
    lines.extend(
        [
            "## 代表系列",
            "",
            "`paradoxical_sequence_transition_examples.csv` に、各 transition/source/group ごとの代表系列を保存した。行数は以下。",
            "",
        ]
    )
    for r in example_counts.itertuples(index=False):
        lines.append(f"- `{r.transition}` / `{r.source}` / `{r.group}`: `{r.rows}` rows")

    lines.extend(
        [
            "",
            "## Entry Route の読み",
            "",
            "- `96-127 -> 64-95` は今回の観測範囲では `START_IN_LAYER` のみ。上流 `128+` からの流入はこの母集団では見えない。",
            "- `64-95 -> 32-63` は `START_IN_LAYER` 側に conditional excess が集中し、`INFLOW_FROM_96-127` 側はほぼ同率かやや negative。したがって、この遷移の conditional excess は混合比だけではなく、開始群側の pass率差と対応している。",
            "- `32-63 -> 16-31` は `START_IN_LAYER` と `INFLOW_FROM_64-95` の両方が positive。mass deficit は inflow 側で大きいが、pass率差は両側に薄く広がる。",
            "",
            "## k-pattern の読み",
            "",
            "- `64-95 -> 32-63` では `transition_k=1` と `pre_k_window_3=1,1,1` が actual pass 側に強く寄る。これは今回の中で最も読みやすい sequence-level concentration。",
            "- `32-63 -> 16-31` では `transition_k=2`, `pre_k_window_3=1,1,2`, `pre_k_window_5=1,1,1,1,2` が pass 側に寄る。support は比較的十分。",
            "- `96-127 -> 64-95` は conditional Δ は最大だが、上位patternの多くが low support。ここは観測候補として扱い、強い主張にしない。",
            "",
            "## 観測の限界",
            "",
            "- 前回と同じ sampled long-word / final-state-defined universe を用いた。全列挙ではない。",
            "- `support_note=low` は重み付き support `< 0.002` とした。low support の pattern は安定主張ではなく候補。",
            "- rolling window は transition 近傍の局所窓に限定した。全語内の全window頻度ではない。",
            "- ここで言えるのは、逆符号現象を担う sequence 群・状態・流入経路との対応であり、原因ではない。",
            "",
            "## 次に調べる候補",
            "",
            "1. `64-95 -> 32-63` の `transition_k=1` / `pre_k_window_3=1,1,1` を大きめ iid sample で安定性確認する。",
            "2. `32-63 -> 16-31` の `START_IN_LAYER` と `INFLOW_FROM_64-95` を分け、`1,1,2` 系がどちらに濃いかを見る。",
            "3. `96-127 -> 64-95` は support を増やすか、現時点では低サポート候補として保留する。",
        ]
    )
    (OUT / "paradoxical_sequence_report.md").write_text("\n".join(lines) + "\n", encoding="utf-8")


if __name__ == "__main__":
    main()
