"""Independent table reconstruction for the methods review; no author code imported."""
import ast
import csv
import io
import json
import unicodedata
import zipfile
from collections import defaultdict, Counter
from pathlib import Path

# Read literal declared selections, without executing the source.
tree = ast.parse(Path('code/mechanics.py').read_text())
decl = {n.targets[0].id: ast.literal_eval(n.value) for n in tree.body
        if isinstance(n, ast.Assign) and isinstance(n.targets[0], ast.Name)
        and n.targets[0].id in ('CLASSES', 'TARGETS')}
classes, targets = decl['CLASSES'], decl['TARGETS']
anchors = [a for aa in classes.values() for a in aa]
counted = [t for group, ts in targets.items() if group != 'bodily' for t in ts]
all_targets = [t for ts in targets.values() for t in ts]
selected = set(anchors + all_targets)

def ziprows(name):
    with zipfile.ZipFile('data/clics4/' + name + '.csv.zip') as archive:
        with archive.open(name + '.csv') as raw:
            yield from csv.DictReader(io.TextIOWrapper(raw, encoding='utf-8'))

gloss = {r['ID']: r['Concepticon_Gloss'] for r in ziprows('concepts')}
with open('data/clics4/languages.csv') as f:
    langs = {r['ID']: r for r in csv.DictReader(f)}
lex = defaultdict(lambda: defaultdict(set))
forms_seen = 0
for r in ziprows('forms'):
    forms_seen += 1
    g = gloss.get(r['Parameter_ID'])
    if g in selected:
        form = unicodedata.normalize('NFC', r['Form'] or '').casefold().strip()
        if form:
            lex[r['Language_ID']][g].add(form)

counts = {}
for a in anchors:
    for t in all_targets:
        both, colex = set(), set()
        for language, concepts in lex.items():
            if a in concepts and t in concepts:
                r = langs.get(language)
                family = (r['Family'] or 'isolate:' + language) if r else 'unknown:' + language
                both.add(family)
                if concepts[a].intersection(concepts[t]):
                    colex.add(family)
        counts[a, t] = (len(colex), len(both))

declared = json.loads(Path('results/R1.json').read_text())
mismatches, omitted_positive, coverage = [], [], {}
comparisons = 0
for a, rows in declared['pairs'].items():
    for t, row in rows.items():
        comparisons += 1
        k, n = counts[a, t]
        if (k, n) != (row['families_colexifying'], row['families_with_both']):
            mismatches.append({'anchor': a, 'target': t, 'independent': [k, n], 'reported': row})
for cl, aa in classes.items():
    eligible = [(a,t) for a in aa for t in counted if t in declared['pairs'][a]]
    missing = [(a,t) for a in aa for t in counted if t not in declared['pairs'][a]]
    coverage[cl] = {'possible': len(aa)*len(counted), 'eligible': len(eligible),
                    'omitted': len(missing), 'any_colex': sum(counts[p][0] > 0 for p in eligible)}
    for a,t in missing:
        k,n = counts[a,t]
        if k:
            omitted_positive.append({'class': cl, 'anchor': a, 'target': t, 'colexifying': k, 'covered': n})
unknown = [r['ID'] for r in langs.values() if not r['Family']]
out = {'raw_forms_read': forms_seen, 'reported_pair_counts_checked': comparisons,
       'count_fields_checked': 2*comparisons, 'mismatches': mismatches,
       'coverage': coverage, 'omitted_positive_pairs': omitted_positive,
       'missing_family_language_records': len(unknown),
       'caveat': 'Counts use the declared form normalization and family-any statistic. This is not independent evidence of absence, homophony resolution, or a power analysis.'}
Path('results/reviewer_audit.json').write_text(json.dumps(out,indent=2)+'\n')
print(json.dumps(out,indent=2))
