#!/usr/bin/env python3
"""Static package checks. These cannot establish browser or screen-reader behavior."""
from pathlib import Path
from html.parser import HTMLParser
from urllib.parse import urlsplit,unquote
import ast,csv,json,re,sys,xml.etree.ElementTree as ET
ROOT=Path(__file__).resolve().parents[1]
class Page(HTMLParser):
    def __init__(self,text):
        super().__init__();self.ids=[];self.refs=[];self.images=[];self.headings=[];self.lang=None;self.main=False;self.feed(text)
    def handle_starttag(self,tag,attrs):
        a=dict(attrs)
        if 'id'in a:self.ids.append(a['id'])
        for k in ('href','src'):
            if k in a:self.refs.append(a[k])
        if tag=='html':self.lang=a.get('lang')
        if tag=='main':self.main=True
        if tag=='img':self.images.append(a)
        if re.fullmatch('h[1-6]',tag):self.headings.append(tag)

def run():
    errors=[];checks=0;refs=0
    def check(value,msg):
        nonlocal checks
        checks+=1
        if not value:errors.append(msg)
    pages={p:Page(p.read_text()) for p in ROOT.glob('*.html')}
    for path,p in pages.items():
        check(p.lang=='en',f'{path.name}: English language missing');check(p.main,f'{path.name}: main landmark missing')
        check(p.headings.count('h1')==1,f'{path.name}: expected one page h1');check(len(p.ids)==len(set(p.ids)),f'{path.name}: duplicate IDs')
        for img in p.images:check(bool(img.get('alt','').strip()),f'{path.name}: missing image text alternative')
        for ref in p.refs:
            if not ref or urlsplit(ref).scheme:continue
            refs+=1;parts=urlsplit(ref);target=(path.parent/unquote(parts.path)).resolve() if parts.path else path
            check(target.exists(),f'{path.name}: missing {ref}')
            if parts.fragment and target in pages:check(unquote(parts.fragment)in pages[target].ids,f'{path.name}: missing anchor {ref}')
    svgfiles=sorted((ROOT/'assets').glob('*.svg'));check(len(svgfiles)==9,'Expected 9 SVGs')
    for path in svgfiles:
        root=ET.parse(path).getroot();ns={'s':'http://www.w3.org/2000/svg'}
        check(root.get('role')=='img',f'{path.name}: SVG role missing')
        check(root.find('s:title',ns)is not None,f'{path.name}: title missing');check(root.find('s:desc',ns)is not None,f'{path.name}: description missing')
    lessons=sorted((ROOT/'lessons').glob('*.md'));word_counts={p.name:len(re.findall(r"\b[\w’-]+\b",p.read_text())) for p in lessons}
    check(len(lessons)==12,'Expected 12 lessons');check(sum(word_counts.values())>=9000,'Expected substantial lesson narrative')
    for name,count in word_counts.items():check(count>=600,f'{name}: unusually short teaching narrative')
    wb=(ROOT/'WORKBOOK.md').read_text();check(len(re.findall(r'^### \d+[ABC] ',wb,re.M))==36,'Expected 36 distinct exercises')
    assess=(ROOT/'ASSESSMENTS.md').read_text();check(len(re.findall(r'^[ABC][1-6]\. ',assess,re.M))==18,'Expected 18 checkpoint questions')
    sol=(ROOT/'SOLUTIONS.md').read_text()
    for i in range(1,13):
        for letter in 'ABC':check(bool(re.search(rf'^{i}{letter}\. ',sol,re.M)),f'Missing answer {i}{letter}')
    for letter in 'ABC':
        for i in range(1,7):check(bool(re.search(rf'^{letter}{i}\. ',sol,re.M)),f'Missing checkpoint answer {letter}{i}')
    for path in ROOT.rglob('*.py'):
        try:ast.parse(path.read_text());check(True,'')
        except SyntaxError as e:check(False,f'{path.relative_to(ROOT)}: {e}')
    values=json.loads((ROOT/'outputs/chart_values.json').read_text());check(sum(values['shipments_histogram']['counts'])==240,'Histogram count mismatch')
    check(values['trial_effect']['ci_low']<values['trial_effect']['difference']<values['trial_effect']['ci_high']<0,'Trial chart ordering')
    check(values['trial_effect']['ci_low']<-2<values['trial_effect']['ci_high'],'Threshold missing from interval')
    report={'checks':checks,'html_pages':len(pages),'local_references':refs,'svg_visuals':len(svgfiles),'lessons':len(lessons),'lesson_word_counts':word_counts,'lesson_words_total':sum(word_counts.values()),'exercises':36,'checkpoint_questions':18,'errors':errors,'scope':'Static source, links, SVG descriptions and content counts only; no browser/accessibility behavior assertion.'}
    (ROOT/'outputs/package_checks.json').write_text(json.dumps(report,indent=2)+'\n')
    print(json.dumps(report,indent=2));return bool(errors)
if __name__=='__main__':raise SystemExit(run())
