import csv
import json
import os
from pathlib import Path
import subprocess
from PIL import Image, ImageChops, ImageStat

os.umask(0o077)
R=Path(__file__).parent
d=json.loads((R/'run.json').read_text())
assert d['stage']=='completed' and d['window_result']=='OFF_ON_COMPLETE'
windows=d['windows']
points={w['mode']:{s['frame']:s for s in w['samples']} for w in windows}
common=sorted(set(points['off']) & set(points['on']))
assert len(common)>=2, 'NO_COMMON_FRAME_BOUNDARIES'
first,last=common[0],common[-1]
rows=[]
for w in windows:
    a,b=points[w['mode']][first],points[w['mode']][last]
    assert a['pts_ns']==points['off'][first]['pts_ns'] and b['pts_ns']==points['off'][last]['pts_ns']
    p,q=a['performance'],b['performance']
    seconds=(q['last_ns']['result']-p['last_ns']['result'])/1e9
    counts={k:q['counts'].get(k,0)-p['counts'].get(k,0) for k in q['counts']}
    means={}
    for k,end in q['durations'].items():
        start=p['durations'].get(k,dict(samples=0,mean_ms=0))
        count=end['samples']-start['samples']
        if count>0:
            means[k]=(end['mean_ms']*end['samples']-start['mean_ms']*start['samples'])/count
    rows.append(dict(mode=w['mode'],first_frame=first,last_frame=last,source_pts_s=[a['pts_ns']/1e9,b['pts_ns']/1e9],
        seconds=seconds,counts=counts,fps={k:v/seconds for k,v in counts.items()},mean_ms=means,
        stale=b['stale']-a['stale'],queue_drop=b['queue_drop']-a['queue_drop'],
        redis_sent=b['publisher'].get('sent_frames',0)-a['publisher'].get('sent_frames',0),
        cleanup_seconds=w['cleanup']['elapsed_s'],visual=w['visual'],events_observed=w['events_observed']))
    first_sample,last_sample=w['samples'][0],w['samples'][-1]
    duration=(last_sample['performance']['last_ns']['result']-first_sample['performance']['last_ns']['result'])/1e9
    rows[-1]['whole_observed_interval']=dict(first_frame=first_sample['frame'],last_frame=last_sample['frame'],
        result_fps=(last_sample['performance']['counts']['result']-first_sample['performance']['counts']['result'])/duration,
        stale=last_sample['stale']-first_sample['stale'],queue_drop=last_sample['queue_drop']-first_sample['queue_drop'])
input_data=json.loads((R/'approved-input.json').read_text())
colors=[]
for path in sorted((R/'visual').glob('capture-*/frame-*.json')):
    value=json.loads(path.read_text())
    stats=json.loads(path.with_suffix('.stats').read_text())
    width,height=value['frameWidth'],value['frameHeight']
    pts=value['ptsNs']/1e9
    p=subprocess.run(['ffmpeg','-v','error','-ss',str(pts),'-i',input_data['path'],'-frames:v','1',
        '-f','rawvideo','-pix_fmt','rgb24','pipe:1'],capture_output=True,timeout=15,check=True)
    assert len(p.stdout)==width*height*3
    reference=Image.frombytes('RGB',(width,height),p.stdout)
    actual=Image.open(path.with_suffix('.jpg')).convert('RGB')
    h=stats['header_height']
    actual=actual.crop((0,h,width,h+height))
    reference=reference.resize((320,180));actual=actual.resize((320,180))
    channels=reference.split();swapped=Image.merge('RGB',tuple(reversed(channels)))
    mae=sum(ImageStat.Stat(ImageChops.difference(actual,reference)).mean)/3
    swapped_mae=sum(ImageStat.Stat(ImageChops.difference(actual,swapped)).mean)/3
    colors.append(dict(frame=value['frameSeq'],pts_s=pts,rgb_mae=mae,swapped_mae=swapped_mae,
                       rgb_closer=mae<swapped_mae))
summary=dict(windows=rows,color=colors,common_frames=common,final=d['final'],
             startup_preparation=windows[0]['preparation'],runtime_windows=2,builds=1,
             first_capture_outside_paired_interval=windows[1]['visual']['capture_timing'][0]['frame_seq']<=first)
(R/'summary.json').write_text(json.dumps(summary,indent=2))
with (R/'summary.csv').open('w',newline='') as f:
    out=csv.writer(f);out.writerow(['mode','first_frame','last_frame','seconds','result_fps','tracking_wall_ms','tracking_cpu_ms','scenario_wall_ms','stale','cleanup_s'])
    for w in rows:
        out.writerow([w['mode'],first,last,w['seconds'],w['fps']['result'],w['mean_ms'].get('tracking'),w['mean_ms'].get('tracking_cpu'),w['mean_ms'].get('scenario'),w['stale'],w['cleanup_seconds']])
print(json.dumps(dict(results=[{k:w[k] for k in ('mode','first_frame','last_frame','fps','mean_ms','stale','queue_drop','cleanup_seconds')} for w in rows],color=colors,preparation=summary['startup_preparation'])))
