"""Run on the app's Xvfb display. Arguments: output-directory, side-label.
Requires the real desktop app at (0,0), size 1600x1000, demo page in right panel.
No CDP or other browser automation attaches during any input.
"""
import os,sys,time,subprocess,pathlib,hashlib,json
out=pathlib.Path(sys.argv[1])/time.strftime('%Y%m%d-%H%M%S');out.mkdir(parents=True)
side=sys.argv[2]
def run(*args):return subprocess.run(args,check=True,stdout=subprocess.PIPE).stdout
def click(x,y):run('xdotool','mousemove',str(x),str(y),'click','1');time.sleep(1)
def key(k):run('xdotool','key',k);time.sleep(0.8)
def capture(label):
 # Move away so hover styling does not obscure the result.
 run('xdotool','mousemove','1000','700')
 a=out/(label+'-stable-a.png');b=out/(label+'-stable-b.png')
 for _ in range(6):
  run('import','-window','root','-crop','1600x1000+0+0',str(a));time.sleep(.5)
  run('import','-window','root','-crop','1600x1000+0+0',str(b))
  # Compare decoded pixels, not PNG metadata.
  same=subprocess.run(['compare','-metric','AE',str(a),str(b),'null:'],capture_output=True).returncode==0
  if same:break
 if not same:raise RuntimeError('Capture did not settle: '+label)
 run('convert',str(b),'-crop','540x600+1060+0','+repage',str(out/(label+'.png')))
 print(json.dumps({'side':side,'capture':label,'stable':same}),flush=True)
log=open(out/'ffmpeg.log','w')
rec=subprocess.Popen(['ffmpeg','-y','-f','x11grab','-draw_mouse','1','-framerate','20','-video_size','1600x1000','-i',os.environ['DISPLAY']+'+0,0','-c:v','libx264','-preset','ultrafast','-crf','20','-pix_fmt','yuv420p',str(out/(side+'.mp4'))],stdin=subprocess.PIPE,stdout=log,stderr=log)
try:
 time.sleep(1)
 click(900,700);click(1133,54);time.sleep(1)
 click(1580,54);capture('01-reload-menu-open')
 click(1210,291);capture('02-reload-page-click')
 click(900,700)
 click(1210,291) # A prior page click before opening the menu again.
 click(1580,54);capture('03-prior-click-menu-open')
 click(1210,291);capture('04-prior-click-page-click')
 click(900,700)
 click(1580,54);key('Escape');key('space');capture('05-keyboard-menu-open')
 click(1210,291);capture('06-keyboard-page-click')
 time.sleep(2)
finally:
 rec.communicate(b'q\n',timeout=20);log.close()
print(str(out),flush=True)
