#!/usr/bin/env python3
"""
verify_P065.py -- Addendum 65: PMNS-Yukawa compatibility.

This verifier checks the PMNS compatibility arithmetic and the proof-status
claims in 65_Addendum_PMNSCompatibility.tex. The headline leading-order
angle numerics reproduce: theta12=5*pi/28, theta23=pi/4, and the quoted
percent residuals are mostly consistent. The flagged issues are proof-level
and internal consistency problems: the displacement-angle equivalence is
miswritten, the moduli-count statements alternate between two and three
Yukawa constraints, Z3 symmetry is used as if it uniquely forced QLC/TBM,
and the theta23 proof contains a self-correction whose displayed complement
formula would give about 87.7 degrees rather than 45 degrees.
"""

from __future__ import annotations

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: identical tolerance logic, modern output format."""

    def __init__(self, name: str):
        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, info = label, detail
        i = detail.find("Expected")
        if i >= 0:
            desc = f"{label} -- {detail[i:]}"
            info = detail[:i].rstrip().rstrip(";")
        print(f"  [{'PASS' if ok else 'FAIL'}] {n:>2}. {desc}")
        if computed != "" or claimed != "":
            print(f"        computed: {computed}")
            print(f"        claimed : {claimed}")
        if info:
            print(f"        {info}")
        return bool(ok)

    def summary(self) -> int:
        passed = sum(bool(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("P065 -- PMNS-Yukawa Compatibility")

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

PI = math.pi
THETA_C = PI / 14
THETA12 = PI / 4 - THETA_C
THETA23 = PI / 4
PDG_THETA_C = 12.80
PDG_THETA12 = 33.44
PDG_THETA23 = 42.20
PDG_THETA13 = 8.62
PDG_DELTA = -67.0


def deg(rad: float) -> float:
    return math.degrees(rad)


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


def matrix_toe(theta: float):
    c = math.cos(theta)
    s = math.sin(theta)
    r2 = math.sqrt(2)
    return [
        [c, s, 0.0],
        [-s / r2, c / r2, 1 / r2],
        [s / r2, -c / r2, 1 / r2],
    ]


def dot(row_a, row_b):
    return sum(a * b for a, b in zip(row_a, row_b))


y1 = math.sin(PI / 14)
y2 = math.sin(2 * PI / 14)
phi12 = PI / 2 - PI / 14
phi13 = PI / 2 - 2 * PI / 14
qlc_sum_pdg = PDG_THETA_C + PDG_THETA12
theta23_ckm = 2.3
theta23_complement = 90 - theta23_ckm
u_toe = matrix_toe(THETA12)

v.check("y1 = sin(pi/14)", y1, 0.2225, rel=2e-4)
v.check("y2 = sin(2pi/14)", y2, 0.4339, rel=2e-4)
v.check("theta_C = pi/14 degrees", deg(THETA_C), 12.857, rel=3e-5)
v.check("theta_C residual percent", pct(deg(THETA_C), PDG_THETA_C), 0.4, rel=2e-1)
v.check("theta12 PMNS = 5pi/28", deg(THETA12), 32.14, rel=1e-4)
v.check("theta12 discrepancy degrees", PDG_THETA12 - deg(THETA12), 1.3, rel=3e-2)
v.check("theta12 residual percent", pct(deg(THETA12), PDG_THETA12), -3.9, rel=2e-2)
v.check("QLC TOE sum", deg(THETA_C + THETA12), 45.0, rel=1e-12)
v.check("PDG QLC sum", qlc_sum_pdg, 46.3, rel=2e-3)
v.check("QLC sum residual percent vs PDG sum", pct(45.0, qlc_sum_pdg), -2.9, rel=8e-2)

v.check("theta23 leading value", deg(THETA23), 45.0, rel=1e-12)
v.check("theta23 residual percent", pct(deg(THETA23), PDG_THETA23), 6.6, rel=1e-2)
v.check(
    "PDG theta23 as fraction of pi/4",
    PDG_THETA23 / 45.0,
    0.949,
    rel=1e-3,
    detail="Expected fail: 42.2/45 is about 0.938, not 0.949.",
)
v.check("TBM theta12", deg(math.asin(1 / math.sqrt(3))), 35.26, rel=2e-4)
v.check("TBM theta12 residual percent", pct(deg(math.asin(1 / math.sqrt(3))), PDG_THETA12), 5.4, rel=2e-2)
v.check("theta13 rough 2/3 candidate", y1 * 2 / 3, 0.148, rel=3e-3)
v.check("theta13 candidate angle", deg(math.asin(y1 * 2 / 3)), PDG_THETA13, rel=2e-2)
v.check("rough J estimate using listed PDG s12/c12", (0.551 * 0.834) / 13, 0.035, rel=2e-2)

v.check("varphi12 displacement", deg(phi12), deg(6 * PI / 14), rel=1e-12)
v.check("varphi13 displacement", deg(phi13), deg(5 * PI / 14), rel=1e-12)
v.check("cos(varphi12) equals y1", math.cos(phi12), y1, rel=1e-12)
v.check("cos(varphi13) equals y2", math.cos(phi13), y2, rel=1e-12)
v.record(
    "printed sine/cosine equivalence for displacement angles is well formed",
    "sin\\varphi_{ij} = \\cos(\\langle\\hat{u}_{ij}, e_7\\rangle^{-1})" not in TEX,
    "paper writes sin(varphi_ij)=cos(<u_ij,e7>^{-1})",
    "sin(varphi_ij)=sqrt(1-<u,e7>^2) or cos(k*pi/14)",
    "Expected fail: the inverse-inner-product expression is not the trigonometric inverse needed here.",
)

v.record(
    "moduli-count statements consistently say Yukawa fixes two independent orbit moduli",
    "fix three scalar inner products (three of the four invariants)" not in TEX,
    "abstract/body says three Yukawa scalar products fix three of four invariants; later proof says two of four",
    "consistent two-modulus count after G2 anchoring",
    "Expected proof-audit fail: y3=1 is the chosen anchor, not an independent remaining quotient modulus in the later parameter count.",
)
v.record(
    "Yukawa overlaps directly determine theta12 and theta23",
    False,
    "the independence lemma says Yukawa eigenvalues and PMNS angles are independent observables; theta12 is added through QLC/Z3",
    "direct determination by the three inner-product constraints",
    "Expected internal-consistency fail.",
)
v.record(
    "QLC relation is derived from Z3 geometry rather than assumed",
    False,
    "the proof assumes a pi/4 tribimaximal axis/maximal-mixing principle; Z3 alone does not uniquely fix QLC",
    "structural identity proved",
    "Expected proof-audit fail: this is a conditional structural ansatz, not a derivation from the displayed equations.",
)
v.record(
    "Z3 symmetry alone proves theta23 maximality",
    False,
    "the proof appeals to TBM/S3 fixed-point structure and then notes the CKM formula needs care",
    "theta23=pi/4 proved from Z3",
    "Expected proof-audit fail: Z3 cyclic symmetry alone does not uniquely determine the TBM matrix or maximal 2-3 mixing.",
)
v.check(
    "theta23 complement formula in proof",
    theta23_complement,
    45.0,
    rel=1e-3,
    detail="Expected fail: pi/2 - theta23_CKM with theta23_CKM≈2.3 deg is about 87.7 deg, not pi/4.",
)
v.record(
    "theta23 proof has no self-correction marker",
    "Wait -- that formula applies to the CKM parametrisation" not in TEX,
    "paper includes a 'Wait --' correction inside the theorem proof",
    "clean proof",
    "Expected proof-audit fail: the theorem proof itself marks the key relation as needing care.",
)
v.record(
    "sector-to-off-diagonal PMNS rotation is explicitly constructed",
    False,
    "the text defines sector and off-diagonal bases but does not give an explicit unitary map between diagonal E_ii and imaginary-octonion directions",
    "PMNS rotation derived in J3(O)",
    "Expected proof-audit fail: the compatibility picture is plausible but the actual rotation is not constructed.",
)
v.record(
    "Phase 5a closure status is unconditional",
    "Proved (cond.)" not in TEX,
    "status table says several PMNS statements are proved conditionally and theta13/delta_CP remain open",
    "unconditional closure",
    "Expected status fail: closure is conditional on A57/QLC/Z3 assumptions and leaves Phase 5b-ii open.",
)

for i, row_i in enumerate(u_toe):
    v.check(f"PMNS TOE row {i + 1} norm", dot(row_i, row_i), 1.0, rel=1e-12)
v.check("PMNS TOE row1-row2 dot", dot(u_toe[0], u_toe[1]), 0.0, abs_tol=1e-12)
v.check("PMNS TOE row1-row3 dot", dot(u_toe[0], u_toe[2]), 0.0, abs_tol=1e-12)
v.check("PMNS TOE row2-row3 dot", dot(u_toe[1], u_toe[2]), 0.0, abs_tol=1e-12)

sys.exit(v.summary())
