#!/usr/bin/env python3
"""Offline conservation and compact-view equivalence, no SQL."""
import copy
import hashlib
import importlib.util
import json
import subprocess
from pathlib import Path

R = Path(__file__).resolve().parent
BASE = R.parent


def validate(document, proposal, cases, results):
    checks = 0
    def ok(test):
        nonlocal checks
        assert test
        checks += 1
    spec = importlib.util.spec_from_file_location('compact', R/'build-compact.py')
    compact = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(compact)
    ok(document == compact.render(proposal))
    expected_cases = json.loads(subprocess.check_output(['python3', str(R/'build-formatter-cases.py')]))
    ok(cases == expected_cases)
    for lane, version in [('B', '7.3.33'), ('C', '7.3.32')]:
        run = results[lane]
        ok(run['lint_stderr'] == run['stderr'] == '')
        ok('No syntax errors detected' in run['lint_stdout'])
        r = run['result']
        ok(r['PHP_VERSION'] == version and r['sql'] == 0)
        ok(r['physical_count'] == 288 and r['physical_null'] == 48)
        ok(r['computed_count'] == 60)
        ok(r['physical_mismatches'] == r['computed_mismatches'] == [])
        ok(len(r['global_round_counterexamples']) == 36)
        ok(len(r['rows']) == 348)
        for case, actual in zip(cases['physical']+cases['computed'], r['rows']):
            ok(case['case_id'] == actual['case_id'])
            ok(case['stored_double_hex'] == actual['input_hex'])
            ok(case['expected_getter_hex'] == actual['expected_hex'] == actual['output_hex'])
    ok(results['B']['result']['rows'] == results['C']['result']['rows'])
    return checks


if __name__ == '__main__':
    proposal = json.loads((R/'proposal.json').read_bytes())
    document = (R/'COMPACT-REVIEW.md').read_text()
    cases = json.loads((R/'formatter-cases.json').read_bytes())
    results = json.loads((R/'formatter-results.json').read_bytes())
    checked = validate(document, proposal, cases, results)
    rejects = []
    changes = [
        ('compact changed bind', lambda d,p,c,r: (d.replace('literal_rint / OS','literal_rint / S',1),p,c,r)),
        ('compact changed SQL', lambda d,p,c,r: (d.replace('CAST(0.5 AS DOUBLE)','CAST(0.51 AS DOUBLE)',1),p,c,r)),
        ('source bits changed', lambda d,p,c,r: (d,p,{**c,'physical':[{**c['physical'][0], 'stored_double_hex':'0000000000000000'}]+c['physical'][1:]},r)),
        ('runtime output changed', lambda d,p,c,r: (d,p,c,{**r,'C':{**r['C'],'result':{**r['C']['result'],'rows':[{**r['C']['result']['rows'][0],'output_hex':'0000000000000000'}]+r['C']['result']['rows'][1:]}}})),
        ('null budget result changed', lambda d,p,c,r: (d,p,c,{**r,'B':{**r['B'],'result':{**r['B']['result'],'physical_null':47}}})),
        ('global-round damage hidden', lambda d,p,c,r: (d,p,c,{**r,'B':{**r['B'],'result':{**r['B']['result'],'global_round_counterexamples':[]}}})),
    ]
    for label, fn in changes:
        mutated = fn(document,copy.deepcopy(proposal),copy.deepcopy(cases),copy.deepcopy(results))
        try:
            validate(*mutated)
        except AssertionError:
            rejects.append(label)
        else:
            raise AssertionError(label+' accepted')
    manifests = []
    for folder, filename, key in [(BASE,'execution-seal.json','public_sha256'),(BASE/'primary-source-derivation-20261011','research-manifest.json','files'),(BASE/'half-tie-execution-20261011','seal.json','public_sha256')]:
        m=json.loads((folder/filename).read_bytes())
        for name, sha in m[key].items():
            assert hashlib.sha256((folder/name).read_bytes()).hexdigest() == sha,name
        manifests.append({'manifest':filename,'files_unchanged':len(m[key])})
    print(json.dumps({'status':'PURE_GREEN_0_SQL', 'assertions':checked, 'mutation_rejections':rejects,
                      'old_seals_verified':manifests, 'compact_full_SQL_bind_case_oracle_equivalence':True,
                      'formatter_data_original_raw_conserved':True},indent=2))
