import subprocess,json,sys,pathlib,time,urllib.request,datetime,os
ROOT=pathlib.Path('/tmp/issue-lead-27024-r1/capture-2')
side,action,*args=sys.argv[1:]
session=os.environ.get('CAPTURE_BROWSER_SESSION','issue-27024-round2-software-'+side)
worktree='/home/ubuntu/wt/issue-27024-'+side
port=7509 if side=='before' else 7128
origin=f'http://localhost:{port}'
run=ROOT/'runs'/(datetime.datetime.now(datetime.timezone.utc).isoformat().replace(':','-')+'-'+side+'-'+action)
run.mkdir(parents=True)
steps=[]
def b(*a):
    t=time.monotonic();p=subprocess.run(['/home/ubuntu/.npm/_npx/6de2aa2fded2970c/node_modules/agent-browser/bin/agent-browser-linux-x64','--args','--disable-gpu,--disable-gpu-compositing','--session',session,'--json',*a],text=True,capture_output=True,cwd=worktree)
    steps.append({'seconds':round(time.monotonic()-started,3),'command':a[0], 'detail':list(a[1:]) if a[0]!='eval' else '[evaluated driver JS]', 'exit':p.returncode})
    if p.returncode: raise RuntimeError(p.stdout+p.stderr)
    try:return json.loads(p.stdout)
    except: return {'raw':p.stdout}
def value(v):return v.get('data',{}).get('result',v.get('data',v))
def ev(s):return value(b('eval',s))
def screenshot(path):
    b('wait','--load','networkidle');ev('document.fonts.ready.then(()=>document.fonts.status)')
    p=pathlib.Path(path);a=run/(p.stem+'-settle-a.png');z=run/(p.stem+'-settle-b.png')
    for attempt in range(6):
        b('screenshot',str(a));time.sleep(.5);b('screenshot',str(z))
        r=subprocess.run(['compare','-metric','AE',str(a),str(z),'null:'],capture_output=True,text=True)
        if r.stderr.strip()=='0':p.write_bytes(z.read_bytes());return
        time.sleep(.5)
    raise RuntimeError('frames did not settle: '+r.stderr)
started=time.monotonic()
try:
 if action=='auth':
    token=(ROOT/f'auth-{side}.private').read_text().strip().splitlines()[-1]
    req=urllib.request.Request(origin+'/api/auth/pairing-token',data=b'{}',headers={'Authorization':'Bearer '+token,'Content-Type':'application/json'},method='POST')
    pair=json.load(urllib.request.urlopen(req))
    b('open',origin)
    ev('(async()=>{const r=await fetch("/api/auth/browser-session",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({credential:'+json.dumps(pair['credential'])+'})});return r.status})()')
    ev("(async()=>{const m=await import('/src/hooks/useSettings.ts');await m.updateClientSettings({glassOpacity:100});return m.getClientSettings().glassOpacity})()")
    descriptor=json.load(urllib.request.urlopen(origin+'/.well-known/t3/environment'))
    b('set','viewport','1440','900','1');b('set','media','dark','reduced-motion')
    b('open',origin+'/'+descriptor['environmentId']+'/evidence-parent')
    print(json.dumps({'environmentId':descriptor['environmentId']}))
 elif action=='eval':print(json.dumps(ev(pathlib.Path(args[0]).read_text())))
 elif action=='shot':
    ev((ROOT/'freeze-clock.js').read_text());ev("document.activeElement?.blur()");screenshot(ROOT/args[0]);print(args[0])
 elif action=='r1':
    ev((ROOT/'freeze-clock.js').read_text());ev("document.activeElement?.blur();document.querySelector('.messages-timeline-scroll').scrollTop=0")
    b('record','start',str(ROOT/f'r1-web-{side}-disclosure.mp4'),'--fps','15')
    time.sleep(2)
    screenshot(ROOT/f'r1-web-{side}-collapsed.png')
    labels=ev("[...document.querySelectorAll('button')].map(e=>e.textContent.trim()).filter(t=>t.startsWith('Worked for'))")
    label=labels[1]
    b('find','role','button','click','--name',label);time.sleep(2)
    ev("document.querySelector('.messages-timeline-scroll').scrollTop=0")
    screenshot(ROOT/f'r1-web-{side}-expanded.png')
    b('find','role','button','click','--name',label);time.sleep(1)
    b('reload');b('wait','--text','LISTED');ev((ROOT/'freeze-clock.js').read_text())
    ev("document.activeElement?.blur();document.querySelector('.messages-timeline-scroll').scrollTop=0");time.sleep(2)
    b('find','role','button','click','--name',label);time.sleep(2)
    b('find','role','button','click','--name',label);time.sleep(2)
    b('record','stop')
    print(json.dumps({'label':label,'steps':steps}))
 elif action=='harness':
    row=args[0];theme='light' if row=='R7' else 'dark';width=390 if row=='R7' else 1440;height=844 if row=='R7' else 900
    b('set','viewport',str(width),str(height),'1');b('set','media',theme,'reduced-motion')
    env=json.load(urllib.request.urlopen(origin+'/.well-known/t3/environment'))['environmentId']
    b('open',origin+'/'+env+'/evidence-parent?evidence='+row)
    b('wait','--text','HARNESS '+row)
    if ev("Boolean(document.querySelector('[role=navigation][aria-label=Threads]'))"):b('find','role','button','click','--name','Toggle main sidebar')
    if ev("document.querySelector('[aria-label=\"Toggle thread details panel\"]')?.getAttribute('aria-pressed')==='true'"):b('find','role','button','click','--name','Toggle thread details panel')
    ev((ROOT/'freeze-clock.js').read_text().replace('2026-10-29T17:00:00.000Z','2026-10-09T10:02:40.000Z'))
    ev("document.activeElement?.blur();document.querySelector('.messages-timeline-scroll').scrollTop=0")
    b('record','start',str(ROOT/f'{row.lower()}-web-{side}.mp4'),'--fps','15');time.sleep(2)
    def cap(tag):
        ev("document.activeElement?.blur();document.querySelector('.messages-timeline-scroll').scrollTop=0")
        screenshot(ROOT/f'{row.lower()}-web-{side}-{tag}.png')
    def fold(prefix,n=0):
        labels=ev("[...document.querySelectorAll('button')].map(e=>e.textContent.trim()).filter(t=>t.startsWith("+json.dumps(prefix)+"))")
        b('find','role','button','click','--name',labels[n]);time.sleep(1)
    cap('collapsed')
    if row=='R1':
        b('find','role','button','click','--name','Resume child');time.sleep(1);cap('resumed-live')
        b('find','role','button','click','--name','Complete child and notify');time.sleep(1);cap('settled')
        fold('Worked for');cap('settled-expanded');fold('Worked for');cap('recollapsed')
        b('reload');b('wait','--text','HARNESS R1');time.sleep(1)
        if ev("Boolean(document.querySelector('[role=navigation][aria-label=Threads]'))"):b('find','role','button','click','--name','Toggle main sidebar')
        if ev("document.querySelector('[aria-label=\"Toggle thread details panel\"]')?.getAttribute('aria-pressed')==='true'"):b('find','role','button','click','--name','Toggle thread details panel')
        b('find','role','button','click','--name','Resume child');b('find','role','button','click','--name','Complete child and notify');time.sleep(1)
        cap('reloaded');fold('Worked for');cap('reloaded-expanded');fold('Worked for')
    elif row in ['R3','R6']:
        fold('Continued for');cap('continued-expanded');fold('Worked for');cap('both-expanded');fold('Continued for');fold('Worked for')
    else:
        fold('Worked for');cap('expanded');fold('Worked for')
    if row=='R2':
        b('find','role','button','click','--name','2 subagents');time.sleep(1);cap('live-batch-open');b('find','role','button','click','--name','2 subagents')
    if row in ['R2','R4']:
        b('find','role','button','click','--name','Settle final child' if row=='R2' else 'Swap trailing work order');time.sleep(2)
        cap('settled' if row=='R2' else 'reverse-order')
        fold('Worked for');cap('settled-expanded' if row=='R2' else 'reverse-expanded')
        if row=='R2':
            b('find','role','button','click','--name','2 subagents');time.sleep(1);cap('settled-batch-open');b('find','role','button','click','--name','Open Research the completed task');b('wait','--text','Harness child target');time.sleep(1);b('back');b('wait','--text','HARNESS R2');time.sleep(1)
        else:fold('Worked for')
    time.sleep(2);b('record','stop')
    print(json.dumps({'row':row,'steps':steps}))
 else: print(json.dumps(b(action,*args)))
finally:
 (run/'steps.json').write_text(json.dumps(steps,indent=2))
