from ops import *
import sys,csv,statistics
mode=sys.argv[1];assert mode in ('pose','mixed');ROOT=HERE/mode
result=json.loads((ROOT/'trial-result.json').read_text());rows=[];stage_rows=[]
for stage in result['stages']:
    if stage['status']!='PASS':continue
    first,last=stage['samples'][0],stage['samples'][-1];dt=last['t']-first['t']
    for camera,channel in last['channels'].items():
        for provider,row in channel['providers'].items():
            old=first['channels'][camera]['providers'][provider]
            a,b=old['publisher_metrics'],row['publisher_metrics'];md0,md1=old['metadata_path'],row['metadata_path']
            delta=lambda x,y,k:y.get(k,0)-x.get(k,0)
            timings={};pa=next(iter(a.get('profile',{}).get('channels',{}).values()),{});pb=next(iter(b.get('profile',{}).get('channels',{}).values()),{})
            for key,value in pb.get('timings',{}).items():
                prior=pa.get('timings',{}).get(key,{});n=value['count']-prior.get('count',0)
                timings[key]=dict(count=n,mean_ms=(value['count']*value['mean_ms']-prior.get('count',0)*prior.get('mean_ms',0))/n if n else None)
            t0=md0['provider_timing'][provider]['selected_to_response'];t1=md1['provider_timing'][provider]['selected_to_response']
            tn=delta(t0,t1,'count');da=next(iter(a.get('delivery',{}).values()),{}).get(provider,{});db=next(iter(b.get('delivery',{}).values()),{}).get(provider,{})
            ni=delta(da,db,'interval_count')
            ar0=(md0.get('artifacts') or {});ar1=(md1.get('artifacts') or {})
            tr0=ar0.get('training') or {};tr1=ar1.get('training') or {}
            rows.append(dict(mode=mode,level=stage['level'],camera=int(camera),provider=provider,seconds=dt,
                request_fps=delta(md0['providers'][provider],md1['providers'][provider],'requests')/dt,
                finalized_fps=delta(md0,md1,'finalized')/dt,
                queue_expired=delta(md0,md1,'completed_queue_expired'),queue_drop=delta(md0,md1,'completed_queue_drop'),
                selected_to_response_ms=delta(t0,t1,'sum_ms')/tn if tn else None,
                over100_pct=100*delta(t0,t1,'over_100ms')/tn if tn else None,
                redis_interval_mean_ms=delta(da,db,'interval_sum_ns')/ni/1e6 if ni else None,
                counts={k:delta(a,b,k) for k in ('sent_frames','replaced','expired','send_error')},
                training={k:delta(tr0,tr1,k) for k in ('settings_reads','admission_reads','candidate_checks','early_interval_skip','reserved','queued')},
                events_created=delta(md0,md1,'events_created'),
                cooldown_suppressed=sum(delta(md0['event_cooldown']['counts'],md1['event_cooldown']['counts'],k) for k in md1['event_cooldown']['counts'] if k.endswith('_suppressed_candidates')),
                max_queue_depth=max(s['channels'][camera]['providers'][provider]['metadata_path'].get('queued',0) for s in stage['samples']),
                max_queue_age=max(s['channels'][camera]['providers'][provider]['metadata_path'].get('completed_queue_age_s',0) for s in stage['samples']),timings=timings))
    stage_rows.append(dict(level=stage['level'],begin=first['wall_ms'],end=last['wall_ms'],
        training_first=first['training'],training_last=last['training'],artifact_ledger_first=first['artifacts'].get('ledger'),artifact_ledger_last=last['artifacts'].get('ledger')))
for name,data in [('detail-sot.json',rows),('storage-sot.json',stage_rows)]:
    with (ROOT/name).open('x') as f:json.dump(data,f,indent=2)
with (ROOT/'detail-sot.csv').open('x',newline='') as f:
    writer=csv.DictWriter(f,fieldnames=list(rows[0]));writer.writeheader();writer.writerows(rows)
print(json.dumps(dict(mode=mode,lanes=len(rows),replaced=sum(r['counts']['replaced'] for r in rows),queue_expired=sum(r['queue_expired'] for r in rows),early_skip=sum(r['training']['early_interval_skip'] for r in rows))))
