import json
import math
import os
from pathlib import Path

ROOT = Path(".")

INPUT_MAIN = ROOT / "results" / "row20_h0_attribution" / "row20_thin_slice_attribution.json"
INPUT_FIRST = ROOT / "results" / "row20_h0_attribution" / "row20_NZ_CFGL_bridge_operator.json"
INPUT_CAPPED = ROOT / "results" / "row20_h0_attribution" / "row20_second_operator_capped_test.json"

OUTPUT_JSON = ROOT / "results" / "row20_h0_attribution" / "row20_BAO_H_wall_probe.json"
OUTPUT_REPORT = ROOT / "results" / "row20_h0_attribution" / "row20_BAO_H_wall_probe.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 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():
    main_data = load(INPUT_MAIN)
    first = load(INPUT_FIRST)
    capped = load(INPUT_CAPPED)

    bao = find_block(main_data, "BAO_DM_H")

    # Extract BAO nodes
    nodes = {n["slice"]: n for n in bao["nodes"]}

    h_0706 = nodes["H z=0.706"]
    dm_0706 = nodes["D_M z=0.706"]

    first_vec = first["transformed_residual_vector"]
    capped_vec = capped["transformed_residual_vector"]

    # After first operator, BAO H is the remaining early/radial limiter.
    bao_h_after_first = first_vec["r_H_BAO"]
    sn_after_first = first_vec["r_SN"]
    sh0es_after_first = first_vec["r_SH0ES"]

    # Desired second operator from SN pivot, but it exceeds BAO H.
    desired_second = abs(sn_after_first)
    allowed_second = bao_h_after_first
    blocked_amount = desired_second - allowed_second

    # Remaining after lawful capped second operator
    remaining_after_capped = capped_vec

    current_final_rss = capped["transformed_rss"]

    # BAO coupled observable test:
    # Use z=0.706 radial/transverse pair as a coupled 2D bridge.
    # This does not change data; it checks whether treating H and D_M as a signed pair
    # produces a wall because their pulls oppose each other.
    bao_pair_gap = h_0706["diag_pull_sigma"] - dm_0706["diag_pull_sigma"]
    bao_pair_mean = (h_0706["diag_pull_sigma"] + dm_0706["diag_pull_sigma"]) / 2.0
    bao_pair_half_gap = abs(bao_pair_gap) / 2.0

    # If H and D_M are treated as independent scalars, H is the limiter.
    # If treated as a coupled anisotropic pair, the natural bridge scale is D_M,
    # but H saturation remains because H residual is smaller after first transfer.
    interpretation = []

    interpretation.append(
        "BAO H is the wall because after the first NZ/CFGL bridge it is the smallest remaining positive early/radial residual."
    )

    if blocked_amount > 0:
        interpretation.append(
            "The SN-desired second operator exceeds the available BAO H headroom, so a full second transfer would flip BAO H."
        )

    if abs(bao_pair_gap) > 2:
        interpretation.append(
            "The original BAO z=0.706 H and D_M pulls form a significant radial/transverse split."
        )

    interpretation.append(
        "This indicates the current wall is a radial/transverse projection constraint, not a random residual."
    )

    # Decision:
    # If blocked amount is large relative to allowed second, v21 current machinery cannot fully pass without deeper BAO mapping.
    block_ratio = blocked_amount / desired_second if desired_second != 0 else 0.0

    if block_ratio > 0.5:
        status = "BAO_H_wall_requires_deeper_mapping"
        interpretation.append(
            "More than half of the desired second transfer is blocked by BAO H headroom; current v21 operators cannot fully resolve H0 without a deeper radial/transverse mapping."
        )
    else:
        status = "BAO_H_wall_may_be_resolvable_with_existing_operator"
        interpretation.append(
            "BAO H blocks only a small portion of the desired transfer; existing operators may still fully resolve the tension."
        )

    result = {
        "signature": "ROW20_BAO_H_WALL_PROBE_v1_NATIVE_DIAGNOSTIC",
        "context": "DIAGNOSTIC_NON_GATING",
        "BAO_z0_706_original": {
            "H_pull": h_0706["diag_pull_sigma"],
            "D_M_pull": dm_0706["diag_pull_sigma"],
            "H_minus_D_M_gap": bao_pair_gap,
            "mean_pull": bao_pair_mean,
            "half_gap": bao_pair_half_gap,
        },
        "after_first_operator": {
            "BAO_H_remaining": bao_h_after_first,
            "SN_remaining": sn_after_first,
            "SH0ES_remaining": sh0es_after_first,
            "desired_second_from_SN": desired_second,
            "allowed_second_before_BAO_H_flip": allowed_second,
            "blocked_amount": blocked_amount,
            "blocked_fraction_of_desired": block_ratio,
        },
        "after_capped_second_operator": {
            "residual_vector": remaining_after_capped,
            "rss": current_final_rss,
        },
        "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 — BAO H Wall Probe\n\n")
        f.write("**Context:** DIAGNOSTIC_NON_GATING. No physics, thresholds, datasets, parameters, or gate verdicts changed.\n\n")

        f.write("## Original BAO z=0.706 radial/transverse pair\n\n")
        f.write("| Quantity | Value |\n")
        f.write("|---|---:|\n")
        f.write(f"| H pull | {h_0706['diag_pull_sigma']:.6f} |\n")
        f.write(f"| D_M pull | {dm_0706['diag_pull_sigma']:.6f} |\n")
        f.write(f"| H - D_M gap | {bao_pair_gap:.6f} |\n")
        f.write(f"| pair mean pull | {bao_pair_mean:.6f} |\n")
        f.write(f"| pair half-gap | {bao_pair_half_gap:.6f} |\n\n")

        f.write("## BAO H wall after first operator\n\n")
        f.write("| Quantity | Value |\n")
        f.write("|---|---:|\n")
        f.write(f"| BAO H remaining | {bao_h_after_first:.6f} |\n")
        f.write(f"| SN remaining | {sn_after_first:.6f} |\n")
        f.write(f"| SH0ES remaining | {sh0es_after_first:.6f} |\n")
        f.write(f"| desired second transfer from SN | {desired_second:.6f} |\n")
        f.write(f"| allowed transfer before BAO H flip | {allowed_second:.6f} |\n")
        f.write(f"| blocked amount | {blocked_amount:.6f} |\n")
        f.write(f"| blocked fraction of desired | {block_ratio:.6f} |\n\n")

        f.write("## After capped second operator\n\n")
        f.write("| Node | Residual |\n")
        f.write("|---|---:|\n")
        for k, v in remaining_after_capped.items():
            f.write(f"| {k} | {v:.6f} |\n")
        f.write(f"\nFinal capped RSS: **{current_final_rss:.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("BAO H wall probe:")
    print(f"H pull original={h_0706['diag_pull_sigma']:.6f}")
    print(f"D_M pull original={dm_0706['diag_pull_sigma']:.6f}")
    print(f"H-D_M gap={bao_pair_gap:.6f}")
    print(f"BAO H remaining after first={bao_h_after_first:.6f}")
    print(f"desired second={desired_second:.6f}")
    print(f"allowed second={allowed_second:.6f}")
    print(f"blocked amount={blocked_amount:.6f}")
    print(f"blocked fraction={block_ratio:.6f}")
    print(f"final capped RSS={current_final_rss:.6f}")
    print(f"status={status}")


if __name__ == "__main__":
    main()