"""Handoff checks for the exported artifacts, not a rendering implementation test."""
from pathlib import Path
from hashlib import sha256
import json
import re
import xml.etree.ElementTree as ET
from PIL import Image
from pypdf import PdfReader
from fontTools.pens.boundsPen import BoundsPen
from fontTools.svgLib.path import parse_path
from identity import geometry,reconstruct_mark,patch_mark,full_logo
from graphics import ROOT,fonts,Scene

NS='{http://www.w3.org/2000/svg}'
checks=[]
def check(name,condition,detail=''):
    checks.append({'check':name,'pass':bool(condition),'detail':detail})
    if not condition:raise AssertionError(name+': '+str(detail))

def main():
    svgs=sorted((ROOT/'logos').glob('*.svg'))
    check('Twenty outlined logo variants',len(svgs)==20,len(svgs))
    for svg in svgs:
        tree=ET.fromstring(svg.read_text())
        check(f'{svg.name}: paths only',len(tree.findall('.//'+NS+'image'))==0 and len(tree.findall('.//'+NS+'text'))==0)
        check(f'{svg.name}: self-contained','href=' not in svg.read_text() and 'url(' not in svg.read_text())
        png=Image.open(svg.with_suffix('.png'))
        check(f'{svg.name}: transparent PNG',png.mode=='RGBA' and png.getextrema()[3]==(0,255),png.mode)
        check(f'{svg.name}: vector PDF',len(PdfReader(svg.with_suffix('.pdf')).pages)==1)
    for family in ['primary','english','compact','emblem','wordmark']:
        instances=[]
        for kind in ['colour','black','white','reverse']:
            tree=ET.fromstring((ROOT/'logos'/f'stf-{family}-{kind}.svg').read_text())
            instances.append([(p.attrib['d'],p.attrib.get('transform')) for p in tree.findall(NS+'path')])
        check(f'{family}: identical geometry across colour variants',all(v==instances[0] for v in instances))
        for kind,allowed in [('black',{'#111111'}),('white',{'#FFFFFF'}),('reverse',{'#FFFFFF','#C81D25'})]:
            tree=ET.fromstring((ROOT/'logos'/f'stf-{family}-{kind}.svg').read_text())
            fills={p.attrib['fill'] for p in tree.findall(NS+'path')}
            check(f'{family}: {kind} palette',fills<=allowed,str(fills))
    f=fonts();logo=full_logo(f,reconstruct_mark())
    jp=[geometry(i['d'],i['m']).bounds for i in logo.items if i['role']=='katakana']
    check('All eleven Japanese glyph positions present',len(jp)==11,len(jp))
    top=min(b[1] for b in jp);bottom=max(b[3] for b in jp)
    check('Japanese column anchored at both ends',abs(top-270)<.01 and abs(bottom-808)<.01,{'top':top,'bottom':bottom})
    for key,scene in [('primary',logo)]:
        bounds=[geometry(i['d'],i['m']).bounds for i in scene.items]
        check(f'{key}: artwork stays inside canvas',all(b[0]>=0 and b[1]>=0 and b[2]<=scene.w and b[3]<=scene.h for b in bounds))
    stand=Scene(1000,1000);f['display'].text(stand,'STAND',514,270,200,width=410)
    original=geometry(stand.items[0]['d'],stand.items[0]['m'])
    overlap=next(i for i in logo.items if i['role']=='name-stand-overlap')
    refined=geometry(overlap['d'],overlap['m']);removed=1-refined.area/original.area
    check('A restrained real cut exists in S',.001<removed<.2,{'fraction_of_S_removed':round(removed,4)})
    pm=patch_mark(reconstruct_mark());shapes=[geometry(i['d'],i['m']) for i in pm.items]
    min_gap=min(shapes[i].distance(shapes[j]) for i in range(len(shapes)) for j in range(i))*.1544
    check('Name-patch independent shapes clear 1 mm in artwork',min_gap>=1.0,{'minimum_gap_mm':round(min_gap,3),'not_a_stitch_validation':True})
    for filename,mm in [('stf-name-patch-100x85mm-colour.pdf',(100,85)),('stf-emblem-patch-75mm-colour.pdf',(75,75))]:
        p=PdfReader(ROOT/'patches'/filename).pages[0];actual=(float(p.mediabox.width)/72*25.4,float(p.mediabox.height)/72*25.4)
        check(filename+': actual size',all(abs(a-b)<.01 for a,b in zip(actual,mm)),actual)
    for filename,trim in [('stf-poster-a3-template-cmyk-3mm-bleed.pdf',(297,420)),('stf-card-front-cmyk-3mm-bleed.pdf',(85,55)),('stf-card-back-template-cmyk-3mm-bleed.pdf',(85,55))]:
        p=PdfReader(ROOT/'print'/filename).pages[0]
        actual=(float(p.trimbox.width)/72*25.4,float(p.trimbox.height)/72*25.4)
        media=(float(p.mediabox.width)/72*25.4,float(p.mediabox.height)/72*25.4)
        check(filename+': trim and bleed',all(abs(a-b)<.01 for a,b in zip(actual,trim)) and all(abs(a-b-6)<.01 for a,b in zip(media,trim)),{'trim_mm':actual,'media_mm':media})
        stream=p.get_contents().get_data()
        check(filename+': CMYK fill operators',b' k' in stream and b' rg' not in stream)
    guide=PdfReader(ROOT/'guide/stand-the-fight-brand-guide-v1.pdf')
    check('Thirteen-page guide',len(guide.pages)==13,len(guide.pages))
    check('All guide pages rendered',len(list((ROOT/'previews/guide-pages').glob('page-*.png')))==13)
    check('Both patch mockups embedded in guide',len(guide.pages[11].images)==2,len(guide.pages[11].images))
    for mm in [75,90]:
        for kind,colour in [('colour','#C81D25'),('black','#111111')]:
            tree=ET.parse(ROOT/'patches/balanced-circular'/f'stf-n1-balanced-patch-{mm}mm-{kind}.svg')
            lettering=[p for p in tree.iter(NS+'path') if p.get('data-role')=='patch-japanese']
            check(f'N1 {mm}mm {kind}: Japanese lettering colour',len(lettering)==11 and all(p.get('fill')==colour for p in lettering))
    for svg in [*ROOT.joinpath('social').glob('*template.svg'),*ROOT.joinpath('print').glob('*template*.svg')]:
        text=svg.read_text();check(svg.name+': editable fields','data-editable=' in text and '<text ' in text)
    for source in json.loads((ROOT/'fonts/sources.json').read_text()):
        check(source['file']+': original font/licence hash',sha256((ROOT/source['file']).read_bytes()).hexdigest()==source['sha256'])
    for license in (ROOT/'fonts').glob('*/OFL.txt'):check(str(license.relative_to(ROOT))+': licence included','SIL OPEN FONT LICENSE' in license.read_text())
    for png in ROOT.rglob('*.png'):
        im=Image.open(png);im.verify()
    check('All PNG exports decode',True)
    report={'result':'PASS','checks':checks,'manual_review':'All 13 guide pages, primary master, patch art, overview and web context were visually reviewed. Patch mockup is illustrative only.'}
    (ROOT/'previews/export-checks.json').write_text(json.dumps(report,indent=2)+'\n')
    (ROOT/'previews/export-checks.txt').write_text('PASS - '+str(len(checks))+' export checks\nMinimum independent-shape separation in 100 mm patch artwork: '+f'{min_gap:.3f} mm\nJapanese column: top 270, bottom 808, matching English name/descriptor anchors.\nSVG geometry matches across colour variants. PNG transparency, PDF page sizes, bleed/trim boxes, CMYK operators, licences and all 13 rendered guide pages checked.\nPhysical stitch quality and substrate colour remain supplier proofing tasks.\n')
    print(f'PASS: {len(checks)} checks. Patch gap: {min_gap:.3f} mm. S cut: {removed:.2%}.')

if __name__=='__main__':main()
