from PIL import Image,ImageDraw,ImageFont
from pathlib import Path
import json
ROOT=Path('/tmp/lead-25709-r1b/evidence-capture');out=ROOT/'sheets';out.mkdir(exist_ok=True)
font=ImageFont.truetype('/usr/share/fonts/truetype/noto/NotoSans-Regular.ttf',19)
fontSmall=ImageFont.truetype('/usr/share/fonts/truetype/noto/NotoSans-Regular.ttf',16)
runs=[ROOT/'2026-10-27T07-37-30-138Z-base-baseline',ROOT/'2026-10-27T07-37-31-442Z-after-off-baseline',ROOT/'2026-10-27T07-39-00-893Z-after-on-feature',ROOT/'2026-10-27T07-40-16-701Z-after-on-feature']
runs+=list(ROOT.glob('*-base-baseline-extra'));files=[p for r in runs for p in r.glob('*.png')]
groups={
'01-before-and-flag-off':[p for p in files if p.parent in runs[:2] or 'base-baseline-extra' in str(p.parent)],
'02-navigation-and-empty':[p for p in files if p.stem.startswith(('R1-','R2-','R3-'))],
'03-providers-and-long-data':[p for p in files if p.stem.startswith(('R4-','R5-','R6-'))],
'04-add-and-validation':[p for p in files if p.stem.startswith(('R7-','R8-','R9-'))],
'05-edit-remove-and-scope':[p for p in files if p.stem.startswith(('R10-','R11-','R12-'))],
'06-diffs':list((ROOT/'diffs').glob('*.png'))}
# Discover later permission/scope run folders, only finalized selected images.
for r in ROOT.glob('*-after-on-*'):
 if r in runs or r.name=='2026-10-27T07-50-00-080Z-after-on-restricted':continue
 for p in r.glob('*.png'):
  if p.stem.startswith(('R5-','R6-')) and ('long-repeat' in r.name or 'restricted' in r.name):groups['03-providers-and-long-data'].append(p)
  if p.stem.startswith('R12-'):groups['05-edit-remove-and-scope'].append(p)
manifest={}
for group,items in groups.items():
 items=sorted(items,key=lambda p:(p.stem,str(p.parent)))
 if not items:continue
 # 6 captures max per sheet to preserve readable image sizes.
 for start in range(0,len(items),6):
  chunk=items[start:start+6];w=1520;cellh=540;h=60+cellh*((len(chunk)+1)//2)
  sheet=Image.new('RGB',(w,h),'#e6e6e6');d=ImageDraw.Draw(sheet);d.text((18,15),group+' — '+str(start//6+1),font=font,fill='black')
  for i,p in enumerate(chunk):
   x=(i%2)*760;y=60+(i//2)*cellh;im=Image.open(p).convert('RGB');im.thumbnail((744,490));
   side='Before a9b513b50c' if 'base-baseline' in str(p.parent) else 'After ee9754767f (flag off)' if 'after-off' in str(p.parent) else 'Diff' if p.parent.name=='diffs' else 'After ee9754767f (flag on)'
   d.text((x+8,y+4),side+' · '+p.stem,font=fontSmall,fill='black');sheet.paste(im,(x+8+(744-im.width)//2,y+32));
  dest=out/(group+'-'+str(start//6+1)+'.png');sheet.save(dest);manifest[str(dest)]=[str(p) for p in chunk]
(out/'sheet-index.json').write_text(json.dumps(manifest,indent=2))
print('\n'.join(manifest))
# Compact before/after proof for embedding directly in the PR body.
pairs=[('Sidebar',ROOT/'2026-10-27T07-37-30-138Z-base-baseline/sidebar-W-L.png',ROOT/'2026-10-27T07-39-00-893Z-after-on-feature/R1-sidebar-W-L.png'),('Settings search: 1password',ROOT/'2026-10-27T07-37-30-138Z-base-baseline/search-W-L.png',ROOT/'2026-10-27T07-39-00-893Z-after-on-feature/R1-search-W-L.png'),('Direct /settings/secrets',ROOT/'2026-10-27T07-37-30-138Z-base-baseline/route-W-L.png',ROOT/'2026-10-27T07-39-00-893Z-after-on-feature/R3-empty-W-L.png')]
sheet=Image.new('RGB',(1520,1680),'#e6e6e6');d=ImageDraw.Draw(sheet);d.text((18,15),'Before a9b513b50c | After ee9754767f (Secrets flag on) — 1440×900 light',font=font,fill='black')
for row,(title,before,after)in enumerate(pairs):
 for col,p in enumerate([before,after]):
  x=col*760;y=60+row*540;d.text((x+8,y+4),('Before · 'if col==0 else 'After · ')+title,font=fontSmall,fill='black');im=Image.open(p).convert('RGB');im.thumbnail((744,490));sheet.paste(im,(x+8,y+32))
dest=out/'before-after-secrets-page.png';sheet.save(dest);manifest[str(dest)]=[str(p)for _,a,b in pairs for p in [a,b]];(out/'sheet-index.json').write_text(json.dumps(manifest,indent=2));print(dest)
