"""Read-back verification for numberdb.org/T604; writes nothing.

    sage -python postfill.py
For an unpublished draft set NUMBERDB_API_KEY. Requires generate.py,
finite_formulas.py and independent.py alongside this file.
"""
import json
import os
import sys
from decimal import Decimal
from fractions import Fraction
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
from generate import HemisphereNeumann
from independent import continuation


def rational(x):
    x=Fraction(x)
    return QQ(x.numerator)/QQ(x.denominator)


def read_values(tid):
    doc=numberdb.table(tid)
    block=doc['Numbers']
    values={}
    if isinstance(block,dict):
        for d,group in block.items():
            for convention,x in group.items():
                if convention not in ('det','logdet'):
                    continue
                values[(int(d),convention)]=x['number'] if isinstance(x,dict) else x
    else:
        for row in block:
            values[(int(row['params']['d']),row['params']['convention'])]=row['number']
    return doc,values


def endpoints(text):
    value=Decimal(text)
    center=rational(value)
    ulp=QQ(10)**int(value.as_tuple().exponent)
    return center-ulp,center+ulp


def stored_ball(text,R):
    lo,hi=endpoints(text)
    return R((lo+hi)/2).add_error(R((hi-lo)/2))


if __name__=='__main__':
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
        raw=sys.stdin.read().strip()
        if raw.startswith('NUMBERDB_') and '=' in raw:
            raw=raw.split('=',1)[1].strip().strip('\"\'')
        os.environ['NUMBERDB_API_KEY']=raw
    numberdb.configure(api_key=os.environ['NUMBERDB_API_KEY'])
    report=HemisphereNeumann().verify(sample=None)
    assert report.ok
    print(json.dumps({'verify':str(report),'table':'T604'}),flush=True)
    doc,neumann=read_values('T604');_,dirichlet=read_values('T603');_,sphere=read_values('T595')
    expected={(d,c) for d in range(1,21) for c in ('det','logdet')}
    assert set(neumann)==expected
    R=RealBallField(numberdb.bits(240))
    for d in range(1,21):
        L,info=continuation(d)
        for convention,x in [('det',L.exp()),('logdet',L)]:
            assert x.is_finite() and x.rad_as_ball()<R(10)**(-160)
            lo,hi=endpoints(neumann[(d,convention)])
            assert x>R(lo) and x<R(hi), (d,convention)
        ns={c:stored_ball(neumann[d,c],R) for c in ('det','logdet')}
        ds={c:stored_ball(dirichlet[d,c],R) for c in ('det','logdet')}
        ss={c:stored_ball(sphere[d,c],R) for c in ('det','logdet')}
        for x in [*ns.values(),*ds.values(),*ss.values()]:
            assert x.is_finite() and x.rad_as_ball()<R(10)**(-97)
        assert (ns['det']*ds['det']).overlaps(ss['det'])
        assert (ns['logdet']+ds['logdet']).overlaps(ss['logdet'])
        assert ns['logdet'].exp().overlaps(ns['det'])
        assert ns['det'].log().overlaps(ns['logdet'])
        if d==1:
            assert ns['det'].overlaps(2*R.pi())
            assert ns['logdet'].overlaps((2*R.pi()).log())
        print(json.dumps({'d':d,'stored_intervals_contain_independent_enclosures':True,
                          'stored_product_sum_and_conversion':True}),flush=True)
    print(json.dumps({'status':'PASS','entries':len(neumann),'dimensions':20,
                      'skill_manifest':'agents/runs/20261029T075206Z-build-skills/manifest.json'}),flush=True)
