"""Session61 solved-page black three/four-dot screen. No rune OCR.
Run beside retained JPEGs, typography_plan.json and three_dot_scan.py.
"""
from pathlib import Path
import json,hashlib
import numpy as np
from PIL import Image,ImageDraw,ImageFont
from three_dot_scan import groups
ROOT=Path(__file__).resolve().parent
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
def main():
 plan=json.loads((ROOT/'typography_plan.json').read_text());manifest=json.loads((ROOT/'jpeg_source_manifest.json').read_text());hashes={x['file']:x['sha256']for x in manifest['files']};records=[];cs=[]
 for n in plan['solved_archive_images']:
  f=ROOT/f'{n:02d}.jpg';assert sha(f)==hashes[f.name];im=Image.open(f).convert('RGB');mx=np.asarray(im).max(axis=2);runs=[]
  for th in plan['thresholds']:
   gs=groups(mx<th);runs.append({'threshold':th,'groups':gs})
   for g in gs:
    if g['dot_count']not in(3,4):continue
    found=[c for c in cs if c['source']==f.name and max(abs(a-b)for a,b in zip(c['bbox'],g['bbox']))<=6]
    if found:c=found[0]
    else:c={'source':f.name,'bbox':g['bbox'],'detections':[]};cs.append(c)
    c['detections'].append({'threshold':th,**g})
  records.append({'source':f.name,'sha256':sha(f),'runs':runs})
  print(f'{f.name}: complete',flush=True)
 cs.sort(key=lambda c:(c['source'],c['bbox'][1],c['bbox'][0]))
 for i,c in enumerate(cs,1):c['id']=i
 result={'plan_sha256':sha(ROOT/'typography_plan.json'),'pages':records,'candidates':cs,'candidate_count':len(cs)}
 (ROOT/'typography_screen_results.json').write_text(json.dumps(result,indent=2)+'\n')
 font=ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',16)
 for part in range((len(cs)+23)//24):
  items=cs[part*24:(part+1)*24];out=Image.new('RGB',(1200,((len(items)+3)//4)*285),'#eef1f5');dr=ImageDraw.Draw(out)
  for j,c in enumerate(items):
   x=j%4*300;y=j//4*285;b=c['bbox'];cx=(b[0]+b[2])//2;cy=(b[1]+b[3])//2;box=[cx-90,cy-67,cx+60,cy+67];c['crop_bbox']=box
   dr.text((x+8,y+8),f"{c['id']:02d} | {c['source']} | dots {sorted(set(d['dot_count']for d in c['detections']))}",font=font,fill='#142432');out.paste(Image.open(ROOT/c['source']).crop(box).resize((285,254),Image.Resampling.NEAREST),(x+7,y+30))
  out.save(ROOT/f'typography_screen_contact_{part+1:02d}.png')
 (ROOT/'typography_screen_results.json').write_text(json.dumps(result,indent=2)+'\n')
 print(json.dumps({'candidate_count':len(cs),'sheets':(len(cs)+23)//24,'plan_sha256':sha(ROOT/'typography_plan.json')}))
if __name__=='__main__':main()
