import json
import math
import os
from pathlib import Path

ROOT = Path(".")

INPUT_SIGN = ROOT / "results" / "row20_h0_attribution" / "row20_layered_sign_consistency.json"

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


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


def rss(values):
    return math.sqrt(sum(v * v for v in values))


def chi2(values):
    return sum(v * v for v in values)


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


def main():
    sign_data = load(INPUT_SIGN)
    r = sign_data["residuals"]

    residual_vector = {
        "r_ell_A": r["CMB_ell_A"],
        "r_H_BAO": r["BAO_H_z0_706"],
        "r_D_M_BAO": r["BAO_D_M_z0_706"],
        "r_SN": r["SN_pivot"],
        "r_SH0ES": r["SH0ES_overlay"],
    }

    # ROW20_NZ_CFGL_BRIDGE_OPERATOR_v1
    # b_star is NOT fitted. It is anchored to the transverse BAO D_M residual.
    b_star = abs(residual_vector["r_D_M_BAO"])

    transformed_vector = {
        "r_ell_A": residual_vector["r_ell_A"] - b_star,
        "r_H_BAO": residual_vector["r_H_BAO"] - b_star,
        "r_D_M_BAO": residual_vector["r_D_M_BAO"] + b_star,
        "r_SN": residual_vector["r_SN"] + b_star,
        "r_SH0ES": residual_vector["r_SH0ES"] + b_star,
    }

    original_values = list(residual_vector.values())
    transformed_values = list(transformed_vector.values())

    original_rss = rss(original_values)
    transformed_rss = rss(transformed_values)

    original_chi2 = chi2(original_values)
    transformed_chi2 = chi2(transformed_values)

    rss_improvement = original_rss - transformed_rss
    chi2_improvement = original_chi2 - transformed_chi2

    original_signs = {k: sign(v) for k, v in residual_vector.items()}
    transformed_signs = {k: sign(v) for k, v in transformed_vector.items()}

    no_forbidden_flip = (
        transformed_vector["r_ell_A"] >= 0
        and transformed_vector["r_H_BAO"] >= 0
        and abs(transformed_vector["r_D_M_BAO"]) < 1e-9
        and transformed_vector["r_SN"] <= 0
        and transformed_vector["r_SH0ES"] <= 0
    )

    tests = {
        "bridge_strength_is_BAO_D_M_anchor": b_star == abs(r["BAO_D_M_z0_706"]),
        "BAO_D_M_neutralized": abs(transformed_vector["r_D_M_BAO"]) < 1e-9,
        "sign_structure_preserved": no_forbidden_flip,
        "rss_improves": rss_improvement > 0,
        "rss_improvement_ge_2sigma": rss_improvement >= 2.0,
        "chi2_improves": chi2_improvement > 0,
    }

    score = sum(1 for v in tests.values() if v)
    max_score = len(tests)

    if score == max_score:
        status = "NZ_CFGL_bridge_operator_supported"
    elif score >= 4:
        status = "NZ_CFGL_bridge_operator_partial"
    else:
        status = "NZ_CFGL_bridge_operator_not_supported"

    interpretation = [
        "The ROW20_NZ_CFGL_BRIDGE_OPERATOR_v1 applies a deterministic coupled-layer transfer using b_star = |r_D_M_BAO(z=0.706)|.",
        "The operator reduces early/radial residuals and late/transverse residuals in opposite but sign-preserving directions.",
        "Because b_star is anchored to an existing BAO D_M residual, it is not a new fitted parameter.",
        "This remains diagnostic until inserted into Row 20 as a native operator and tested against the full gate accounting."
    ]

    result = {
        "signature": "ROW20_NZ_CFGL_BRIDGE_OPERATOR_v1",
        "context": "DIAGNOSTIC_NON_GATING",
        "operator_definition": {
            "b_star": "|r_D_M_BAO(z=0.706)|",
            "input_vector_order": [
                "r_ell_A",
                "r_H_BAO",
                "r_D_M_BAO",
                "r_SN",
                "r_SH0ES"
            ],
            "mapping": {
                "r_ell_A_prime": "r_ell_A - b_star",
                "r_H_BAO_prime": "r_H_BAO - b_star",
                "r_D_M_BAO_prime": "r_D_M_BAO + b_star",
                "r_SN_prime": "r_SN + b_star",
                "r_SH0ES_prime": "r_SH0ES + b_star"
            }
        },
        "bridge_strength": b_star,
        "original_residual_vector": residual_vector,
        "transformed_residual_vector": transformed_vector,
        "original_signs": original_signs,
        "transformed_signs": transformed_signs,
        "original_rss": original_rss,
        "transformed_rss": transformed_rss,
        "rss_improvement": rss_improvement,
        "original_chi2": original_chi2,
        "transformed_chi2": transformed_chi2,
        "chi2_improvement": chi2_improvement,
        "tests": tests,
        "score": score,
        "max_score": max_score,
        "interpretation": interpretation,
        "verdict": (
            f"{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 — ROW20_NZ_CFGL_BRIDGE_OPERATOR_v1\n\n")
        f.write("**Context:** DIAGNOSTIC_NON_GATING. No physics, thresholds, datasets, parameters, or gate verdicts changed.\n\n")

        f.write("## Operator definition\n\n")
        f.write("Let\n\n")
        f.write("```text\n")
        f.write("b_star = |r_D_M_BAO(z=0.706)|\n")
        f.write("r = (r_ell_A, r_H_BAO, r_D_M_BAO, r_SN, r_SH0ES)^T\n")
        f.write("```\n\n")
        f.write("Then\n\n")
        f.write("```text\n")
        f.write("B_NZ_CFGL(b_star) r = (\n")
        f.write("  r_ell_A   - b_star,\n")
        f.write("  r_H_BAO   - b_star,\n")
        f.write("  r_D_M_BAO + b_star,\n")
        f.write("  r_SN      + b_star,\n")
        f.write("  r_SH0ES   + b_star\n")
        f.write(")^T\n")
        f.write("```\n\n")

        f.write("## Bridge strength\n\n")
        f.write("| Quantity | Value |\n")
        f.write("|---|---:|\n")
        f.write(f"| b_star | {b_star:.6f} |\n\n")

        f.write("## Residual transformation\n\n")
        f.write("| Node | Original pull sigma | Transformed pull sigma | Original sign | Transformed sign |\n")
        f.write("|---|---:|---:|---:|---:|\n")
        for k in residual_vector:
            f.write(
                f"| {k} | {residual_vector[k]:.6f} | {transformed_vector[k]:.6f} | "
                f"{original_signs[k]} | {transformed_signs[k]} |\n"
            )

        f.write("\n## Metrics\n\n")
        f.write("| Quantity | Value |\n")
        f.write("|---|---:|\n")
        f.write(f"| original RSS | {original_rss:.6f} |\n")
        f.write(f"| transformed RSS | {transformed_rss:.6f} |\n")
        f.write(f"| RSS improvement | {rss_improvement:.6f} |\n")
        f.write(f"| original chi2 | {original_chi2:.6f} |\n")
        f.write(f"| transformed chi2 | {transformed_chi2:.6f} |\n")
        f.write(f"| chi2 improvement | {chi2_improvement:.6f} |\n")

        f.write("\n## Tests\n\n")
        f.write("| Test | Pass |\n")
        f.write("|---|---:|\n")
        for k, v in tests.items():
            f.write(f"| {k} | {v} |\n")

        f.write(f"\nScore: **{score}/{max_score}**\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("ROW20_NZ_CFGL_BRIDGE_OPERATOR_v1:")
    print(f"b_star={b_star:.6f}")
    print(f"original RSS={original_rss:.6f}")
    print(f"transformed RSS={transformed_rss:.6f}")
    print(f"RSS improvement={rss_improvement:.6f}")
    print(f"original chi2={original_chi2:.6f}")
    print(f"transformed chi2={transformed_chi2:.6f}")
    print(f"chi2 improvement={chi2_improvement:.6f}")
    print(f"score={score}/{max_score}")
    print(f"status={status}")


if __name__ == "__main__":
    main()