from pathlib import Path
from collections import Counter
from pptx import Presentation
from PIL import Image,ImageDraw
import json,re,subprocess,sys,xml.etree.ElementTree as ET,hashlib
R=Path(__file__).parent;scenes=sys.argv[1:] or ['enterprise','university','k12','hospital','eldercare'];allresults=[]
for scene in scenes:
 d=R/'deliverables'/scene;q=d/'qa';q.mkdir(exist_ok=True);data=json.loads((R/scene/'slides.json').read_text());n=len(data['slides']);p=d/(data['name']+'.pptx');pdf=p.with_suffix('.pdf');prs=Presentation(p)
 assert len(prs.slides)==n
 layout=json.loads((d/'rendered-layout.json').read_text());txt=subprocess.check_output(['pdftotext',str(pdf),'-']).decode();pages=txt.split('\f')[:n];assert len(pages)==n
 result={'scene':scene,'pages':n,'reserved':[],'editable_text_shapes':0,'font_check':'pending','visual_qa':'pending','warnings':[]}
 norm=lambda t:re.sub(r'\s+','',t)
 for i,(r,sl,t) in enumerate(zip(layout,prs.slides,pages),1):
  assert norm(r['title']) in norm(t),(scene,i,'title missing')
  if r.get('message'):assert norm(r['message']) in norm(t),(scene,i,'conclusion missing')
  assert sl.has_notes_slide and '来源' in sl.notes_slide.notes_text_frame.text,(scene,i,'notes missing')
  count=sum(sh.has_text_frame and bool(sh.text.strip()) for sh in sl.shapes);result['editable_text_shapes']+=count
  if data['slides'][i-1]['layout']=='reserved':result['reserved'].append(i);assert count==3
  expected=''.join(x['text'] for x in r['text']);miss=Counter(norm(expected))-Counter(norm(t))
  if miss:result['warnings'].append({'page':i,'missing_native_glyphs':dict(miss)})
  for x in r['text']:
   assert x['x']>=0 and x['y']>=0 and x['x']+x['w']<=13.335 and x['y']+x['h']<=7.501,(scene,i,'textbox out of canvas',x)
 assert result['reserved']==[2,3,4,n-1,n],result['reserved']
 fonts=subprocess.check_output(['pdffonts',str(pdf)]).decode();assert 'MicrosoftYaHei' in fonts;assert 'Arial' in fonts;assert 'FrankRuhl' not in fonts
 result['font_check']='微软雅黑/Arial embedded'
 root=ET.fromstring(subprocess.check_output(['pdftotext','-bbox',str(pdf),'-']));ns={'x':'http://www.w3.org/1999/xhtml'}
 for i,pg in enumerate(root.findall('.//x:page',ns),1):
  for w in pg.findall('x:word',ns):
   assert float(w.attrib['xMin'])>=-1 and float(w.attrib['yMin'])>=-1
   assert float(w.attrib['xMax'])<=float(pg.attrib['width'])+1 and float(w.attrib['yMax'])<=float(pg.attrib['height'])+1,(scene,i,w.text)
 files=sorted(q.glob('page-*.jpg'));assert len(files)==n,(scene,'previews missing')
 for off in range(0,n,12):
  subset=files[off:off+12];sheet=Image.new('RGB',(1600,((len(subset)+2)//3)*320),'#e5e5e5');dr=ImageDraw.Draw(sheet)
  for j,f in enumerate(subset):
   im=Image.open(f);im.thumbnail((520,293));x=j%3*533+6;y=j//3*320;sheet.paste(im,(x,y));dr.text((x+8,y+298),f'{scene} {f.stem}',fill='black')
  sheet.save(q/f'contact-{off//12+1}.jpg')
 result['files']=[{'filename':f.name,'bytes':f.stat().st_size,'sha256':hashlib.sha256(f.read_bytes()).hexdigest()} for f in [p,pdf]]
 (q/'pdf-text.txt').write_text(txt);(R/scene/'validation.json').write_text(json.dumps(result,ensure_ascii=False,indent=2));allresults.append(result)
 print(json.dumps({k:v for k,v in result.items() if k!='files'},ensure_ascii=False))
