#!/usr/bin/env python3
"""Public UI reproduction driver. Requires a paired, isolated T3 dev server.

Run each revision as a real app, never swap helper outputs into another build:
  git switch --detach <revision>
  vp run dev --no-seed --home-dir /tmp/ev-24611/<revision>
Launch headed Chromium on Xvfb with CDP 19246 and a task-owned profile.
Pair manually with that server's startup token (never publish the token).
The app auto-creates an empty server project/thread on this VM.
Run configure, send, then plan; stop server before changing revision.
Use a fresh isolated server home for each revision. No live userdata access.

Browser for this round: Chrome 156 headless Linux, actual independently running apps.
This reproduction recipe adapts the earlier driver. This round acquired seed state
through the built-in preview UI, not by executing this script end to end. Use
capture-real.py for the executed capture driver and provenance.json for actual sends.
Provider: actual installed Codex gpt-6.1-sol, low effort, full-access mode.
The custom unavailable text-generation model is intentional: title generation
fails and leaves the client-produced title seed visible. Turn provider works.
All input and mutations use the app UI; eval only reads DOM or blurs focus.
"""
import argparse
import json
import subprocess
from pathlib import Path

P = argparse.ArgumentParser()
P.add_argument('action', choices=['configure','send','plan','stills','probe'])
P.add_argument('--session', default='ev24611')
P.add_argument('--cdp', default='19246')
P.add_argument('--out', default='/tmp/ev-24611')
P.add_argument('--label', default='reproduced')
A = P.parse_args()
OUT = Path(A.out)
OUT.mkdir(parents=True, exist_ok=True)
PREFIX = ['npx','--yes','agent-browser','--session',A.session] # Already open and paired to the isolated app.
Z = '\u200b'
T50 = 'Text '+Z*44+'😀 tail'
E50 = 'Keep '+Z*43+'😀 tail'
SHORT = '  short 😀  '
PLAN_MARKDOWN = '# Plan '+Z*34+'😀 tail\n\nReply OK.'
PLAN = ('Evidence-only UI fixture. Do not inspect files, use tools, change files or execute anything. '
        'Return exactly this proposed plan in a native proposed_plan block. Preserve all zero-width spaces in its heading:\n'
        '<proposed_plan>\n'+PLAN_MARKDOWN+'\n</proposed_plan>')

def ab(*args):
    result = subprocess.run(PREFIX+list(args), text=True, capture_output=True)
    with (OUT/'driver-transcript.txt').open('a') as f:
        f.write(json.dumps(list(args),ensure_ascii=True)+'\n'+result.stdout+result.stderr+'\n')
    if result.returncode or result.stdout.startswith('✗') or result.stderr.startswith('✗'):
        raise RuntimeError(result.stdout+result.stderr)
    return result.stdout

def click(role,name):
    return ab('find','role',role,'click','--name',name,'--exact')

def fill(name,value):
    return ab('find','role','textbox','fill','--name',name,value,'--exact')

def mode(enabled):
    snapshot=ab('snapshot','-i')
    if 'Plan mode (legacy)' not in snapshot:
        click('button','Legacy features')
        snapshot=ab('snapshot','-i')
    expected='switch "Plan mode (legacy)" [checked='+str(enabled).lower()
    if expected not in snapshot:
        click('switch','Plan mode (legacy)')

def settle():
    ab('wait','--fn','!Array.from(document.querySelectorAll("button")).some(b=>b.getAttribute("aria-label")==="Stop generation") && Array.from(document.querySelectorAll("p")).some(p=>p.textContent==="OK")')

def stills():
    ab('eval','document.activeElement?.blur()')
    ab('screenshot',str(OUT/(A.label+'.png')))
    ab('screenshot',str(OUT/(A.label+'-settled.png')))
    (OUT/(A.label+'-dom.json')).write_text(ab('eval','JSON.stringify({h2:[...document.querySelectorAll("h2")].map(x=>x.textContent),paragraphs:[...document.querySelectorAll("p")].map(x=>x.textContent),viewport:[innerWidth,innerHeight],dpr:devicePixelRatio,userAgent:navigator.userAgent})'))

if A.action=='configure':
    ab('set','viewport','1440','1000')
    click('button','Settings')
    click('button','Providers')
    click('button','Add custom model')
    fill('gpt-6.7-codex-ultra-preview','evidence-title-unavailable')
    click('button','Add')
    click('button','General')
    click('button','GPT-6-Luna')
    click('option','evidence-title-unavailable Codex Add to favorites')
    mode(True)
    click('button','Back')
    snapshot=ab('snapshot','-i')
    if 'button "GPT-6-Astra"' in snapshot:
        click('button','GPT-6-Astra')
        click('option','GPT-6.1-Sol Codex Add to favorites')
elif A.action=='send':
    for text in [T50,E50,SHORT]:
        if 'textbox \"Message New thread\"' not in ab('snapshot','-i'):
            click('button','New thread')
        fill('Message New thread',text)
        click('button','Submit message')
        ab('wait','--fn','!Array.from(document.querySelectorAll("button")).some(b => b.getAttribute("aria-label") === "Stop generation")')
        input('Wait for the actual run and unavailable title-generation attempt to complete, then Enter: ')
elif A.action=='plan':
    click('button','Settings')
    mode(True)
    click('button','Back')
    click('button','New thread')
    if 'Default mode. Click to enter plan mode' in ab('snapshot','-i'):
        click('button','Default mode. Click to enter plan mode')
    fill('Message New thread',PLAN)
    click('button','Submit message')
    ab('wait','--fn','Array.from(document.querySelectorAll("button")).some(b=>b.textContent==="Implement")')
    heading='Plan '+Z*34+'😀 tail'
    ab('wait','--fn','Array.from(document.querySelectorAll("h3")).some(h=>h.textContent==='+json.dumps(heading)+')')
    ab('eval','document.activeElement?.blur()')
    ab('screenshot',str(OUT/(A.label+'-source.png')))
    click('button','Implementation actions')
    click('menuitem','Implement in a new thread')
    settle()
    stills()
elif A.action=='stills':
    settle()
    stills()
else:
    print(ab('eval','JSON.stringify({h2:[...document.querySelectorAll("h2")].map(x=>x.textContent),paragraphs:[...document.querySelectorAll("p")].map(x=>x.textContent),viewport:[innerWidth,innerHeight],dpr:devicePixelRatio,userAgent:navigator.userAgent})'))
