"""Verify the T666 program repair with SageMath.
Run: sage -python repair_checks.py
Keep before-document.json, proposed-document.json, generate.py,
context_checks.py and skill-evidence.json beside this file.
All coefficients and point counts are exact integers; no argument rounding occurs.
"""
import json,hashlib,sys,platform,ast
from pathlib import Path
import numberdb.sage as numberdb
from sage.rings.integer_ring import ZZ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.env import SAGE_VERSION
from generate import FermatZeta, zeta_polynomial
from context_checks import standard_sage as context_sage
w=Path(__file__).resolve().parent
before=json.loads((w/'before-document.json').read_text())
after=json.loads((w/'proposed-document.json').read_text())
old={};new={}
exec(before['Programs']['program-sage']['code'],old)
exec(after['Programs']['program-sage']['code'],new)
R=PolynomialRing(ZZ,'T')

def count(N,p):
    affine=sum((pow(x,N,p)+pow(y,N,p)-1)%p==0 for x in range(p) for y in range(p))
    infinity=sum((pow(x,N,p)+1)%p==0 for x in range(p))
    return affine+infinity

controls=[]
for p in (3,5,7,11):
    for N in (1,2):
        actual=count(N,p);assert actual==p+1
        controls.append({'N':N,'p':p,'points':actual})
wrong=old['standard_sage'](4,3)
assert wrong==R('(T+1)^6')
assert count(4,3)==4 and 3+1+wrong[1]==10
try:old['standard_sage'](3,5)
except Exception as e: second={'type':type(e).__name__,'message':str(e)}
else:raise AssertionError('Expected nonsplit failure for (3,5)')
invalid=[(4,3),(3,5),(2,5),(0,7),(-3,7),(3,1),(3,4),(3,25),(3,3),(3,2),(3,-5)]
rejected=[]
for N,p in invalid:
    for f in (new['standard_sage'],context_sage):
        try:f(N,p)
        except ValueError as e: assert str(e)=='This algorithm requires N >= 3 and a prime p = 1 mod N'
        else:raise AssertionError(('Accepted unsupported input',N,p))
    rejected.append([N,p])
rows=[]
for Nstr,prime_rows in before['Numbers'].items():
    for pstr,value in prime_rows.items():
        N,p=int(Nstr),int(pstr);expected=R(value)
        assert old['standard_sage'](N,p)==expected
        assert new['standard_sage'](N,p)==expected
        assert context_sage(N,p)==expected
        assert zeta_polynomial(N,p)==expected
        points=count(N,p);assert points==p+1+expected[1]
        rows.append({'N':N,'p':p,'points':points,'coefficients':len(expected.list())})
assert len(rows)==48
assert [(r['N'],r['p']) for r in rows]==[(p['N'],p['p']) for p in FermatZeta().enumerate()]
assert before['Numbers']==after['Numbers']
assert before['Parameters']==after['Parameters']
assert list(before['Parameters'])==list(after['Parameters'])
assert {k for k in before if before[k]!=after[k]}=={'Programs','Tags'}
fn=lambda code:next(n for n in ast.parse(code).body if isinstance(n,ast.FunctionDef) and n.name=='standard_sage')
assert ast.dump(fn(after['Programs']['program-sage']['code']))==ast.dump(fn((w/'context_checks.py').read_text()))
report={'table':'T666','skill':json.loads((w/'skill-evidence.json').read_text()),'versions':{'sage':SAGE_VERSION,'python':platform.python_version()},'counterexample':{'N':4,'p':3,'old_polynomial':str(wrong),'predicted_points':10,'actual_points':4,'old_leading_coefficient':1,'required_leading_coefficient':27},'second_nonsplit_failure':second,'rejected_inputs':rejected,'controls':controls,'all_48_polynomials_match_old_program_repaired_program_context_helper_and_generator':True,'independent_prime_field_counts':rows,'coefficient_slots':sum(r['coefficients'] for r in rows),'enumeration_and_parameter_order_unchanged':True,'stored_values_unchanged':True,'scope':'Repair verification, not an independent argument-selection critique. Exact arithmetic, with no new stored values.','sources':[{'url':'https://doc.sagemath.org/html/en/reference/modfrm/sage/modular/dirichlet.html','section':'jacobi_sum','checked':'Positive Jacobi-sum convention and trivial-character examples.'}],'file_sha256':{n:hashlib.sha256((w/n).read_bytes()).hexdigest() for n in ['repair_checks.py','before-document.json','proposed-document.json','generate.py','context_checks.py','skill-evidence.json']}}
print('REPAIR_EVIDENCE '+json.dumps(report,sort_keys=True))
