"""Capture actual CLI startup on two checkouts; no tests or mocked services.
Usage: python3 prove-startup.py BASE_CHECKOUT HEAD_CHECKOUT OUTPUT_DIRECTORY
All data is synthetic. Published transcripts replace absolute paths with placeholders.
"""
import datetime
import os
from pathlib import Path
import re
import selectors
import signal
import subprocess
import sys
import time

base, head, output = map(Path, sys.argv[1:])
run = output / datetime.datetime.now(datetime.timezone.utc).strftime('run-%Y%m%dT%H%M%SZ')
run.mkdir(parents=True)
home = run / 'isolated-home'
home.mkdir()
env = {'PATH': os.environ['PATH'], 'HOME': str(home), 'T3CODE_DEV_SEED': '0', 'NO_COLOR': '1', 'TERM': 'dumb'}

def capture(checkout, side, case, data):
    raw = run / f'{side}-{case}.raw.log'
    command = ['node', 'src/bin.ts', 'serve', '--base-dir', str(data), '--port', '47961', '--host', '127.0.0.1']
    proc = subprocess.Popen(command, cwd=checkout / 'apps/server', env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, start_new_session=True)
    selector = selectors.DefaultSelector()
    selector.register(proc.stdout, selectors.EVENT_READ)
    content = b''
    ready = False
    deadline = time.monotonic() + 90
    try:
        while time.monotonic() < deadline:
            for key, _ in selector.select(0.25):
                chunk = os.read(key.fileobj.fileno(), 65536)
                content += chunk
                if not chunk:
                    break
            if b'T3 Code server is ready' in content:
                ready = True
                break
            if proc.poll() is not None:
                content += proc.stdout.read()
                break
    finally:
        if proc.poll() is None:
            os.killpg(proc.pid, signal.SIGTERM)
            try:
                tail, _ = proc.communicate(timeout=15)
            except subprocess.TimeoutExpired:
                os.killpg(proc.pid, signal.SIGKILL)
                tail, _ = proc.communicate()
            content += tail
        selector.close()
    raw.write_bytes(content)
    text = content.decode(errors='replace')
    text = re.sub(r'\x1b\[[0-9;]*m', '', text)
    text = text.replace(str(data), '<data-dir>').replace(str(checkout), '<checkout>').replace(str(home), '<isolated-home>')
    text = text.replace(str(run), '<evidence-dir>')
    text = re.sub(r'Connection string:.*?(?=\[|\Z)', '[Pairing details and QR code redacted]\n', text, flags=re.S)
    text = re.sub(r'https?://\S+', '<URL redacted>', text)
    sha = subprocess.check_output(['git', 'rev-parse', 'HEAD'], cwd=checkout, text=True).strip()
    header = f'{side.upper()} | {case} | commit {sha}\nLinux x86_64 | Node {subprocess.check_output(["node", "--version"], text=True).strip()} | real server CLI\nT3CODE_DEV_SEED=0; isolated HOME; synthetic data only\nAbsolute paths shown as placeholders; pairing URLs redacted.\n\n$ T3CODE_DEV_SEED=0 node src/bin.ts serve --base-dir <data-dir> --port 47961 --host 127.0.0.1\n'
    footer = f'\nObserved: ready={ready}; ' + ('server stopped by capture driver after readiness' if ready else f'exit code={proc.returncode}') + '\n'
    (run / f'{side}-{case}.txt').write_text(header + text + footer)
    print(f'{side} {case}: ready={ready}, exit={proc.returncode}', flush=True)
    return ready

for checkout, side in [(base, 'before'), (head, 'after')]:
    healthy = run / side / 'healthy'
    healthy.mkdir(parents=True)
    capture(checkout, side, 'healthy', healthy)
    damaged = run / side / 'damaged'
    (damaged / 'userdata').mkdir(parents=True)
    db = damaged / 'userdata/statev2.sqlite'
    db.write_bytes(b'not a db\n')
    capture(checkout, side, 'damaged', damaged)
    # Follow exactly the recovery advice: retain the damaged files outside userdata.
    backup = damaged / 'retained-damaged-files'
    backup.mkdir()
    for name in ['statev2.sqlite', 'statev2.sqlite-wal', 'statev2.sqlite-shm']:
        path = damaged / 'userdata' / name
        if path.exists():
            path.rename(backup / name)
    capture(checkout, side, 'recovered', damaged)
print(run, flush=True)
