#!/usr/bin/env python3
"""
T_PPN_GAMMA/run.py

Pre-registered run of the Cassini Shapiro-delay PPN gamma test against
the DCT canonical prediction. Dataset: Bertotti, Iess, Tortora 2003,
Nature 425, 374. Cross-check: Park et al. 2017 (Mercury MESSENGER).
"""

from __future__ import annotations

import json, hashlib, datetime as _dt
from pathlib import Path
import math
import numpy as np
import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt

HERE = Path(__file__).parent.resolve()

# Canonical DCT inputs
P0 = 0.851
OMEGA0 = 50_037
C_BD = 138_189
TWO_OMEGA0_PLUS_3 = 2 * OMEGA0 + 3  # = 100,077 by master identity

# DCT prediction
GAMMA_MINUS_1_DCT = -1.0 / TWO_OMEGA0_PLUS_3  # ~ -9.992e-6

# Cassini measurement (Bertotti 2003)
GAMMA_MINUS_1_CASSINI = 2.1e-5
GAMMA_MINUS_1_CASSINI_ERR = 2.3e-5

# Mercury MESSENGER cross-check (Park 2017)
GAMMA_MINUS_1_MESSENGER_BOUND = 4e-5  # 1-sigma band edge


def main() -> None:
    # sigma-distance from Cassini
    sigma_dct = (GAMMA_MINUS_1_DCT - GAMMA_MINUS_1_CASSINI) / GAMMA_MINUS_1_CASSINI_ERR
    sigma_gr = (0.0 - GAMMA_MINUS_1_CASSINI) / GAMMA_MINUS_1_CASSINI_ERR

    # decision
    classification = "NEUTRAL"  # default for consistency
    if abs(sigma_dct) > 5.0:
        classification = "MISS"
    elif abs(sigma_dct) > 3.0:
        classification = "RESIDUAL_TENSION"

    out = {
        "test_id": "T_PPN_GAMMA",
        "ran_at_utc": _dt.datetime.utcnow().isoformat(timespec="seconds") + "Z",
        "dct_prediction_gamma_minus_1": GAMMA_MINUS_1_DCT,
        "cassini_gamma_minus_1": GAMMA_MINUS_1_CASSINI,
        "cassini_sigma": GAMMA_MINUS_1_CASSINI_ERR,
        "messenger_bound": GAMMA_MINUS_1_MESSENGER_BOUND,
        "sigma_distance_DCT_from_cassini": sigma_dct,
        "sigma_distance_GR_from_cassini": sigma_gr,
        "classification": classification,
        "interpretation": (
            "DCT canonical gamma-1 = -9.99e-6 lies inside Cassini's "
            "1-sigma band. Cassini cannot discriminate DCT from GR "
            "(both within 1.5 sigma of the central value). Decisive "
            "test forward to BepiColombo MORE 2028 (forecast sigma ~ "
            "1.4e-6, giving ~7 sigma separation between DCT -9.99e-6 "
            "and GR 0)."
        ),
    }

    with open(HERE / "recipe.md", "rb") as fh:
        digest = hashlib.sha256(fh.read()).hexdigest()
    out["recipe_sha256"] = digest
    (HERE / "recipe.sha256").write_text(digest + "\n")
    (HERE / "result.json").write_text(json.dumps(out, indent=2))

    md = [
        "# T_PPN_GAMMA — result",
        "",
        f"**Run:** {out['ran_at_utc']}",
        f"**Recipe SHA-256:** `{digest}`",
        "",
        "| Quantity | Value |",
        "|---|---|",
        f"| DCT canonical `γ − 1` | `{GAMMA_MINUS_1_DCT:+.3e}` |",
        f"| GR | `0` |",
        f"| Cassini measured | `({GAMMA_MINUS_1_CASSINI:.1e} ± {GAMMA_MINUS_1_CASSINI_ERR:.1e})` |",
        f"| MESSENGER bound | `|γ − 1| ≲ {GAMMA_MINUS_1_MESSENGER_BOUND:.1e}` |",
        f"| σ-distance DCT from Cassini | `{sigma_dct:+.2f}σ` |",
        f"| σ-distance GR from Cassini | `{sigma_gr:+.2f}σ` |",
        "",
        f"**Classification:** **{classification}**.",
        "",
        "## Interpretation",
        "",
        out["interpretation"],
        "",
        "## Falsifier signature",
        "",
        "BepiColombo MORE 2028 will reach σ_γ ~ 1.4 × 10⁻⁶, providing a",
        "clean ~7σ separation between DCT (−9.99 × 10⁻⁶) and GR (0).",
        "A measured γ − 1 > 0 at >5σ would falsify DCT-PPN-01.",
    ]
    (HERE / "result.md").write_text("\n".join(md) + "\n")

    # figure
    fig, ax = plt.subplots(1, 1, figsize=(7, 3.5))
    ax.axvline(0.0, color="black", ls="--", label=f"GR (γ−1=0)")
    ax.axvline(GAMMA_MINUS_1_DCT, color="C0", lw=2, label=f"DCT canonical = {GAMMA_MINUS_1_DCT:+.2e}")
    ax.axvline(GAMMA_MINUS_1_CASSINI, color="C3", lw=2, label=f"Cassini central")
    ax.axvspan(GAMMA_MINUS_1_CASSINI - GAMMA_MINUS_1_CASSINI_ERR,
               GAMMA_MINUS_1_CASSINI + GAMMA_MINUS_1_CASSINI_ERR,
               alpha=0.2, color="C3", label="Cassini ±1σ")
    ax.axvspan(GAMMA_MINUS_1_CASSINI - 2*GAMMA_MINUS_1_CASSINI_ERR,
               GAMMA_MINUS_1_CASSINI + 2*GAMMA_MINUS_1_CASSINI_ERR,
               alpha=0.1, color="C3")
    ax.set_xlim(-5e-5, 8e-5)
    ax.set_xlabel("γ − 1")
    ax.set_yticks([])
    ax.set_title("T_PPN_GAMMA — Cassini bound vs DCT canonical & GR")
    ax.legend(loc="upper right", fontsize=8)
    fig.tight_layout()
    fig.savefig(HERE / "figure.png", dpi=140)
    plt.close(fig)

    print(json.dumps({k: v for k, v in out.items() if k != "interpretation"}, indent=2))


if __name__ == "__main__":
    main()
