import sys,json,pathlib,textwrap,subprocess
from PIL import Image,ImageDraw,ImageFont
p=pathlib.Path(sys.argv[1]);side=sys.argv[2];sha=sys.argv[3];data=json.loads((p/(side+'-results.json')).read_text());events=data['events'];prefix='before' if side=='base' else 'after'
font=ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf',22)
lines=[prefix.upper()+' '+sha+' | Real T3 server | Node 26.12.1','Fresh isolated database; synthetic ACP agent never completes','delegate_task mode: wait; no timeoutMs; no clientRequestId','Timed client-output replay at 10x; long handles abbreviated below','Full responses are in the attached JSON transcript.','']
frames=[]
for index,e in enumerate(events):
 msg=e['message']
 if msg.startswith('Real server') or msg.startswith('delegate_task {'):continue
 if 'result:' in msg or 'response:' in msg:
  try:
   obj=json.loads(msg.split(': ',1)[1]);r=obj.get('result',obj)
   if isinstance(r,dict) and 'structuredContent' in r:r=r['structuredContent']
   elif isinstance(r,dict) and 'content' in r:r=json.loads(r['content'][0]['text'])
   if 'error' in obj:msg='stdio bridge error: '+json.dumps(obj['error'])+'; no task handle'
   else:
    r={k:(v[:20]+'...'+v[-12:] if k in ['taskId','childThreadId'] and isinstance(v,str) else v) for k,v in r.items() if k in ['taskId','childThreadId','status','waitTimedOut']}
    msg=msg.split(': ',1)[0]+': '+json.dumps(r)
  except:pass
 lines.extend(textwrap.wrap(f"+{e['seconds']:.1f}s {msg}",100));lines.append('')
 im=Image.new('RGB',(1440,900),'#111827');d=ImageDraw.Draw(im)
 for i,line in enumerate(lines):d.text((36,30+i*31),line,font=font,fill='#e5e7eb')
 path=p/(prefix+'-frame-'+str(index)+'.png');im.save(path);frames.append((e['seconds'],path))
frames[-1][1].replace(p/(prefix+'.png'))
frames[-1]=(frames[-1][0],p/(prefix+'.png'))
concat=p/(prefix+'-frames.txt')
text=''
for i,(t,f) in enumerate(frames):
 duration=max(.2,((frames[i+1][0]-t)/10) if i+1<len(frames) else 5)
 text+="file '"+str(f)+"'\nduration "+str(duration)+"\n"
text+="file '"+str(frames[-1][1])+"'\n"
concat.write_text(text)
subprocess.run(['ffmpeg','-v','error','-y','-f','concat','-safe','0','-i',str(concat),'-vf','fps=10','-c:v','libx264','-pix_fmt','yuv420p',str(p/(prefix+'-timed.mp4'))],check=True)
