#!/usr/bin/env python3
"""Run from either checkout; needs vp, node, and the adjacent catalog-agent.mjs."""
import datetime, json, os, pathlib, signal, subprocess, sys, time
checkout=pathlib.Path.cwd()
root=pathlib.Path(__file__).resolve().parent
stamp=datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%dT%H%M%SZ')
run=root/('run-'+sys.argv[1]+'-'+stamp)
run.mkdir()
(run/'workspace').mkdir()
# Each server creates its own fresh database at its own migration level.
home=checkout/'.t3'/('proof-'+stamp)
(home/'userdata').mkdir(parents=True)
settings={'providerInstances':{'evidenceCatalog':{'driver':'acpRegistry','displayName':'Synthetic catalog','config':{'source':'local','commandPath':'/usr/bin/env','commandArgs':['node',str(root/'catalog-agent.mjs')]}}}}
(home/'userdata'/'settings.json').write_text(json.dumps(settings))
sha=subprocess.check_output(['git','rev-parse','HEAD'],text=True).strip()
env={**os.environ,'T3CODE_DEV_SEED':'0','EVIDENCE_OUTPUT':str(run/'response.json')}
log=open(run/'private-startup.log','w')
server=subprocess.Popen(['vp','run','dev','--home-dir',str(home)],stdout=log,stderr=subprocess.STDOUT,env=env,start_new_session=True)
try:
 for _ in range(240):
  if server.poll() is not None:raise RuntimeError('Server exited; inspect private-startup.log')
  if 'Listening on http://' in (run/'private-startup.log').read_text():break
  time.sleep(.5)
 else:raise RuntimeError('Startup timeout')
 command=['node','apps/server/src/bin.ts']
 with open(run/'private-seed.log','w') as out:
  subprocess.run(command+['project','add','--base-dir',str(home),str(run/'workspace'),'--title','Synthetic evidence project'],check=True,stdout=out,stderr=subprocess.STDOUT)
 with open(run/'private-launch.log','w') as out:
  subprocess.run(command+['thread','start','--base-dir',str(home),'--provider','evidenceCatalog','--model','sample-1','--title','Delegation refusal evidence',str(run/'workspace'),'Run the two invalid-model delegation requests.','--wait','--json'],check=True,stdout=out,stderr=subprocess.STDOUT)
 events=[json.loads(x) for x in (run/'response.json.ndjson').read_text().splitlines()]
 header=f'T3 Code real server | Linux | source dev server\nCommit: {sha}\nFresh isolated database; synthetic ACP catalog; no paid provider.\nCatalog: '+', '.join(events[0]['slugs'])+'\n'
 # A direct terminal recording of the request/response journal. No response text is invented.
 frames=[(0,header)]
 t0=events[0]['at']
 for e in events[1:]:
  if e['event']=='request': text='\n> delegate_task '+json.dumps(e['args'])+'\n'
  else:
   result=e['result']; failure=json.loads(result['content'][0]['text'])
   text='< isError='+str(result['isError']).lower()+' '+failure['code']+'\n'+failure['message']+'\n'
  frames.append(((e['at']-t0)/1000,text))
 with open(run/'interaction.cast','w') as out:
  out.write(json.dumps({'version':2,'width':112,'height':32,'timestamp':int(time.time()),'title':'Real server delegation refusal'})+'\n')
  for at,text in frames:out.write(json.dumps([at,'o',text.replace('\n','\r\n')])+'\n')
 (run/'transcript.txt').write_text(''.join(text for _,text in frames))
 print(run)
finally:
 os.killpg(server.pid,signal.SIGTERM)
 try:server.wait(timeout=20)
 except subprocess.TimeoutExpired:
  os.killpg(server.pid,signal.SIGKILL);server.wait()
 log.close()
