#!/usr/bin/env python3
"""Run the built real server twice intact, then with its signing key truncated.
Usage: python3 reproduce.py CHECKOUT OUTPUT_ROOT SIDE PORT
No secrets, pairing links, or local paths are published in the transcript.
"""
import os, sys, subprocess, time, pathlib, selectors, json, datetime, urllib.request
checkout, root, side, port = sys.argv[1:]
out = pathlib.Path(root) / (side + '-' + datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%dT%H%M%SZ'))
out.mkdir(parents=True)
state = out / 'state'
sha = subprocess.check_output(['git','rev-parse','HEAD'],cwd=checkout,text=True).strip()
start = time.monotonic(); events=[]
def emit(s):
    print(s,flush=True); events.append([round(time.monotonic()-start,3),s])
emit('T3 Code real server | Linux x86_64 | Node '+subprocess.check_output(['node','--version'],text=True).strip())
emit('Commit: '+sha)
emit('Built with: vp run --filter t3 build:bundle')
emit('Fresh isolated state; T3CODE_DEV_SEED=0; loopback only; no client/theme/viewport')
def launch(label):
    emit('\n$ '+label+': node apps/server/dist/bin.mjs serve --base-dir <disposable-state> --host 127.0.0.1 --port <port> --no-browser')
    raw=open(out/(label+'.private.log'),'w')
    p=subprocess.Popen(['node','apps/server/dist/bin.mjs','serve','--base-dir',str(state),'--host','127.0.0.1','--port',port,'--no-browser'],cwd=checkout,env={**os.environ,'T3CODE_DEV_SEED':'0'},stdout=subprocess.PIPE,stderr=subprocess.STDOUT,bufsize=0)
    sel=selectors.DefaultSelector(); sel.register(p.stdout,selectors.EVENT_READ)
    ready=False; pending=''; deadline=time.monotonic()+60
    while time.monotonic()<deadline:
        if sel.select(.2):
            chunk=os.read(p.stdout.fileno(),65536).decode(errors='replace')
            if not chunk and p.poll() is not None: break
            raw.write(chunk); raw.flush(); pending+=chunk
            while '\n' in pending:
                line,pending=pending.split('\n',1)
                for marker in ['Migrations ran successfully','Listening on http://127.0.0.1:', 'T3 Code server is ready.', 'An HMAC key cannot be empty']:
                    if marker in line: emit('server: '+line.strip().split('): ')[-1].replace(port,'<port>'))
                if 'T3 Code server is ready.' in line: ready=True
            if ready: break
        elif p.poll() is not None: break
    if ready:
        deadline_http=time.monotonic()+30
        status=None
        while time.monotonic()<deadline_http:
            try:
                with urllib.request.urlopen('http://127.0.0.1:'+port+'/.well-known/t3/environment') as r: status=r.status
            except urllib.error.HTTPError as e: status=e.code
            if status != 503: break
            time.sleep(.1)
        emit('HTTP GET /.well-known/t3/environment: '+str(status))
        p.terminate()
    elif p.poll() is None: p.terminate()
    try: code=p.wait(timeout=15)
    except subprocess.TimeoutExpired: p.kill(); code=p.wait()
    raw.write(p.stdout.read().decode(errors='replace')); raw.close(); sel.close()
    emit('Result: '+('READY; stopped completely' if ready else 'NOT READY; exit '+str(code)))
    return ready
key=state/'userdata/secrets/server-signing-key.bin'
launch('01-initial-start')
original=key.read_bytes(); emit('Generated signing-key file: '+str(len(original))+' bytes')
launch('02-intact-restart')
emit('Existing non-empty signing key unchanged: '+str(original==key.read_bytes()).lower())
key.write_bytes(b''); emit('\n$ truncate signing-key file to zero bytes (server stopped)')
emit('Signing-key file before restart: '+str(key.stat().st_size)+' bytes')
launch('03-empty-restart')
emit('Signing-key file after restart: '+str(key.stat().st_size)+' bytes')
if key.stat().st_size: emit('Replacement differs from original: '+str(original!=key.read_bytes()).lower())
(out/'transcript.txt').write_text('\n'.join(e[1] for e in events)+'\n')
(out/'events.json').write_text(json.dumps(events))
print('EVIDENCE_DIRECTORY='+str(out))
