import subprocess,pathlib,json,time,datetime,sys,os
from PIL import Image,ImageChops
ROOT=pathlib.Path('/tmp/issue-lead-4812-r2/evidence-capture')
AB=str(ROOT/'browser-tools/node_modules/.bin/agent-browser')
OUT=ROOT/('run-'+datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%dT%H%M%SZ'))
OUT.mkdir()
print(OUT,flush=True)
def ab(side,*args,allow=False):
    p=subprocess.run([AB,'--session','issue4812-'+side,'--json',*map(str,args)],text=True,capture_output=True,timeout=40)
    try: result=json.loads(p.stdout)
    except: result={'raw':p.stdout,'stderr':p.stderr}
    if p.returncode and not allow: raise RuntimeError((side,args,result,p.stderr))
    return result

def value(side,js):
    r=ab(side,'eval',js)
    return r['data']['result']

def stable(side,name):
    ab(side,'wait','--load','networkidle')
    value(side,'document.fonts.ready.then(() => document.fonts.status)')
    for attempt in range(8):
        a=OUT/f'{name}-settle-{attempt}-a.png'; b=OUT/f'{name}-settle-{attempt}-b.png'
        ab(side,'screenshot',a)
        time.sleep(.5)
        ab(side,'screenshot',b)
        diff=ImageChops.difference(Image.open(a).convert('RGB'),Image.open(b).convert('RGB'))
        if diff.getbbox() is None:
            dest=OUT/f'{name}.png'; dest.write_bytes(b.read_bytes())
            return {'identical':True,'interval_ms':500,'attempt':attempt,'files':[a.name,b.name]}
    raise RuntimeError('frames did not settle '+name)

results=[]
for row in sys.argv[1:] or ['R1','R2']:
  for width,height in [(1440,900),(390,844)]:
    if os.environ.get('CAPTURE_WIDTH') and width != int(os.environ['CAPTURE_WIDTH']): continue
    for theme in ['light','dark']:
      if os.environ.get('CAPTURE_THEME') and theme != os.environ['CAPTURE_THEME']: continue
      for side,port in [('before',8386),('after',6471)]:
        name=f'{row}-{width}x{height}-{theme}-{side}'
        print('START',name,flush=True)
        ab(side,'set','viewport',1440,900,1)
        ab(side,'set','media',theme)
        value(side,f"""(() => {{localStorage.setItem('t3code:theme','{theme}');localStorage.setItem('t3code:theme-follow-system','false');localStorage.setItem('t3code:theme-appearance-mode','{theme}');return true;}})()""")
        ab(side,'open',f'http://localhost:{port}/#/')
        ab(side,'reload')
        ab(side,'set','media','reduced-motion')
        ab(side,'wait','--fn',"Array.from(document.querySelectorAll('button')).some(b => b.getAttribute('aria-label') === 'Add project')")
        ab(side,'find','role','button','click','--name','New thread','--exact')
        ab(side,'wait','--text','What should we build')
        if row=='R1':
          ab(side,'open',f'http://localhost:{port}/#/settings/about')
          ab(side,'wait','--text','Update available.')
        ab(side,'set','viewport',width,height,1)
        ab(side,'set','media','reduced-motion')
        if row=='R2' and width==390:
          ab(side,'find','role','button','click','--name','Toggle main sidebar','--exact')
        target='Download' if row=='R1' else 'Update 0.0.30-nightly.20260728.933 ready to download'
        ab(side,'wait','--fn',f'Array.from(document.querySelectorAll("button")).some(b => b.getAttribute("aria-label") === {json.dumps(target)} || b.textContent.trim() === {json.dumps(target)})')
        ab(side,'mouse','move',1,height-1)
        pre=stable(side,name+'-pre')
        snapshot=ab(side,'snapshot','-i');(OUT/f'{name}-snapshot.json').write_text(json.dumps(snapshot,indent=2))
        metadata=value(side,'''({width:innerWidth,height:innerHeight,dpr:devicePixelRatio,ua:navigator.userAgent,rootFontSize:getComputedStyle(document.documentElement).fontSize,theme:document.documentElement.className,reduced:matchMedia('(prefers-reduced-motion: reduce)').matches,clock:new Date().toISOString(),scroll:[scrollX,scrollY],calls:__capture.calls})''')
        ab(side,'record','start',OUT/f'{name}.webm','--fps','10')
        t0=time.monotonic();time.sleep(1)
        clickStart=time.monotonic()-t0
        ab(side,'find','role','button','click','--name',target,'--exact')
        clickEnd=time.monotonic()-t0
        ab(side,'mouse','move',1,height-1)
        ab(side,'wait','--fn','window.__capture.calls.length === 1')
        if side=='after' or row=='R2': ab(side,'wait','--text','Could not download update')
        post=stable(side,name)
        stillAt=time.monotonic()-t0
        data=value(side,'({calls:__capture.calls,state:__capture.getState(),text:document.body.innerText})')
        time.sleep(max(0,4-(time.monotonic()-t0)))
        duration=time.monotonic()-t0
        ab(side,'record','stop')
        result={'name':name,'row':row,'side':side,'viewport':[width,height],'theme':theme,'environment':metadata,'pre':pre,'post':post,'click_start':clickStart,'click_end':clickEnd,'still_at':stillAt,'duration':duration,'observed':data}
        results.append(result);(OUT/'results.json').write_text(json.dumps(results,indent=2))
        print('DONE',name,'click',round(clickStart,3),'still',round(stillAt,3),flush=True)
print('COMPLETE',OUT,flush=True)
