#!/usr/bin/env python3
"""Real built CLI shared-home reproduction. Linux user/PID/network/UTS namespaces.
Usage: python3 driver.py CHECKOUT OUTPUT_ROOT SIDE
No live T3 state or service is modified. Output paths are redacted for publication.
"""
import os, sys, pathlib, subprocess, time, json, re, signal, selectors, shlex
checkout, root, side = map(str, sys.argv[1:])
run = pathlib.Path(root) / (side + '-' + str(time.time_ns())); run.mkdir(parents=True)
home = run/'home'; home.mkdir(); base = home/'.t3'; base.mkdir()
node = subprocess.check_output(['node','-p','process.execPath'],text=True).strip()
binfile = str(pathlib.Path(checkout)/'apps/server/dist/bin.mjs')
env = dict(os.environ, HOME=str(home), XDG_CONFIG_HOME=str(home/'.config'), T3CODE_DEV_SEED='0', NO_COLOR='1', FORCE_COLOR='0', T3CODE_HOME=str(base), DBUS_SESSION_BUS_ADDRESS='unix:path=/nonexistent-evidence-bus')
for key in ['T3_SERVICE_LAUNCHER_CONTEXT','SYSTEMD_UNIT_PATH','VITE_HTTP_URL','VITE_WS_URL']:
    env.pop(key,None)
start=time.monotonic(); events=[]; transcript=[]
def clean(s):
    s=re.sub(r'\x1b\[[0-9;]*[a-zA-Z]','',s)
    return s.replace(str(home),'$HOME').replace(checkout,'<checkout>').replace(str(run),'<scratch>')
def emit(s):
    s=clean(s); transcript.append(s); events.append([round(time.monotonic()-start,3),'o',s]); print(s,end='',flush=True)
def command(args, label, timeout=25):
    emit('\n$ '+label+'\n')
    p=subprocess.Popen([node,binfile]+args, env=env, cwd=checkout+'/apps/server',stdout=subprocess.PIPE,stderr=subprocess.STDOUT,start_new_session=True)
    sel=selectors.DefaultSelector(); sel.register(p.stdout,selectors.EVENT_READ); deadline=time.monotonic()+timeout; buf=''
    while time.monotonic()<deadline:
        for key,_ in sel.select(.1):
            data=os.read(key.fileobj.fileno(),65536)
            if data:
                text=data.decode(errors='replace'); buf+=text; emit(text)
            else: sel.unregister(key.fileobj)
        if p.poll() is not None and not sel.get_map(): break
        if '__service-launcher' in args and ('restart this service' in buf): break
    if p.poll() is None:
        os.killpg(p.pid,signal.SIGTERM)
        try:p.wait(8)
        except subprocess.TimeoutExpired:os.killpg(p.pid,signal.SIGKILL);p.wait()
        emit('[capture driver stopped the process it started]\n')
    else: emit('[exit '+str(p.returncode)+']\n')
    return buf
ownerlog=open(run/'owner-private.log','w')
# exec makes the actual server PID 1 within host A, colliding with host B init.
owner=subprocess.Popen(['unshare','-Urnpfu','--mount-proc','sh','-c','hostname evidence-host-a; exec "$@"','host-a',node,binfile,'serve','--base-dir',str(base),'--port','39555'],env=env,cwd=checkout+'/apps/server',stdout=ownerlog,stderr=subprocess.STDOUT,start_new_session=True)
try:
    state=base/'userdata/server-runtime.json'
    for _ in range(600):
        if state.exists(): break
        if owner.poll() is not None: raise RuntimeError('owner exited; inspect private log')
        time.sleep(.1)
    else:raise RuntimeError('owner did not publish runtime state')
    data=json.loads(state.read_text())
    emit('Shared-home CLI reproduction | '+side.upper()+'\n')
    emit('Linux x86_64; built CLI; fresh synthetic HOME; no copied database.\n')
    emit('Host A: isolated PID + network + UTS namespaces; hostname evidence-host-a.\n')
    emit('Host B: normal PID/network namespace; same home files.\n')
    emit('Server A is live; recorded PID='+str(data['pid'])+', port='+str(data['port'])+', hostname='+str(data.get('hostname','<absent>'))+'.\n')
    emit('Local PID 1 exists; server A loopback is unreachable from host B.\n')
    command(['pair','--base-dir',str(base)],'t3 pair --base-dir "$HOME/.t3"')
    command(['serve','--base-dir',str(base),'--port','39556'],'t3 serve --base-dir "$HOME/.t3" --port 39556')
    # Synthetic installed unit, read by the real CLI. Never load or activate it.
    unit=home/'.config/systemd/user/t3code.service';unit.parent.mkdir(parents=True)
    unit.write_text('[Unit]\nDescription=Synthetic evidence service\n[Service]\nEnvironment=T3CODE_HOME='+str(base)+'\nExecStart=/synthetic/t3 __service-launcher\n')
    before=unit.read_bytes()
    command(['up','--base-dir',str(home/'.t3-hostB'),'--yes','--headless'],'t3 up --base-dir "$HOME/.t3-hostB" --yes --headless')
    emit('Synthetic unit unchanged: '+str(before==unit.read_bytes())+'. No uninstall executed.\n')
    runtime=base/'runtime'; version=runtime/'versions/0.1.8';version.mkdir(parents=True)
    (version/'.install-complete').write_text('0.1.8')
    wrapper=version/'t3';wrapper.write_text('#!/bin/sh\nexec '+shlex.quote(node)+' '+shlex.quote(binfile)+' "$@"\n');wrapper.chmod(0o755)
    (runtime/'service-state.json').write_text(json.dumps({'protocol':3,'activeVersion':'0.1.8'}))
    command(['__service-launcher'],'t3 __service-launcher (same shared T3 home)',timeout=30)
    emit('Server A still alive after all commands: '+str(owner.poll() is None)+'.\n')
finally:
    if owner.poll() is None: os.killpg(owner.pid,signal.SIGTERM)
    try:owner.wait(10)
    except subprocess.TimeoutExpired:os.killpg(owner.pid,signal.SIGKILL);owner.wait()
    ownerlog.close()
    (run/'transcript.txt').write_text(''.join(transcript))
    with (run/'recording.cast').open('w') as f:
        f.write(json.dumps({'version':2,'width':120,'height':40,'title':'Shared-home CLI '+side,'env':{'TERM':'xterm-256color'}})+'\n')
        for e in events:f.write(json.dumps(e)+'\n')
    (run/'events.json').write_text(json.dumps(events))
    print('RUN_DIRECTORY='+str(run))
