"""Verify the one-value program example for T681 without writing to the API.

With generate.py, table-proposed.json and repair-provenance.json beside this file:
    sage -python repair-check.py
Prints JSON evidence. Independent third moments use finite Hurwitz-zeta sums.
"""
import ast, hashlib, json, sys
from math import gcd
from pathlib import Path
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
from sage.env import SAGE_VERSION
from generate import moment, HigherCyclotomicMahler

root=Path(__file__).resolve().parent
doc=json.loads((root/'table-proposed.json').read_text())
provenance=json.loads((root/'repair-provenance.json').read_text())
source=doc['Programs']['program-sage']['code']
module=ast.parse(source)
assert isinstance(module.body[-1],ast.Expr)
namespace={}
exec(compile(ast.Module(body=module.body[:-1],type_ignores=[]),'<Programs>','exec'),namespace)
result=eval(compile(ast.Expression(module.body[-1].value),'<Programs>','eval'),namespace)
R=RealBallField(600)

def exact_decimal(text):
    from decimal import Decimal
    dec=Decimal(text)
    sign,digits,exponent=dec.as_tuple()
    mantissa=int(''.join(map(str,digits))) * (-1 if sign else 1)
    unit=QQ(10)**int(exponent)
    return mantissa*unit,unit

records=[]
for n, moments in doc['Numbers'].items():
    for k, entry in moments.items():
        value=entry['number'] if isinstance(entry,dict) else entry
        records.append(({'n':int(n),'k':int(k)},value))
assert len(records)==88
stored={(int(p['n']),int(p['k'])):v for p,v in records}
enumerated=[(int(p['n']),int(p['k'])) for p in HigherCyclotomicMahler().enumerate()]
assert enumerated==list(stored)

def third_independent(n):
    residues=[a for a in range(n) if gcd(a,n)==1]
    d=len(residues)
    csum,ssum=R(0),R(0)
    for i,a in enumerate(residues):
        for j in range(i+1,d):
            delta=QQ(residues[j]-a)/n
            b=int(delta.denominator())
            c3,s2=R(0),R(0)
            for r in range(1,b+1):
                angle=2*R.pi()*R(delta*r)
                c3+=angle.cos()*R(3).zeta(R(QQ(r)/b))/b**3
                s2+=angle.sin()*R(2).zeta(R(QQ(r)/b))/b**2
            csum+=c3
            ssum+=s2*(d*delta-(j-i))
    return -QQ(3)/2*d*d*R(3).zeta()-3*d*csum-3*R.pi()*ssum

checks=[]
for n,k,got,expected in [(1,2,moment(1,2),R.pi()**2/12),(1,3,moment(1,3),-QQ(3)/2*R(3).zeta()),(15,3,result,third_independent(15))]:
    center,ulp=exact_decimal(stored[n,k])
    assert got.is_finite() and expected.is_finite()
    assert got.accuracy()>=numberdb.bits(100,losing=32)
    assert expected.accuracy()>=550
    assert abs(R(got)-R(center))<R(ulp)
    assert abs(expected-R(center))<R(ulp)
    assert got.overlaps(expected)
    checks.append({'n':n,'k':k,'stored':stored[n,k],'computed_ball':str(got),'independent_ball':str(expected),'computed_accuracy_bits':int(got.accuracy()),'independent_accuracy_bits':int(expected.accuracy()),'computed_and_independent_contained_in_stored_interval':True,'overlap':True,'independent_error_ulp_upper':str((abs(expected-R(center))/R(ulp)).upper())})
print(json.dumps({'table':'T681','skill_manifest':provenance['skill_manifest'],'skill_versions':provenance['skill_versions'],'generator_sha256':hashlib.sha256((root/'generate.py').read_bytes()).hexdigest(),'program':source,'program_executes':True,'enumerated_rows':len(enumerated),'enumeration_matches_stored_order':True,'checks':checks,'precision_and_uncertainty':'Root angles are exact rational residues; 600-bit Arb enclosures propagate argument uncertainty through trig and Hurwitz zeta. Stored decimal intervals are checked with exact decimal centers and ULPs.','versions':{'sage':SAGE_VERSION,'python':sys.version}},indent=2))
