"""Render the raw measurement output; no measured values are entered by hand.
Usage: python3 report.py BASE_MEASUREMENT HEAD_MEASUREMENT OUTPUT_DIR
"""
import sys,json,pathlib,statistics
from PIL import Image,ImageDraw,ImageFont
def load(p):
 path=pathlib.Path(p);data=json.loads(path.read_text());inline=path.with_name('inline-verification.json')
 if inline.exists():data['inlineVerification']=json.loads(inline.read_text())
 return data
base,head=[load(p) for p in sys.argv[1:3]]
out=pathlib.Path(sys.argv[3]); metrics=[('openMedianMs','Open'),('olderMedianMs','Older page'),('combinedMedianMs','Open + older'),('sixConcurrentP95Ms','Six opens p95')]
for side,data in [('before',base),('after',head)]:
 lines=['LONG THREAD / REAL SERVER HTTP MEASUREMENT',side.upper()+'  '+data['commit'],data['environment'],f"Fresh replay history: {data['seed']['turns']} turns x {data['seed']['toolsPerTurn']} tools x 40,000 bytes",f"Prompts: {data['seed'].get('authorship','agent/mcp')}; one inline tool every 20 turns; deferWork=1",'3 warmups; 40 open + older reads; 15 x 6 concurrent opens','Five rounds, same VM, milliseconds','',f'{"Round":<8}{"Open":>13}{"Older":>13}{"Combined":>13}{"6-open p95":>15}']
 for r in data['rounds']:lines.append(f'{r["round"]:<8}'+''.join(f'{r[k]:>13.2f}' for k,_ in metrics))
 lines+=['','Median of rounds / range across round statistics:']
 for k,label in metrics:
  vals=[r[k] for r in data['rounds']];lines.append(f'{label:<18} {statistics.median(vals):7.2f} ms   [{min(vals):.2f}, {max(vals):.2f}]')
 b=data['behavior']; lines += ['', f"Returned rows: initial {b['initial']['returnedItems']}, older {b['older']['returnedItems']}; deferred groups {len(b['initial']['deferredGroups'])}/{len(b['older']['deferredGroups'])}", f"Known inline items retained: {data.get('inlineVerification',{}).get('initial',{}).get('knownInlineItemsRetained','?')}/{data.get('inlineVerification',{}).get('older',{}).get('knownInlineItemsRetained','?')} (initial/older); bodies load separately"]
 lines+=['','Synthetic data only. Timings include loopback HTTP and JSON.','Not a browser/render measurement or the historical 6.3 GB DB.']
 text='\n'.join(lines);(out/(side+'.txt')).write_text(text+'\n')
 font=ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf',19)
 im=Image.new('RGB',(1540,48+len(lines)*26),'#10151c');d=ImageDraw.Draw(im)
 for i,line in enumerate(lines):d.text((28,24+i*26),line,font=font,fill='#e1e8ef')
 im.save(out/(side+'.png'))
print('semantic hashes:',base['semanticSha256'],head['semanticSha256'])
for k,label in metrics:
 a=[r[k] for r in base['rounds']];b=[r[k] for r in head['rounds']]
 gain=statistics.median(a)-statistics.median(b)
 print(label, 'base',round(statistics.median(a),2),'head',round(statistics.median(b),2),'ratio',round(statistics.median(a)/statistics.median(b),2),'gain',round(gain,2),'base spread',round(max(a)-min(a),2),'head spread',round(max(b)-min(b),2),'ranges separated',max(b)<min(a))
