import os,sys,time,json,subprocess,socket,urllib.request,urllib.error,signal
from pathlib import Path
ROOT=Path(__file__).parent
NODE=subprocess.check_output(['which','node'],text=True).strip()
def cmd(args): return subprocess.check_output(args,text=True,stderr=subprocess.STDOUT).strip()
def run(side,checkout,port):
 out=ROOT/(side+'-'+time.strftime('%Y%m%d-%H%M%S'));out.mkdir()
 home=out/'home'; rt=home/'runtime/versions/0.1.9';rt.mkdir(parents=True)
 binary=rt/'t3'; binary.write_text('#!/bin/sh\nexec '+NODE+' '+str(Path(checkout)/'apps/server/dist/bin.mjs')+' "$@"\n');binary.chmod(0o755)
 (rt/'.install-complete').write_text('0.1.9')
 (home/'runtime/service-state.json').write_text(json.dumps({'protocol':4,'activeVersion':'0.1.9'}))
 env=os.environ.copy();env.update(T3CODE_HOME=str(home),T3CODE_DEV_SEED='0',T3CODE_PORT=str(port),T3CODE_HOST='127.0.0.1')
 unit='factory-pr-25237-evidence-3-'+side+'-'+str(int(time.time()))
 events=[]; start=time.monotonic()
 def log(s):
  event={'seconds':round(time.monotonic()-start,1),'text':s};events.append(event);print(side,event,flush=True)
 def probe():
  try:
   r=urllib.request.urlopen('http://127.0.0.1:'+str(port)+'/.well-known/t3/environment',timeout=1);return 'HTTP '+str(r.status)
  except urllib.error.HTTPError as e:return 'HTTP '+str(e.code)
  except Exception:return 'connection refused'
 def status():
  active=cmd(['systemctl','--user','show',unit,'--property=ActiveState','--value'])
  pid=cmd(['systemctl','--user','show',unit,'--property=MainPID','--value'])
  try: children=Path('/proc/'+pid+'/task/'+pid+'/children').read_text().split()
  except: children=[]
  return 'service='+active+', server children='+str(len(children))+', '+probe()
 competitor=None
 try:
  log('Linux user service; real bundled CLI; fresh isolated T3 home; no seeded data.')
  log('Start competing T3 server on the same home (desktop-managed server equivalent).')
  f=open(out/'competitor.raw.log','w');competitor=subprocess.Popen([str(binary),'serve'],env=env,stdout=f,stderr=f)
  for _ in range(90):
   if probe()!='connection refused':break
   if competitor.poll() is not None:raise RuntimeError('competing server failed; inspect private raw log')
   time.sleep(1)
  if probe()=='connection refused':raise RuntimeError('competing server never listened')
  log('Competing server descriptor endpoint: '+probe())
  rejection=subprocess.run([str(binary),'serve'],env=env,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
  log('Second real server on same home exits with status '+str(rejection.returncode))
  args=['systemd-run','--user','--unit='+unit,'--property=Restart=no','--setenv=T3CODE_HOME='+str(home),'--setenv=T3CODE_DEV_SEED=0','--setenv=T3CODE_PORT='+str(port),'--setenv=T3CODE_HOST=127.0.0.1',str(binary),'__service-launcher']
  cmd(args);log('Start isolated user service with production service launcher.')
  for _ in range(40):
   journal=cmd(['journalctl','--user','-u',unit,'--no-pager','-o','cat'])
   if 'Another T3 Code server owns' in journal:break
   time.sleep(1)
  if 'Another T3 Code server owns' not in journal:raise RuntimeError('launcher did not enter ownership idle')
  log('Launcher reports: '+next(x.strip() for x in journal.splitlines() if 'Another T3 Code server owns' in x))
  log('Ownership conflict observed: '+status())
  log('Stop competing server with SIGTERM; wait for its process to exit.')
  competitor.terminate();competitor.wait(timeout=30);log('Competing server exited; '+status());released=time.monotonic()
  for i in range(17):
   if i:time.sleep(5)
   log('After ownership release +'+str(round(time.monotonic()-released,1))+'s: '+status())
  journal=cmd(['journalctl','--user','-u',unit,'--no-pager','-o','cat'])
  for line in journal.splitlines():
   if 'The T3 home is free again.' in line:log(line.strip())
  log('Observation complete. Stop isolated service.')
 finally:
  subprocess.run(['systemctl','--user','stop',unit],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
  if competitor and competitor.poll() is None:competitor.terminate();competitor.wait(timeout=30)
  (out/'events.json').write_text(json.dumps(events,indent=2))
  (out/'transcript.txt').write_text('\n'.join(f"{e['seconds']:6.1f}s  {e['text']}" for e in events)+'\n')
  print('OUTPUT',out,flush=True)
if __name__=='__main__':
 run(sys.argv[1],sys.argv[2],int(sys.argv[3]))
