#!/usr/bin/env python3
from __future__ import annotations
import json, re, shutil, subprocess, tempfile
from pathlib import Path
from PIL import Image, ImageStat
ROOT=Path(__file__).resolve().parents[1]
products=json.loads((ROOT/'data/kidz-products.json').read_text())
files=[]
for p in products:
    files.append((p['id'],'protected-a4',ROOT/p['internalMaster'],p['pageCount'],'A4'))
    letter=(ROOT/p['internalMaster']).with_name((ROOT/p['internalMaster']).name.replace('-a4.pdf','-us-letter.pdf'))
    if letter.exists(): files.append((p['id'],'protected-letter',letter,None,'Letter'))
    for kind,key in [('public-full','publicFile'),('public-sample','sampleFile')]:
        if p.get(key): files.append((p['id'],kind,ROOT/'public'/p[key].lstrip('/'),None,'A4'))
failures=[];warnings=[];results=[];total_pages=0;rendered_pages=0
with tempfile.TemporaryDirectory(prefix='mpc-kidz-pdf-audit-') as td:
    td=Path(td)
    for index,(pid,kind,file,expected_pages,expected_size) in enumerate(files):
        row={'productId':pid,'kind':kind,'path':str(file.relative_to(ROOT)),'exists':file.exists()}
        if not file.exists(): failures.append(f'{row["path"]}: missing');results.append(row);continue
        try:
            info=subprocess.run(['pdfinfo',str(file)],capture_output=True,text=True,check=True).stdout
            pages=int(re.search(r'^Pages:\s+(\d+)',info,re.M).group(1));total_pages+=pages
            page_size=re.search(r'^Page size:\s+([0-9.]+) x ([0-9.]+) pts',info,re.M)
            width,height=(float(page_size.group(1)),float(page_size.group(2))) if page_size else (0,0)
            row.update({'pages':pages,'widthPoints':width,'heightPoints':height,'portrait':height>width,'sizeBytes':file.stat().st_size,'tagged':bool(re.search(r'^Tagged:\s+yes',info,re.I|re.M))})
            if pages<3: failures.append(f'{row["path"]}: fewer than 3 pages')
            if expected_pages and pages!=expected_pages: failures.append(f'{row["path"]}: metadata says {expected_pages}, PDF has {pages}')
            if height<=width: failures.append(f'{row["path"]}: not portrait')
            if expected_size=='A4' and not (590<=width<=600 and 838<=height<=846): failures.append(f'{row["path"]}: unexpected A4 dimensions {width}x{height}')
            if expected_size=='Letter' and not (609<=width<=615 and 789<=height<=795): failures.append(f'{row["path"]}: unexpected Letter dimensions {width}x{height}')
            text=subprocess.run(['pdftotext',str(file),'-'],capture_output=True,text=True,check=True).stdout
            row['textCharacters']=len(text.strip())
            if len(text.strip())<150: failures.append(f'{row["path"]}: too little extractable text')
            if '\ufffd' in text: failures.append(f'{row["path"]}: replacement glyph detected')
            fonts=subprocess.run(['pdffonts',str(file)],capture_output=True,text=True,check=True).stdout.splitlines()[2:]
            row['fontRows']=len(fonts)
            not_embedded=[line for line in fonts if len(line.split())>=5 and line.split()[3].lower()=='no']
            if not_embedded: failures.append(f'{row["path"]}: non-embedded font detected')
            out=td/f'doc-{index:03d}';out.mkdir()
            prefix=out/'page'
            subprocess.run(['pdftoppm','-r','36','-png',str(file),str(prefix)],check=True,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
            renders=sorted(out.glob('page-*.png'));rendered_pages+=len(renders)
            if len(renders)!=pages: failures.append(f'{row["path"]}: rendered {len(renders)} of {pages} pages')
            blank=[]
            for page_no,image_path in enumerate(renders,1):
                with Image.open(image_path) as im:
                    grey=im.convert('L'); stat=ImageStat.Stat(grey)
                    if stat.mean[0]>249.5 and stat.stddev[0]<1.5: blank.append(page_no)
            row['blankPages']=blank
            if blank: failures.append(f'{row["path"]}: blank-looking pages {blank}')
            if not row['tagged']: warnings.append(f'{row["path"]}: PDF is not tagged for full screen-reader navigation')
        except Exception as exc:
            failures.append(f'{row["path"]}: {exc}')
        results.append(row)
report={'generatedAt':subprocess.run(['date','-u','+%Y-%m-%dT%H:%M:%SZ'],capture_output=True,text=True).stdout.strip(),'status':'failed' if failures else 'passed','scope':'Automated structural, metadata, font, text extraction, page-size and raster blank-page validation. Launch collection receives separate manual rendered-page review.','totals':{'pdfFiles':len(files),'protectedA4':sum(1 for x in files if x[1]=='protected-a4'),'protectedLetter':sum(1 for x in files if x[1]=='protected-letter'),'publicFull':sum(1 for x in files if x[1]=='public-full'),'publicSamples':sum(1 for x in files if x[1]=='public-sample'),'documentPages':total_pages,'renderedPages':rendered_pages,'failed':len(failures),'warnings':len(warnings)},'failures':failures,'warnings':warnings,'results':results}
(ROOT/'operations').mkdir(exist_ok=True);(ROOT/'operations/MPC_KIDZ_PDF_VALIDATION_REPORT.json').write_text(json.dumps(report,indent=2)+'\n')
if failures:
    print('\n'.join(failures[:50]));raise SystemExit(1)
print(f'MPC Kidz PDF audit passed: {len(files)} files, {total_pages} pages inspected, {rendered_pages} pages rendered; {len(warnings)} accessibility warnings recorded.')
