#!/usr/bin/env python3
"""Offline public-copy integrity and arithmetic check, written for publication v1."""
from pathlib import Path
import csv
import hashlib
import json

ROOT = Path(__file__).resolve().parent
EXPECTED = {
    'index.html', 'README.md', 'summary.csv', 'summary.json', 'claim-support.json',
    'implementation-excerpt.md', 'verify.py', 'samples/sample-q009.json',
    'samples/sample-q045.json', 'samples/sample-q053.json',
}

def require(condition, message):
    if not condition:
        raise SystemExit('FAIL: ' + message)

entries = {}
for line in (ROOT / 'SHA256SUMS.txt').read_text().splitlines():
    digest, name = line.split('  ', 1)
    require(name not in entries and name in EXPECTED, 'Unexpected or duplicate file')
    entries[name] = digest
require(set(entries) == EXPECTED, 'Checksum inventory differs')
actual_files = {str(p.relative_to(ROOT)) for p in ROOT.rglob('*') if p.is_file()}
require(actual_files == EXPECTED | {'SHA256SUMS.txt'}, 'Directory inventory differs')
for name, digest in entries.items():
    require(hashlib.sha256((ROOT / name).read_bytes()).hexdigest() == digest, 'Checksum: ' + name)

summary = json.loads((ROOT / 'summary.json').read_text())
rows = list(csv.DictReader((ROOT / 'summary.csv').open(newline='')))
for row in rows:
    row['count'] = int(row['count'])
    require(row['count'] > 0, 'Non-positive cell')
    for key in ['eci_issue', 'unverified_profile_merge', 'inference_only_issue']:
        require(row[key] in ['true', 'false'], 'Boolean format')
        row[key] = row[key] == 'true'
require(rows == summary['contingency'], 'CSV/JSON cells differ')
require(len({tuple(r[k] for k in ['phase','identity_state','eci_issue','unverified_profile_merge','inference_only_issue']) for r in rows}) == len(rows), 'Duplicate aggregate cells')
for phase in ['baseline', 'retest']:
    selected = [r for r in rows if r['phase'] == phase]
    total = summary['totals'][phase]
    count = lambda predicate: sum(r['count'] for r in selected if predicate(r))
    require(count(lambda r: True) == total['denominator'] == 20, phase + ' denominator')
    distribution = {state: count(lambda r: r['identity_state'] == state) for state in sorted({r['identity_state'] for r in selected})}
    require(distribution == total['identity_distribution'], phase + ' identity distribution')
    require(count(lambda r: r['identity_state'] in ['MIXED','WRONG_ENTITY']) == total['confirmed_identity_contamination'], phase + ' confirmed contamination')
    require(count(lambda r: r['identity_state'] in ['MIXED','WRONG_ENTITY'] or r['unverified_profile_merge']) == total['broad_identity_sensitivity'], phase + ' sensitivity')
    for key in ['eci_issue','inference_only_issue','unverified_profile_merge']:
        require(count(lambda r: r[key]) == total[key], phase + ' ' + key)
    require(count(lambda r: r['identity_state'] == 'TARGET' and r['eci_issue']) == total['target_with_eci_issue'], phase + ' TARGET with ECI')
require([summary['totals'][p]['confirmed_identity_contamination'] for p in ['baseline','retest']] == [10,2], '10 to 2')
require([summary['totals'][p]['broad_identity_sensitivity'] for p in ['baseline','retest']] == [10,6], '10 to 6')
require([summary['totals'][p]['eci_issue'] for p in ['baseline','retest']] == [13,16], '13 to 16')
require([summary['totals'][p]['inference_only_issue'] for p in ['baseline','retest']] == [13,15], '13 to 15')
require(summary['totals']['retest']['target_with_eci_issue'] == 11 and summary['totals']['retest']['identity_distribution']['TARGET'] == 13, '11 of 13')
for phase, expected in [('baseline',(2,200)),('retest',(1,20))]:
    coverage = [r for r in summary['coverage'] if r['phase'] == phase]
    require(tuple(sum(r[k] for r in coverage) for k in ['primary','follow_up']) == expected, phase + ' coverage')
    require(all(r['valid_saved_answers'] == r['primary']+r['follow_up'] and r['exact_isolated_follow_up_requests'] == r['follow_up'] for r in coverage), phase + ' coverage consistency')
for name in EXPECTED:
    if name.endswith('.json'):
        json.loads((ROOT / name).read_text())
print('PASS: 10 files; hashes, CSV/JSON, coverage, distributions, sensitivity and ECI arithmetic agree.')
print('This does not independently validate withheld records, classification judgments, truth or publication effects.')
