#!/usr/bin/env python3
"""
verify_P070.py -- Addendum 70: Phase 5b midpoint conjecture.

This verifier checks:
  * Candidate I/II and midpoint arithmetic for E_R
  * the half-splitting and Wolfenstein order-by-order table
  * the internal proof logic for the theta23 correction
  * the m_nu3 value inferred from the midpoint formula
"""

import math
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))
from verify_common import CheckResult, Verifier


class ModernVerifier(Verifier):
    """Local adapter: tolerance logic inherited byte-identical from
    verify_common.Verifier; only the output layer is modernised."""

    def __init__(self, name: str) -> None:
        self.name = name
        self.results = []
        print(name)

    def record(self, label, ok, computed="", claimed="", detail=""):
        self.results.append(CheckResult(label, ok, computed, claimed, detail))
        n = len(self.results)
        desc = f"{label} -- {detail}" if detail else label
        print(f"  [{'PASS' if ok else 'FAIL'}] {n:>2}. {desc}")
        if computed != "" or claimed != "":
            print(f"        computed: {computed}")
            print(f"        claimed : {claimed}")
        return ok

    def summary(self):
        passed = sum(r.ok for r in self.results)
        failed = len(self.results) - passed
        print(f"\n{'='*60}\nRESULT: {passed} PASS / {failed} FAIL")
        return 1 if failed else 0


v = ModernVerifier("P070 -- Phase 5b Midpoint Closure")

ROOT = Path(__file__).resolve().parents[1]
TEX = (ROOT / "70_Addendum_PhaseVbClosure.tex").read_text()

PI = math.pi
MU0 = 4 * PI**3 + PI**2 + PI
MU1 = 16 * PI**3 / 5 + 3 * PI**2 / 4 + 2 * PI / 3
MU = MU1 / MU0
E_PL_CANON = 68.096
E_R_OBS = 56.502
SIGMA_E = 0.0088
LAMBDA_W = math.sin(PI / 14)
THETA_C = PI / 14
ME_MEV = 0.511
E_V_CANON = 19.636
DM31 = 2.453e-3


def pct(value: float, target: float) -> float:
    return 100 * (value - target) / target


eps_i = MU * PI / 6
eps_ii = MU / 2
e_r_i = E_PL_CANON - 12 + eps_i
e_r_ii = E_PL_CANON - 12 + eps_ii
eps_mid = MU * (PI + 3) / 12
e_r_mid = E_PL_CANON - 12 + eps_mid
half_split = MU * (PI - 3) / 12

v.check("MU", MU, 0.793338, rel=1e-5)
v.check("Candidate I epsilon = MU*pi/6", eps_i, 0.4154, rel=5e-4)
v.check("Candidate II epsilon = MU/2", eps_ii, 0.3967, rel=5e-4)
v.check("Candidate I E_R", e_r_i, 56.511, abs_tol=0.001)
v.check("Candidate II E_R", e_r_ii, 56.493, abs_tol=0.001)
v.check("midpoint correction (pi+3)/12", (PI + 3) / 12, 0.511799388, rel=1e-8)
v.check("midpoint epsilon", eps_mid, 0.406068, rel=2e-4)
v.check("midpoint E_R", e_r_mid, 56.502, abs_tol=0.001)
v.check("arithmetic midpoint of candidates", (e_r_i + e_r_ii) / 2, e_r_mid, abs_tol=1e-12)
v.check("half-splitting", half_split, 0.009359, rel=5e-4)
v.check("half-splitting sigma", half_split / SIGMA_E, 1.063, rel=1e-3)
v.check("mean E6 exponent", (1 + 4 + 5 + 7 + 8 + 11) / 6, 6.0, rel=1e-12)
v.check("N_gen from half mean E6 exponent", ((1 + 4 + 5 + 7 + 8 + 11) / 6) / 2, 3.0, rel=1e-12)

delta_w2 = LAMBDA_W**2 / (2 * MU)
v.check("Wolfenstein O(lambda^2) spectral correction", delta_w2, 0.03120, rel=5e-4)
v.check("Wolfenstein O(lambda^2) factor vs 0.009", delta_w2 / 0.009, 3.47, rel=5e-3)
v.check("Wolfenstein O(lambda^2) factor vs half-splitting", delta_w2 / half_split, 3.33, rel=5e-3)
v.record(
    "theta23 extraction proof avoids singular derivative at maximal mixing",
    "-2\\tan(2\\theta_{23})" not in TEX,
    "proof writes tan(2 theta23) at theta23=pi/4 and then sets it to 1",
    "finite/quadratic expansion",
    "Expected fail: tan(pi/2) is singular while d sin^2(2theta)/dtheta is zero at maximal mixing; the displayed derivation is not valid as written.",
)

orders = {
    "MU lambda": MU * LAMBDA_W,
    "MU theta": MU * THETA_C,
    "MU lambda^2": MU * LAMBDA_W**2,
    "lambda^2/(2 MU)": LAMBDA_W**2 / (2 * MU),
    "MU theta^2": MU * THETA_C**2,
    "MU lambda^3": MU * LAMBDA_W**3,
    "MU theta^3": MU * THETA_C**3,
    "MU lambda^4": MU * LAMBDA_W**4,
}
claimed = {
    "MU lambda": 0.17649,
    "MU theta": 0.17803,
    "MU lambda^2": 0.039274,
    "lambda^2/(2 MU)": 0.031199,
    "MU theta^2": 0.039932,
    "MU lambda^3": 0.008749,
    "MU theta^3": 0.008966,
    "MU lambda^4": 0.001947,
}
for key, target in claimed.items():
    v.check(f"order table {key}", orders[key], target, rel=1e-3)

lambda3_gap = pct(orders["MU lambda^3"], half_split)
theta3_gap = pct(orders["MU theta^3"], half_split)
v.check("lambda^3 shortfall vs half-splitting", -lambda3_gap, 6.5, rel=3e-2)
v.check("thetaC^3 shortfall vs half-splitting", -theta3_gap, 4.2, rel=3e-2)
v.record(
    "abstract 1--3 percent cubic proximity matches exact half-splitting",
    abs(lambda3_gap) <= 3 and abs(theta3_gap) <= 3,
    f"lambda^3 gap={lambda3_gap:+.2f}%, theta^3 gap={theta3_gap:+.2f}%",
    "within 1--3%",
    "Expected fail: the exact gaps are about 6.6% and 4.2%, although the later summary correctly says 4--7%.",
)
v.check("12 sin^3(pi/14) / (pi-3)", 12 * LAMBDA_W**3 / (PI - 3), 0.934, rel=5e-4)
v.check("12 sin^3(pi/14) minus (pi-3)", (PI - 3) - 12 * LAMBDA_W**3, 0.00935, rel=5e-3)

e_nu_abs = E_R_OBS - 2 * E_V_CANON
e_nu = -e_nu_abs
m_nu3_mev = ME_MEV * math.exp(MU * (e_nu - PI))
m_nu3_mev_milli_ev = m_nu3_mev * 1e9
dm31_from_mid = (m_nu3_mev * 1e6) ** 2
v.check("E_nu3 absolute from midpoint and E_v", e_nu_abs, 17.230, abs_tol=0.001)
v.check("m_nu3 from midpoint", m_nu3_mev_milli_ev, 48.7, rel=1e-2)
v.check(
    "Delta m31 from midpoint m_nu3",
    dm31_from_mid,
    2.37e-3,
    rel=2e-2,
)
v.check(
    "paper proof's Delta m31 comparison",
    dm31_from_mid,
    2.450e-3,
    rel=5e-3,
    detail="Expected fail: 48.7-48.9 meV implies about 2.39e-3 eV^2, not 2.450e-3; the proof line accidentally uses 49.5 meV.",
)
v.check(
    "Delta m31 residual from midpoint",
    pct(dm31_from_mid, DM31),
    0.12,
    rel=1e-1,
    detail="Expected fail: recomputing from the midpoint mass gives a few-percent low Delta m31, not +0.12%.",
)
v.record(
    "midpoint mass comparison uses midpoint mass, not 49.5 meV",
    "49.5^2\\times10^{-6}" not in TEX,
    "proof comparison uses 49.5^2 even though proposition predicts 48.7 meV",
    "48.7^2 for midpoint prediction",
    "Expected fail: this makes the final comparison circular/stale.",
)

v.record(
    "Phase 5b status remains conjectural",
    "Phase~5b is \\emph{not yet closed}" in TEX and "Phase~5b closure & \\textbf{Conjecture}" in TEX,
    "open/conjecture status present",
    "not yet closed",
)

sys.exit(v.summary())
