"""Checks for T649's standalone Programs example.
Run: sage -python repair_checks.py
Keep standalone-program.py, generate.py, checks.py, table-before.json,
and binding-before.json in the same directory. No API access or writes.
"""
import json, platform, time, hashlib
from pathlib import Path
import numberdb.sage as numberdb
from sage.env import SAGE_VERSION
import mpmath as mp
from checks import cubic_jensen, hypergeometric

work=Path(__file__).resolve().parent
binding=json.loads((work/'binding-before.json').read_text())
print(json.dumps({'kind':'environment','sage':SAGE_VERSION,'python':platform.python_version(),
 'mpmath':mp.__version__,'skill_manifest':binding['skill_manifest'],
 'skill_sha256':binding['skill_sha256'],
 'program_sha256':hashlib.sha256((work/'standalone-program.py').read_bytes()).hexdigest()}),flush=True)
namespace={}
exec(compile((work/'standalone-program.py').read_text(),'standalone-program.py','exec'),namespace)
hessian=namespace['hessian_measure']
table=json.loads((work/'table-before.json').read_text())

def agreement(a,b):
    delta=abs(a-b)/max(1,abs(b))
    return float(-mp.log10(delta)) if delta else 999.0

with mp.workdps(210):
    L=(mp.zeta(2,mp.mpf(1)/3)-mp.zeta(2,mp.mpf(2)/3))/9
    control=3*mp.sqrt(3)*L/(4*mp.pi)

cases=[('0','0'),('-1','-1'),('27','27'),('24','24'),('-216','-216'),('54','54'),
 ('-13500000+1431000*sqrt(89)',lambda: -13500000+1431000*mp.sqrt(89)),
 ('-8','-8'),('1','1'),('8','8'),('125','125')]
for key,arg in cases:
    start=time.monotonic()
    if key=='24':
        lo,hi=namespace['low'],namespace['high']
    else:
        lo=hessian(arg,140)
        hi=hessian(arg,190)
    with mp.workdps(210):
        assert mp.isfinite(lo) and mp.isfinite(hi)
        digits=agreement(lo,hi)
        assert digits>115,(key,digits)
        result={'t':key,'working_digits':[140,190],'agreement_digits':digits,
                'value':mp.nstr(hi,190),'seconds':round(time.monotonic()-start,3)}
        if key in table['Numbers']:
            entry=table['Numbers'][key]
            text=entry['number'] if isinstance(entry,dict) else entry
            last_place=mp.power(10,-len(text.split('.')[1]))
            distance=abs(hi-mp.mpf(text))/last_place
            assert distance<1,(key,str(distance))
            result['stored_midpoint_distance_ulp']=str(distance)
        if key in ('0','27'):
            target=control if key=='0' else 3*control
            d=agreement(hi,target)
            assert d>115,(key,d)
            result['independent_control_digits']=d
    # Independent original-cubic integration checks inputs outside the catalogue.
    if key in ('-8','1','8','125'):
        item={'key':key,'a':key,'b':'0','d':1}
        oracle,err=cubic_jensen(item,125)
        with mp.workdps(210):
            d=agreement(hi,mp.mpf(oracle))
            assert d>110,(key,d)
            result['independent_cubic_digits']=d
            result['independent_cubic_value']=oracle
            result['independent_quadrature_estimate']=err
        if key in ('-8','125'):
            other=hypergeometric(item,125)
            with mp.workdps(210):
                d=agreement(hi,mp.mpf(other))
                assert d>110,(key,d)
                result['hypergeometric_digits']=d
    print(json.dumps(result),flush=True)
    mp.mp._tanh_sinh.clear()
print(json.dumps({'kind':'summary','passed':len(cases),'stored_values_changed':False}),flush=True)
