"""Replay only retained post-NMS observations. Never invokes a model or NMS."""
import importlib.metadata
import json
import time
from types import SimpleNamespace
from common import OUT,load,read,save,sha
from app.byte_tracking import ByteTracker,TrackingSettings


def run(clip):
    started=time.monotonic();rows,selected,spec,cache,mapping=load(clip)
    root=OUT/'work'/clip;validation=root/'tracking_validation.json'
    if validation.exists():
        v=read(validation);assert v['status']=='PASS' and sha(root/'tracking30.json')==v['derived_sha256'];print('REUSE',clip);return v
    input_sha={'pose.json':sha(cache/'pose.json')};derived={};mismatches=[];all_candidates=0;visible_match=0
    source_hashes={}
    for name in ('byte_tracking.py','tracking_kernel.py','pose_nms.py'):
        source_hashes[name]=sha('/opt/contextra/app/'+name)
    summary=read(cache.parent/'reports/pose_summary.json')
    for name in ('byte_tracking.py','tracking_kernel.py'):
        assert summary['source_files'][name]==source_hashes[name],(clip,name,'historical tracker source differs')
    if spec['tracking_mode']=='stored10':
        derived={str(r['sample']):{str(p['query']):p['track_id'] for p in r['persons']} for r in rows}
        detail=dict(replay10='NOT_REPLAYED_INCOMPLETE_CANDIDATES',frame_rate=10,
                    limit='Stored post-person0.15 cache omits original lower-score tracker observations')
    else:
        rawpath=cache/'pose_candidates_prefilter.jsonl';input_sha[rawpath.name]=sha(rawpath)
        tracker10=ByteTracker(TrackingSettings.parse(summary['tracking']))
        settings30=dict(summary['tracking'],frame_rate=30)
        tracker30=ByteTracker(TrackingSettings.parse(settings30))
        with rawpath.open() as f:
            for index,line in enumerate(f):
                raw=json.loads(line);row=rows[index]
                assert (raw['sample'],raw['source_frame'],raw['seconds'],raw['width'],raw['height'])==(row['sample'],row['source_frame'],row['seconds'],row['width'],row['height'])
                candidates=[p for p in raw['candidates'] if p['nms_keep']]
                assert all(p['parse_keep'] for p in candidates)
                assert [p['query'] for p in candidates]==sorted(p['query'] for p in candidates)
                observed=[]
                for p in candidates:
                    w,h=raw['width'],raw['height'];b=p['bbox']
                    observed.append(SimpleNamespace(class_id=0,score=p['score'],bbox_xyxy=(b[0]/w,b[1]/h,b[2]/w,b[3]/h),
                        frame=SimpleNamespace(frame_width=w,frame_height=h)))
                ids10=tracker10.update(observed);ids30=tracker30.update(observed)
                old={p['query']:tid for p,tid in zip(candidates,ids10)}
                derived[str(row['sample'])]={str(p['query']):tid for p,tid in zip(candidates,ids30)}
                for p,tid in zip(candidates,ids10):
                    all_candidates+=1
                    if p['track_id']!=tid:mismatches.append(dict(sample=row['sample'],query=p['query'],stored=p['track_id'],replayed=tid))
                current={p['query']:p for p in candidates}
                for p in row['persons']:
                    orig=current[p['query']]
                    assert (p['score'],p['bbox'],p['keypoints'])==(orig['score'],orig['bbox'],orig['keypoints'])
                    assert old[p['query']]==p['track_id'],(clip,row['sample'],p['query'])
                    visible_match+=1
        assert index+1==len(rows)
        assert not mismatches,(clip,mismatches[:10])
        detail=dict(replay10='EXACT_ALL_RETAINED_CANDIDATES',frame_rate=30,
            replay10_candidates=all_candidates,stored_person_matches=visible_match,settings30=settings30)
    save(root/'tracking30.json',derived)
    changes=[]
    for row in rows:
        for p in row['persons']:
            other=derived[str(row['sample'])][str(p['query'])]
            if other!=p['track_id']:changes.append(dict(sample=row['sample'],source_frame=row['source_frame'],query=p['query'],old=p['track_id'],new=other))
    save(root/'tracking_changes.json',changes)
    result=dict(status='PASS',clip=clip,samples=len(rows),displayed=len(selected),candidate_input_hashes=input_sha,
        source_hashes=source_hashes,supervision=importlib.metadata.version('supervision'),
        derived_sha256=sha(root/'tracking30.json'),changes=len(changes),elapsed_seconds=time.monotonic()-started,
        new_model_inference=False,nms_reexecution=False,**detail)
    save(validation,result);print('TRACK_PASS',clip,json.dumps(result),flush=True);return result


if __name__=='__main__':
    import os
    clip=os.environ['CLIP']
    names=list(read(OUT/'specs.json')) if clip=='all' else [clip]
    for name in names:run(name)
