import json
import os
from pathlib import Path

ROOT = Path(".")
INPUT_JSON = ROOT / "results" / "row20_h0_attribution" / "row20_thin_slice_attribution.json"
OUTPUT_JSON = ROOT / "results" / "row20_h0_attribution" / "row20_ladder_probe.json"
OUTPUT_REPORT = ROOT / "results" / "row20_h0_attribution" / "row20_ladder_probe_REPORT.md"


def load_json(path):
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)


def find_block(data, tag):
    for block in data.get("blocks", []):
        if block.get("tag") == tag:
            return block
    raise ValueError(f"Block not found: {tag}")


def main():
    if not INPUT_JSON.exists():
        raise FileNotFoundError(f"Missing input JSON: {INPUT_JSON}")

    data = load_json(INPUT_JSON)
    sn = find_block(data, "SN")

    nodes = sn.get("nodes", [])
    nuisance = sn.get("nuisance", {})
    chi2 = sn["chi2"]
    dof = sn["dof"]
    chi2_per_dof = sn["chi2_per_dof"]

    sh0es = data["totals"]["SH0ES_overlay"]

    ranked = sorted(
        nodes,
        key=lambda n: abs(n.get("diag_pull_sigma", 0)),
        reverse=True
    )

    interpretation = []

    if chi2_per_dof > data["threshold_reference_chi2_per_dof"]:
        interpretation.append(
            "SN relative block is already stressed before SH0ES is added."
        )
    else:
        interpretation.append(
            "SN relative block is internally acceptable before SH0ES is added."
        )

    if abs(sh0es["pull_sigma"]) >= 5:
        interpretation.append(
            "SH0ES overlay is a strong high-side H0 outlier relative to the v21 baseline."
        )

    interpretation.append(
        "The ladder-side problem is not only the SH0ES overlay; the SN midpoint node also carries significant residual structure."
    )

    result = {
        "signature": "ROW20_LADDER_PROBE_v1_NATIVE_DIAGNOSTIC",
        "context": "DIAGNOSTIC_NON_GATING",
        "rules": data.get("rules", {}),
        "SN_block": {
            "chi2": chi2,
            "dof": dof,
            "chi2_per_dof": chi2_per_dof,
            "nuisance": nuisance,
            "ranked_nodes": ranked
        },
        "SH0ES_overlay": sh0es,
        "interpretation": interpretation,
        "verdict": (
            "ladder_side_structured_tension; diagnostic only; "
            "no physics, thresholds, datasets, parameters, or gate verdicts changed."
        )
    }

    OUTPUT_JSON.parent.mkdir(parents=True, exist_ok=True)

    with open(OUTPUT_JSON, "w", encoding="utf-8") as f:
        json.dump(result, f, indent=2)

    with open(OUTPUT_REPORT, "w", encoding="utf-8") as f:
        f.write("# UTFANSWF v21 — Row 20 Ladder-Side Probe\n\n")
        f.write("**Context:** DIAGNOSTIC_NON_GATING. No physics, thresholds, datasets, parameters, or gate verdicts changed.\n\n")

        f.write("## SN block\n\n")
        f.write("| Quantity | Value |\n")
        f.write("|---|---:|\n")
        f.write(f"| chi2 | {chi2:.6f} |\n")
        f.write(f"| dof | {dof} |\n")
        f.write(f"| chi2/dof | {chi2_per_dof:.6f} |\n\n")

        f.write("## SN nuisance handling\n\n")
        f.write("```json\n")
        f.write(json.dumps(nuisance, indent=2))
        f.write("\n```\n\n")

        f.write("## Ranked SN nodes\n\n")
        f.write("| Rank | Slice | data | theory | residual | pull sigma | chi2 contribution |\n")
        f.write("|---:|---|---:|---:|---:|---:|---:|\n")
        for i, n in enumerate(ranked, start=1):
            f.write(
                f"| {i} | {n['slice']} | "
                f"{n['data']:.6f} | "
                f"{n['theory']:.6f} | "
                f"{n['residual_after_gate_handling']:.6f} | "
                f"{n['diag_pull_sigma']:.6f} | "
                f"{n['white_chi2_contribution']:.6f} |\n"
            )

        f.write("\n## SH0ES overlay\n\n")
        f.write("| Quantity | Value |\n")
        f.write("|---|---:|\n")
        f.write(f"| H0_SH0ES | {sh0es['H0_SH0ES']:.6f} |\n")
        f.write(f"| sigma | {sh0es['sigma']:.6f} |\n")
        f.write(f"| pull sigma | {sh0es['pull_sigma']:.6f} |\n")
        f.write(f"| chi2 | {sh0es['chi2']:.6f} |\n\n")

        f.write("## Interpretation\n\n")
        for item in interpretation:
            f.write(f"- {item}\n")

        f.write("\n## Verdict\n\n")
        f.write(result["verdict"] + "\n")

    print("Wrote:")
    print(os.path.abspath(OUTPUT_JSON))
    print(os.path.abspath(OUTPUT_REPORT))
    print()
    print("Ladder-side probe:")
    print(f"SN chi2/dof={chi2_per_dof:.6f}")
    print(f"SH0ES pull={sh0es['pull_sigma']:.6f} sigma")
    print("Top SN node:")
    top = ranked[0]
    print(f"{top['slice']} pull={top['diag_pull_sigma']:.6f} sigma")


if __name__ == "__main__":
    main()