import json
import os
from pathlib import Path

ROOT = Path(".")

INPUT_MAIN = ROOT / "results" / "row20_h0_attribution" / "row20_thin_slice_attribution.json"
INPUT_LA = ROOT / "results" / "row20_h0_attribution" / "row20_lA_probe.json"
INPUT_SN_OFFSET = ROOT / "results" / "row20_h0_attribution" / "row20_SN_offset_probe.json"
INPUT_BAO = ROOT / "results" / "row20_h0_attribution" / "row20_BAO_bridge_probe.json"

OUTPUT_JSON = ROOT / "results" / "row20_h0_attribution" / "row20_joint_residual_minimap.json"
OUTPUT_REPORT = ROOT / "results" / "row20_h0_attribution" / "row20_joint_residual_minimap.md"


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


def sign(x):
    if x > 0:
        return "+"
    if x < 0:
        return "-"
    return "0"


def main():
    main_data = load(INPUT_MAIN)
    la = load(INPUT_LA)
    sn_offset = load(INPUT_SN_OFFSET)
    bao = load(INPUT_BAO)

    ellA_pull = la["ell_A"]["diag_pull_sigma"]
    ellA_frac = la["ell_A"]["fractional_required_shift"]

    sn_pivot_pull = sn_offset["pivot_geometry"]["global_recentered_pivot_pull"]

    bao_H = bao["z_0_706_projection"]["H"]["pull"]
    bao_DM = bao["z_0_706_projection"]["D_M"]["pull"]
    bao_gap = bao["z_0_706_projection"]["pull_gap_H_minus_DM"]
    bao_chi2 = bao["z_0_706_projection"]["combined_chi2"]

    sh0es = main_data["totals"]["SH0ES_overlay"]["pull_sigma"]

    residual_vector = {
        "CMB_ell_A": {
            "pull_sigma": ellA_pull,
            "sign": sign(ellA_pull),
            "role": "early acoustic anchor",
        },
        "SN_z0_35_pivot": {
            "pull_sigma": sn_pivot_pull,
            "sign": sign(sn_pivot_pull),
            "role": "late distance curvature pivot",
        },
        "BAO_z0_706_H": {
            "pull_sigma": bao_H,
            "sign": sign(bao_H),
            "role": "radial bridge",
        },
        "BAO_z0_706_D_M": {
            "pull_sigma": bao_DM,
            "sign": sign(bao_DM),
            "role": "transverse bridge",
        },
        "SH0ES_overlay": {
            "pull_sigma": sh0es,
            "sign": sign(sh0es),
            "role": "late ladder overlay",
        },
    }

    # Diagnostic logic:
    # If all major pulls share sign, one monotonic mapping correction might solve them.
    # If signs oppose across layers, a single monotonic shift cannot solve all simultaneously.
    major = [ellA_pull, sn_pivot_pull, bao_H, bao_DM]
    signs = {sign(x) for x in major if abs(x) > 1.0}

    interpretation = []

    interpretation.append(
        "This minimap tests whether a single monotonic mapping axis can reduce the dominant H0-related residuals together."
    )

    if len(signs) == 1:
        interpretation.append(
            "Major residuals share one sign; a single monotonic mapping correction remains plausible."
        )
        resolution_status = "single_axis_resolution_plausible"
    else:
        interpretation.append(
            "Major residuals have opposing signs; a single monotonic mapping correction is unlikely to reduce all stresses simultaneously."
        )
        resolution_status = "single_axis_resolution_unlikely"

    if sign(bao_H) != sign(bao_DM):
        interpretation.append(
            "BAO z≈0.706 has opposite-sign H and D_M pulls, indicating a radial/transverse bridge split."
        )

    if sign(ellA_pull) != sign(sn_pivot_pull):
        interpretation.append(
            "CMB ell_A and SN pivot pull in opposite signs, meaning early anchor and late curvature do not move together under a simple offset."
        )

    if abs(bao_gap) > 2:
        interpretation.append(
            "The BAO bridge gap exceeds 2 sigma and must be resolved or formally attributed before an H0-resolution claim is publishable."
        )

    interpretation.append(
        "A true solution now requires a nontrivial existing-v21 mapping relation that can reduce ell_A, SN pivot curvature, and BAO radial/transverse split without new freedom."
    )

    result = {
        "signature": "ROW20_JOINT_RESIDUAL_MINIMAP_v1_NATIVE_DIAGNOSTIC",
        "context": "DIAGNOSTIC_NON_GATING",
        "rules": main_data.get("rules", {}),
        "residual_vector": residual_vector,
        "coupling_tests": {
            "major_residual_signs": sorted(list(signs)),
            "BAO_H_minus_DM_gap_sigma": bao_gap,
            "BAO_z0_706_combined_chi2": bao_chi2,
            "ell_A_fractional_shift_to_match_data": ellA_frac,
            "resolution_status": resolution_status,
        },
        "interpretation": interpretation,
        "verdict": (
            f"{resolution_status}; 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 Joint Residual Minimap\n\n")
        f.write("**Context:** DIAGNOSTIC_NON_GATING. No physics, thresholds, datasets, parameters, or gate verdicts changed.\n\n")

        f.write("## Residual vector\n\n")
        f.write("| Node | Pull σ | Sign | Role |\n")
        f.write("|---|---:|---:|---|\n")
        for key, item in residual_vector.items():
            f.write(f"| {key} | {item['pull_sigma']:.6f} | {item['sign']} | {item['role']} |\n")

        f.write("\n## Coupling tests\n\n")
        f.write("| Quantity | Value |\n")
        f.write("|---|---:|\n")
        f.write(f"| BAO H-D_M gap σ | {bao_gap:.6f} |\n")
        f.write(f"| BAO z≈0.706 combined χ² | {bao_chi2:.6f} |\n")
        f.write(f"| ell_A fractional shift | {ellA_frac:.9e} |\n")
        f.write(f"| resolution status | {resolution_status} |\n")

        f.write("\n## 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("Joint residual minimap:")
    print(f"CMB ell_A = {ellA_pull:.6f} sigma")
    print(f"SN pivot = {sn_pivot_pull:.6f} sigma")
    print(f"BAO H = {bao_H:.6f} sigma")
    print(f"BAO D_M = {bao_DM:.6f} sigma")
    print(f"BAO gap = {bao_gap:.6f} sigma")
    print(f"status = {resolution_status}")


if __name__ == "__main__":
    main()