# Usage: python3 legacy-startup-driver.py BASE_CHECKOUT HEAD_CHECKOUT NEW_SCRATCH_DIRECTORY
import os,sys,time,subprocess,sqlite3,pathlib,json,signal,re,socket
ROOT=pathlib.Path(sys.argv[3]).resolve()
ROOT.mkdir(parents=True,exist_ok=True)
RUN=ROOT/time.strftime('run-%Y%m%d-%H%M%S'); RUN.mkdir()
BAD='2026-07-13T14:13:00.3NZ'; GOOD='2026-07-13T14:00:00.000Z'
SIDES={'before':(sys.argv[1],'f7b81e1d1115bc7284b39161d3cd6c7f3184eb1c'),'after':(sys.argv[2],'ba95a8c7ff634273b41983f421b08a39a4536749')}
procs=[]
def start(cwd,home,port,name):
 log=RUN/(name+'.raw.log'); f=log.open('w')
 p=subprocess.Popen(['node','apps/server/src/bin.ts','serve','--base-dir',str(home),'--host','127.0.0.1','--port',str(port)],cwd=cwd,env={**os.environ,'T3CODE_DEV_SEED':'0'},stdout=f,stderr=subprocess.STDOUT,start_new_session=True); procs.append(p)
 deadline=time.time()+80
 while time.time()<deadline:
  text=log.read_text()
  if 'T3 Code server is ready.' in text:return p,log,True
  if p.poll() is not None:return p,log,False
  time.sleep(.2)
 return p,log,False
def stop(p):
 if p.poll() is None:
  os.killpg(p.pid,signal.SIGTERM)
  try:p.wait(15)
  except subprocess.TimeoutExpired:os.killpg(p.pid,signal.SIGKILL);p.wait()
def seed(home,case):
 db=sqlite3.connect(home/'userdata/statev2.sqlite')
 db.execute('INSERT INTO projection_projects (project_id,title,workspace_root,scripts_json,created_at,updated_at) VALUES (?,?,?,?,?,?)',('legacy-project','Legacy timestamp demo',str(ROOT/'demo'),'[]',GOOD,GOOD))
 rows=[('legacy-archived','Archived legacy conversation',BAD,BAD,None),('legacy-deleted','Deleted legacy conversation',BAD,None,BAD)] if case=='thread' else [('legacy-preview','Legacy preview conversation',GOOD,None,None)]
 for tid,title,updated,archived,deleted in rows:
  db.execute('INSERT INTO projection_threads (thread_id,project_id,title,model_selection_json,runtime_mode,interaction_mode,created_at,updated_at,archived_at,deleted_at) VALUES (?,?,?,?,?,?,?,?,?,?)',(tid,'legacy-project',title,'{"instanceId":"codex","model":"default"}','full-access','default',GOOD,updated,archived,deleted))
  db.execute('INSERT INTO projection_thread_messages (message_id,thread_id,role,text,is_streaming,created_at,updated_at) VALUES (?,?,?,?,?,?,?)',(tid+'-message',tid,'user','Synthetic legacy question: can this conversation open?',0,BAD if case=='preview' else GOOD,GOOD))
 db.commit();db.close()
results=[]
try:
 (ROOT/'demo').mkdir(exist_ok=True)
 subprocess.run(['git','init',str(ROOT/'demo')],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
 for side,(cwd,sha) in SIDES.items():
  for case in ['thread','preview']:
   home=RUN/(side+'-'+case);port=14323 if side=='before' else 14324
   p,log,ready=start(cwd,home,port,side+'-'+case+'-initialize')
   if not ready:raise RuntimeError('Fresh server initialization failed: '+str(log))
   stop(p);seed(home,case)
   p,log,ready=start(cwd,home,port,side+'-'+case+'-reproduce')
   text=log.read_text();errors='\n'.join(x.strip() for x in text.splitlines() if 'Invalid date' in x or 'LegacyV1ThreadImporter' in x or 'server is ready' in x or 'Listening on' in x)
   transcript=[f'Side: {side}',f'Commit: {sha}',f'Environment: Linux, real Node server bound to loopback, fresh isolated database.',f'Case: {case}',f'Malformed timestamp: {BAD}',f'Server reached readiness: {ready}',f'Process exit code: {p.poll()}',errors]
   db=sqlite3.connect(home/'userdata/statev2.sqlite')
   data=db.execute('SELECT thread_id,payload_json FROM orchestration_v2_projection_threads ORDER BY thread_id').fetchall()
   public=[]
   for tid,payload in data:
    t=json.loads(payload);public.append({k:t.get(k) for k in ['id','title','createdAt','updatedAt','archivedAt','deletedAt']})
   transcript.append('Imported thread projections: '+json.dumps(public,indent=2))
   msgs=db.execute('SELECT count(*) FROM orchestration_v2_projection_messages').fetchone()[0]
   transcript.append('Imported message count: '+str(msgs));db.close()
   if ready:
    cmd=['node','apps/server/src/bin.ts','thread','show','--base-dir',str(home),'--json','legacy-preview' if case=='preview' else 'legacy-archived']
    r=subprocess.run(cmd,cwd=cwd,env={**os.environ,'T3CODE_DEV_SEED':'0'},capture_output=True,text=True,timeout=40)
    out=r.stdout+r.stderr
    out=out.replace(str(ROOT),'[isolated-fixture]').replace(cwd,'[checkout]')
    transcript.append('Real CLI conversation read (through running server):\n'+out)
   path=RUN/(side+'-'+case+'.txt');path.write_text('\n'.join(transcript)+'\n')
   results.append(dict(side=side,case=case,sha=sha,ready=ready,invalidDate='Invalid date' in text,transcript=str(path),home=str(home)))
   print(json.dumps(results[-1]),flush=True)
   stop(p)
 (RUN/'results.json').write_text(json.dumps(results,indent=2));print('RUN='+str(RUN),flush=True)
finally:
 for p in procs:stop(p)
