#!/usr/bin/env python3
"""Run from outside either checkout: python3 prove.py HEAD_CHECKOUT BASE_CHECKOUT OUTPUT_DIR.
Uses synthetic databases only; invokes the real CLI, never imports implementation code.
"""
import datetime, json, os, pathlib, re, socket, sqlite3, subprocess, sys, time
head, base, output = map(pathlib.Path, sys.argv[1:])
run = output / datetime.datetime.now(datetime.timezone.utc).strftime('run-%Y%m%d-%H%M%S')
run.mkdir(parents=True)
env = dict(os.environ, T3CODE_DEV_SEED='0', NO_COLOR='1')
results = {}
def backup(source, dest):
    with sqlite3.connect(source) as src, sqlite3.connect(dest) as dst: src.backup(dst)
def server(checkout, home, port):
    home.mkdir(parents=True, exist_ok=True)
    raw = home / 'private-startup.log'
    f = raw.open('w')
    p = subprocess.Popen(['node','apps/server/src/bin.ts','serve','--base-dir',str(home),'--host','127.0.0.1','--port',str(port),'--no-browser'], cwd=checkout, env=env, stdout=f, stderr=subprocess.STDOUT)
    listening = False
    try:
        for _ in range(240):
            if p.poll() is not None: break
            try:
                with socket.create_connection(('127.0.0.1',port), timeout=.1):
                    if f'Listening on http://127.0.0.1:{port}' in raw.read_text():
                        listening = True; break
                    time.sleep(.25)
            except OSError: time.sleep(.25)
    finally:
        if p.poll() is None:
            p.terminate()
            try: p.wait(timeout=15)
            except subprocess.TimeoutExpired: p.kill(); p.wait()
        f.close()
    text = raw.read_text()
    # Publish only migration diagnostics; startup logs also contain private pairing credentials.
    diagnostic = re.findall(r"This database's migration history would skip required schema migrations:[^\n]+",text)
    return {'listening':listening, 'exitCode':p.returncode, 'migrationDiagnostic':list(dict.fromkeys(diagnostic))}
for side, checkout, port in [('before',base,18474),('after',head,18475)]:
    folder = run / side; folder.mkdir()
    sha = subprocess.check_output(['git','rev-parse','HEAD'],cwd=checkout,text=True).strip()
    seeded = folder / 'fresh'
    created = server(checkout,seeded,port)
    if not created['listening']: raise RuntimeError('Fresh server failed: '+str(created))
    source = seeded / 'userdata/statev2.sqlite'
    report = [f'Side: {side}',f'Commit: {sha}','Environment: Linux x86_64; Node '+subprocess.check_output(['node','--version'],text=True).strip(), 'Surface: real T3 server CLI from source; isolated synthetic database; launcher protocol 4.', 'Fresh server: listening; stopped cleanly before SQLite backup.','']
    cases = {}
    for case in ['current','conflicting-name','missing-required','supported-upgrade']:
        home = folder / case; (home/'userdata').mkdir(parents=True)
        db = home/'userdata/statev2.sqlite'; backup(source,db)
        sql = None
        if case == 'conflicting-name': sql = "UPDATE effect_sql_migrations SET name = 'SomethingElse' WHERE migration_id = (SELECT max(migration_id) FROM effect_sql_migrations)"
        if case == 'missing-required': sql = 'DELETE FROM effect_sql_migrations WHERE migration_id = 81'
        if case == 'supported-upgrade': sql = 'DELETE FROM effect_sql_migrations WHERE migration_id = 82; DROP INDEX orchestration_v2_projection_turn_items_conversation_idx'
        if sql:
            with sqlite3.connect(db) as conn: conn.executescript(sql)
        with sqlite3.connect(db) as conn:
            rows = conn.execute('SELECT migration_id,name FROM effect_sql_migrations WHERE migration_id >= 80 ORDER BY migration_id').fetchall()
        before = db.read_bytes()
        cmd = ['node','apps/server/src/bin.ts','__service-preflight','--database-path',str(db),'--launcher-protocol','4']
        completed = subprocess.run(cmd,cwd=checkout,env=env,capture_output=True,text=True,timeout=60)
        response = json.loads(completed.stdout)
        unchanged = before == db.read_bytes()
        startup = server(checkout,home,port)
        with sqlite3.connect(db) as conn:
            final_head = conn.execute('SELECT max(migration_id) FROM effect_sql_migrations').fetchone()[0]
        report += [f'CASE: {case}', 'Mutation: '+(sql or '(none)'), 'Recorded tail: '+json.dumps(rows),'$ t3 __service-preflight --database-path <standalone-copy> --launcher-protocol 4',completed.stdout.strip(),f'CLI exit: {completed.returncode}; database byte-for-byte unchanged by preflight: {unchanged}', '$ t3 serve --base-dir <isolated-home> --host 127.0.0.1 --port <isolated-port> --no-browser', 'Startup: '+json.dumps(startup),f'Migration head after startup: {final_head}','']
        cases[case] = dict(preflight=response,startup=startup,unchanged=unchanged)
    transcript = '\n'.join(report)
    (run / f'{side}.txt').write_text(transcript)
    print(transcript,flush=True)
    results[side] = dict(sha=sha,cases=cases)
(run/'results.json').write_text(json.dumps(results,indent=2))
print('OUTPUT',run)
