"""Render captured CLI state and timestamped process events; no app state is synthesized."""
from PIL import Image,ImageDraw,ImageFont
import pathlib,json,re,subprocess,textwrap
root=pathlib.Path(__file__).parent
font=ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf',19)
small=ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf',16)
for side in ['before','after']:
 folder=sorted(root.glob(side+'-*'))[-1]
 events=[json.loads(line) for line in (folder/'recording.cast').read_text().splitlines()[1:]]
 stages=[]; history=[]
 for elapsed,kind,line in events:
  line=line.strip()
  if 'automatic continuation messages=' in line:
   label=line.split(' UTC ',1)[1].split(':',1)[0]
   data=json.loads((folder/(label+'.json')).read_text())
   thread=data['thread']; line=line.split(': status=',1)[0]+': status='+thread['status']+'; runCount='+str(thread['runCount'])
   line+='; automatic resumes='+str(thread['runCount']-1)
  elif '[assistant]' in line or '[user]' in line or line.startswith('FINAL:') or ' UTC FINAL:' in line: continue
  history.extend(textwrap.wrap(line,108))
  stages.append((elapsed,list(history)))
 final=json.loads((folder/'after-loss-4.json').read_text())['thread']
 history.extend(['','Final raw CLI fields:',json.dumps({k:final[k] for k in ['status','runCount','activeRunId']},indent=2)])
 stages.append((stages[-1][0]+2,history[:]))
 def frame(lines,clock):
  im=Image.new('RGB',(1440,900),'#111820'); d=ImageDraw.Draw(im)
  d.text((30,25),'Crash recovery budget | '+side.upper(),font=font,fill='#f2f6fb')
  d.text((30,60),'Actual CLI responses + process events | elapsed '+str(round(clock,1))+' s',font=small,fill='#a6b9ca')
  y=110
  for line in lines[-30:]:
   for row in line.splitlines():
    d.text((30,y),row,font=font,fill=('#ffb86c' if 'Unplanned' in row else '#d5e4ee')); y+=24
  d.text((30,860),'Replay ACP agent; real source server and fresh database. Video timeline: 12x.',font=small,fill='#a6b9ca')
  return im
 frame(history,stages[-1][0]).save(root/(side+'.png'))
 proc=subprocess.Popen(['ffmpeg','-y','-loglevel','error','-f','rawvideo','-pixel_format','rgb24','-video_size','1440x900','-framerate','10','-i','-','-an','-c:v','libx264','-preset','fast','-crf','22','-pix_fmt','yuv420p',str(root/(side+'.mp4'))],stdin=subprocess.PIPE)
 end=stages[-1][0]+24
 for i in range(int(end/12*10)):
  real=i/10*12
  current=stages[0][1]
  for stamp,lines in stages:
   if stamp<=real: current=lines
  proc.stdin.write(frame(current,real).tobytes())
 proc.stdin.close(); assert proc.wait()==0
 # Sanitized evidence is limited to captured CLI responses and safe runtime warnings.
 warnings=[]
 for log in sorted(folder.glob('server-*.log')):
  for line in log.read_text().splitlines():
   if 'Not continuing a run restarted too many times in a row' in line: warnings.append(line)
 (root/(side+'-runtime-warning.txt')).write_text('\n'.join(warnings)+'\n')
 (root/(side+'-cli.json')).write_text(json.dumps({label:json.loads((folder/(label+'.json')).read_text()) for label in ['initial','after-loss-1','after-loss-2','after-loss-3','after-loss-4']},indent=2))
 (root/(side+'-transcript.txt')).write_text('\n'.join(history)+'\n')
