"""Independent checks of saved explanations against raw poses and B outputs."""
import hashlib
import json
import os
from pathlib import Path
from collections import Counter
from review_data import load_rows,verify_baseline,strict_people

verify_baseline()
clip=os.environ['CLIP'];dest=Path('/download')/clip/'data'
if (dest/'technical_audit.json').exists():
    previous_audit=json.loads((dest/'technical_audit.json').read_text())
    assert previous_audit['status']=='PASS'
    assert previous_audit['core_sha256']==hashlib.sha256((dest/'B_diagnostics.jsonl').read_bytes()).hexdigest()
    print('REUSED_AUDIT',clip)
    raise SystemExit(0)
rows,chosen,check,previous=load_rows(clip)
core=[json.loads(x) for x in (dest/'B_diagnostics.jsonl').read_text().splitlines()]
views=[json.loads(x) for x in (dest/'review_diagnostics.jsonl').read_text().splitlines()]
assert len(core)==len(views)==len(rows)
palette={int(k):tuple(v) for k,v in json.loads((previous/'identity_palette.json').read_text()).items()}
kinds=Counter();stages=Counter();max_groups=0
for row,c,v in zip(rows,core,views):
    assert (c['sample'],c['source_frame'],c['seconds'])==(row['sample'],row['source_frame'],row['seconds'])
    assert (v['sample'],v['source_frame'],v['seconds'])==(row['sample'],row['source_frame'],row['seconds'])
    assert v['episode']==c['episode'] and v['events']==c['events'] and v['current_rules']==c['current_rules']
    assert v['displayed']==(row['sample'] in chosen)
    assert len(v['candidate_edges'])==c['candidate_pairs']
    nodes={x for pair in v['candidate_edges'] for x in pair}
    grouped=[x for g in v['groups'] for x in g['orders']]
    assert len(grouped)==len(set(grouped)) and set(grouped)==nodes
    membership={x:g['group'] for g in v['groups'] for x in g['orders']}
    assert all(membership[a]==membership[b] for a,b in v['candidate_edges'])
    for g in v['groups']:
        reached={g['orders'][0]}
        for _ in g['orders']:
            for a,b in g['edges']:
                if a in reached or b in reached:reached.update((a,b))
        assert reached==set(g['orders']) and len(reached)>=2
        assert all(0<=x<row['width'] and 0<=y<row['height'] for x,y in g['polygon'])
    # The source palette owns displayed frames, not earlier engine warm-up frames.
    people=strict_people(row,palette) if c['displayed'] else []
    assert all(p['person_score']>=.25 for p in people)
    for p in people:
        for k,state in zip(p['joints'],p['joint_states']):
            assert state!='LOW'
            if state=='HIGH':assert k[2]>=.10
    pairs={p['token']:p for p in c['pairs']}
    assert {p['token'] for p in v['pairs']}==set(pairs)
    assert set(v['current_support'])=={p['token'] for p in c['pairs'] if p['hit']}
    if v['held_support']:
        assert v['episode']['display'] and not v['current_rules']
    for p in v['pairs']:
        source=pairs[p['token']]
        assert p['orders']==source['orders'] and p['ids']==source['ids'] and p['rules']==source['rules']
        assert p['input_end']==row['seconds'] and (p['input_start'] is None or p['input_start']<=row['seconds'])
        for body in p['bodies']:
            raw=row['persons'][body['order']]
            assert body['bbox']==raw['bbox'] and body['tid']==raw['track_id'] and raw['score']>=.25
        for e in p['evidence']:
            a=e['values'];checks=e['checks']
            expected_strike=a['valid'] and a['relative_motion']>=.18 and a['toward']>=.10 and a['approach']>=.04 and a['hand_distance']<=1.25
            assert bool(expected_strike)==a['strike']
            expected_dynamic=a['valid'] and a['hand_distance']<=1.0 and a['relative_motion']>=.07 and p['features']['pair_relative_change']>=.08
            assert bool(expected_dynamic)==a['dynamic']
            accumulated=('STRIKE' in p['rules'] and a['strike']) or ('PUSH_GRAPPLE' in p['rules'] and a['dynamic'])
            expected_level=3 if accumulated else 2 if a['strike'] or a['dynamic'] else 1 if a['valid'] and (a['relative_motion']>=.07 or a['hand_distance']<=1.) else 0
            assert e['level']==expected_level
            stages[str(e['level'])]+=1
        a=p['association'];kinds[a['kind']]+=1
        if a['difference']:
            assert a['kind'] in ('B_RESET_SAME_T_PAIR','T_CHANGE_B_CONTINUES','T_SWAP_B_CONTINUES')
            assert a['elapsed']<=.15+1e-8 and all(t is not None for t in a['current_ids']+a['previous_ids'])
        if a['kind']=='B_RESET_SAME_T_PAIR':
            assert a['previous_token']!=a['token'] and set(a['previous_ids'])==set(a['current_ids'])
        if a['kind'] in ('T_CHANGE_B_CONTINUES','T_SWAP_B_CONTINUES'):
            assert a['previous_token']==a['token'] and a['previous_ids']!=a['current_ids']
        if p['token'] in v['held_support']:
            assert a['previous_token']==a['token'] and a['elapsed']<=.15+1e-8
    max_groups=max(max_groups,len(v['groups']))
report=dict(status='PASS',observations=len(rows),display_observations=len(chosen),max_groups=max_groups,
    association_kinds=dict(kinds),arm_stages=dict(stages),same_observation=True,groups_not_feedback=True,
    thresholds_verified=True,no_future_frames=True,core_sha256=hashlib.sha256((dest/'B_diagnostics.jsonl').read_bytes()).hexdigest())
(dest/'technical_audit.json').write_text(json.dumps(report,indent=2))
print(json.dumps(report))
