#!/usr/bin/env python3
"""Drive isolated real apps through agent-browser. Never upload private runtime logs."""
import sys, subprocess, json, re, time
from pathlib import Path
from datetime import datetime, timezone
from PIL import Image, ImageChops
ROOT=Path('/tmp/issue-lead-33252-r2/evidence-capture')
SESSION='evidence-33252-416bebe89473'
PORT={'after':6483,'before':8599}
for side in PORT:
    marker=ROOT/(side+'-location.txt')
    if marker.exists():
        server_log=Path(marker.read_text().strip())/'server.private.log'
        match=re.search(r'webPort=(\d+)',server_log.read_text())
        if match: PORT[side]=int(match[1])
HOST={'after':'localhost','before':'localhost'}

def ab(*args, check=True):
    p=subprocess.run(['/home/ubuntu/.npm/_npx/6de2aa2fded2970c/node_modules/agent-browser/bin/agent-browser-linux-x64','--session',SESSION,'--json',*map(str,args)],capture_output=True,text=True)
    if check and p.returncode: raise RuntimeError(p.stderr+p.stdout)
    try: return json.loads(p.stdout)
    except ValueError: return {'output':p.stdout,'error':p.stderr}

def js(expression):
    import base64
    r=ab('eval','-b',base64.b64encode(expression.encode()).decode())
    if not r.get('success',True): raise RuntimeError(str(r))
    return r.get('data',{}).get('result',r)

def screenshot(path):
    endpoint=ab('get','cdp-url')['data']['cdpUrl']
    subprocess.run(['node',str(ROOT/'full-screenshot.mjs'),endpoint,str(path)],check=True)

def settled(path):
    ab('mouse','move',0,0)
    ab('mouse','down','left');ab('mouse','up','left')
    js("document.activeElement instanceof HTMLElement && document.activeElement.blur()")
    js("document.fonts.ready.then(()=>true)")
    ab('wait','--load','networkidle')
    a=path.with_name(path.stem+'-stability-a.png')
    b=path.with_name(path.stem+'-stability-b.png')
    for attempt in range(5):
        screenshot(a)
        time.sleep(.5)
        screenshot(b)
        if ImageChops.difference(Image.open(a).convert('RGB'),Image.open(b).convert('RGB')).getbbox() is None:
            path.write_bytes(b.read_bytes()); return
    raise RuntimeError('Frames failed pixel-identical stability: '+str(path))

def prepare(side,width,theme):
    height=900 if width==1440 else 844
    ab('set','viewport',width,height,1)
    ab('set','media',theme,'reduced-motion')
    ab('open',f'http://{HOST[side]}:{PORT[side]}/welcome')
    ab('wait','--text','Connect your computers')
    js("document.querySelector('button[aria-label=\"Toggle main sidebar\"]')?.getAttribute('aria-pressed')==='true' && document.querySelector('button[aria-label=\"Toggle main sidebar\"]').click()")
    ab('find','role','button','click','--name','Continue','--exact')
    ab('wait','--text','Connect your agents')
    ab('mouse','move',0,0)
    ab('mouse','down','left');ab('mouse','up','left')
    js("document.activeElement instanceof HTMLElement && document.activeElement.blur()")
    return height

if __name__=='__main__':
    mode=sys.argv[1]
    if mode=='pair':
        side=sys.argv[2]
        text=Path(sys.argv[3]).read_text()
        ab('cookies','clear')
        url=re.search(r'http://(?:localhost|127\.0\.0\.1):\d+/pair#token=[A-Z0-9]+',text)[0]
        ab('open',f'http://{HOST[side]}:{PORT[side]}/pair')
        ab('wait','--text','Pairing token')
        token=url.split('token=')[1]
        js("(async()=>{const {submitServerAuthCredential}=await import('/src/environments/primary/auth.ts');await submitServerAuthCredential("+json.dumps(token)+");return true})()")
        ab('open',f'http://{HOST[side]}:{PORT[side]}/welcome')
        ab('wait','--text','Connect your computers')
        print('Paired '+side+' (credential omitted)')
    elif mode=='provider':
        side=sys.argv[2]
        ab('open',f'http://{HOST[side]}:{PORT[side]}/settings/providers')
        ab('wait','--text','Add provider')
        ab('find','role','button','click','--name','Add provider','--exact')
        ab('find','role','radio','click','--name','Pi','--exact')
        ab('find','role','button','click','--name','Next','--exact')
        ab('wait','--text','Instance ID')
        ab('find','role','button','click','--name','Next','--exact')
        ab('wait','--fn',"Array.from(document.querySelectorAll('button')).some(b=>b.textContent.trim()==='Add instance')")
        ab('find','role','button','click','--name','Add instance','--exact')
        ab('wait','--fn',"!Array.from(document.querySelectorAll('button')).some(b=>b.textContent.trim()==='Add instance')")
        print('Added synthetic Pi instance')
    elif mode=='capture':
        side,width,theme,row=sys.argv[2],int(sys.argv[3]),sys.argv[4],sys.argv[5]
        run=ROOT/(datetime.now(timezone.utc).strftime('run-%Y%m%dT%H%M%SZ')+'-'+side+'-'+row+'-'+str(width)+'-'+theme)
        run.mkdir()
        height=prepare(side,width,theme)
        if row=='LP':
            js("window.evidence.holdScan=true")
            ab('record','start',run/'L.webm','--fps','30')
            # The browser clock remains frozen; performance.now measures recording steps.
            js("""(()=>{const e=window.evidence;e.start=performance.now();e.timeline=[];
              setTimeout(()=>{e.timeline.push({event:'Continue from Agents',ms:performance.now()-e.start});Array.from(document.querySelectorAll('button')).find(b=>b.textContent.trim()==='Continue').click()},1000);
              setTimeout(()=>{e.timeline.push({event:'release gate',ms:performance.now()-e.start});e.release()},6000);
              return true})()""")
            ab('wait','--text','Looking for projects')
            # Additional loading endpoint for paired pixel diffs; recording is the primary L proof.
            settled(run/'L-loading.png')
            ab('wait','--text','Import your projects')
            ab('wait','--text','1 of 1 selected')
            time.sleep(2)
            ab('record','stop')
            settled(run/'P.png')
            timeline=js('window.evidence.timeline')
            (run/'timeline.json').write_text(json.dumps(timeline,indent=2))
        elif row=='E':
            ab('find','role','button','click','--name','Continue','--exact')
            ab('wait','--text','Import your projects')
            ab('wait','--text','Import 0 projects')
            settled(run/'E.png')
        environment=js("({browser:navigator.userAgent,deviceEmulation:false,dpr:devicePixelRatio,fontScaling:getComputedStyle(document.documentElement).fontSize,viewport:[innerWidth,innerHeight],reducedMotion:matchMedia('(prefers-reduced-motion: reduce)').matches,theme:matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light',clock:new Date().toISOString()})")
        (run/'environment.json').write_text(json.dumps(environment,indent=2))
        print(run)
