import csv
import json
from pathlib import Path
import statistics

root=Path(__file__).parent
def cpu(row):
    v=list(map(int,row['cpu_stat'].split()[1:9]));return sum(v),v[3]+v[4]
def usage(row):return dict(line.split() for line in row['cpu.stat'].splitlines())
def summarize(name):
    d=json.loads((root/(name+'.json')).read_text());rows=d['samples'];first,last=rows[0],rows[-1]
    seconds=last['wall']-first['wall']
    channels=[]
    for end in last['streams']:
        start=next((r for r in first['streams'] if r['stream_id']==end['stream_id']),None)
        if start is None or start['run_id']!=end['run_id']:raise ValueError('Run drift within observation')
        a,b=start['metadata_path'],end['metadata_path']
        if set(a['providers'])!=set(b['providers']):raise ValueError('Provider drift')
        for provider, value in b['providers'].items():
            old=a['providers'][provider]
            delta=lambda key:value.get(key,0)-old.get(key,0)
            channels.append(dict(stream=end['stream_id'],provider=provider,seconds=seconds,
                completed_fps=delta('responses')/seconds,request_fps=delta('requests')/seconds,
                finalized_fps=(b.get('finalized',0)-a.get('finalized',0))/seconds,
                redis_fps=(end['publisher_metrics'].get('sent_frames',0)-start['publisher_metrics'].get('sent_frames',0))/seconds,
                sender_replaced=end['publisher_metrics'].get('replaced',0)-start['publisher_metrics'].get('replaced',0),
                source_queue_gap=b.get('performance',{}).get('counts',{}).get('source_queue_gap',0)-a.get('performance',{}).get('counts',{}).get('source_queue_gap',0),
                cache=end['metadata_path'].get('artifacts',{}).get('protected_cache'),
                artifact_delta={k:v-a.get('artifacts',{}).get(k,0) for k,v in b.get('artifacts',{}).items() if isinstance(v,int)}))
    total0,idle0=cpu(first);total1,idle1=cpu(last)
    app_cpu=(int(usage(last)['usage_usec'])-int(usage(first)['usage_usec']))/1e6/seconds*100
    gpu=[list(map(float,r['gpu'].splitlines()[0].split(','))) for r in rows if r.get('gpu')]
    by_provider={}
    for key in sorted({r['provider'] for r in channels}):
        selected=[r for r in channels if r['provider']==key]
        by_provider[key]={kind:dict(mean=statistics.mean(r[kind] for r in selected),minimum=min(r[kind] for r in selected)) for kind in ('completed_fps','finalized_fps','redis_fps')}
    return dict(name=name,seconds=seconds,samples=len(rows),channels=channels,providers=by_provider,
                host_cpu_percent=100*(1-(idle1-idle0)/(total1-total0)),app_cpu_one_core_percent=app_cpu,
                cgroup_memory_average=statistics.mean(int(r['memory.current']) for r in rows),
                cgroup_memory_peak=max(int(r['memory.current']) for r in rows),
                host_available_min_kib=min(r['memory']['MemAvailable'] for r in rows),
                gpu_average=statistics.mean(r[0] for r in gpu),gpu_memory_max_mib=max(r[1] for r in gpu))

summary={name:summarize(name) for name in ('baseline-resource','candidate')}
for name in summary:
    with (root/(name+'-fps.csv')).open('w') as f:
        keys=['stream','provider','seconds','request_fps','completed_fps','finalized_fps','redis_fps','sender_replaced','source_queue_gap']
        w=csv.DictWriter(f,fieldnames=keys,extrasaction='ignore');w.writeheader();w.writerows(summary[name]['channels'])
(root/'comparison.json').write_text(json.dumps(summary,indent=2))
for name,s in summary.items():
    print(json.dumps({k:v for k,v in s.items() if k!='channels'},indent=2))
