"""Validate every public page, local route, and asset before packaging."""
from pathlib import Path
from html.parser import HTMLParser
from urllib.parse import urlsplit, unquote
import json
import hashlib
ROOT = Path(__file__).resolve().parents[1]
class Page(HTMLParser):
    def __init__(self):
        super().__init__(); self.links=[]; self.ids=[]; self.h1=0; self.title=0; self.canonical=0; self.errors=[]
    def handle_starttag(self, tag, attrs):
        a=dict(attrs)
        if 'id' in a: self.ids.append(a['id'])
        self.h1 += tag == 'h1'; self.title += tag == 'title'
        self.canonical += tag == 'link' and a.get('rel') == 'canonical'
        for key in ['href','src']:
            if key in a: self.links.append(a[key])
        if tag=='img' and 'alt' not in a: self.errors.append('image missing alt')

def validate():
    paths=[ROOT/'index.html', ROOT/'coherence'/'index.html'] + sorted((ROOT/'products').rglob('index.html')) + [ROOT/'method'/'index.html'] + sorted((ROOT/'lab').rglob('index.html')) + [ROOT/'downloads'/'index.html']
    parsed={}; errors=[]; links=0
    for path in paths:
        page=Page(); page.feed(path.read_text(encoding='utf-8')); parsed[path.resolve()]=page
        for key in ['h1','title','canonical']:
            if getattr(page,key)!=1: errors.append(f'{path.relative_to(ROOT)}: expected one {key}, got {getattr(page,key)}')
        if len(page.ids)!=len(set(page.ids)): errors.append(f'{path}: duplicate IDs')
        errors.extend(f'{path.name}: {x}' for x in page.errors)
    for path,page in parsed.items():
        for link in page.links:
            u=urlsplit(link)
            if u.scheme or u.netloc: continue
            target=(ROOT/unquote(u.path.lstrip('/'))) if u.path.startswith('/') else (path.parent/unquote(u.path)) if u.path else path
            if target.is_dir(): target=target/'index.html'
            target=target.resolve(); links+=1
            if not target.is_relative_to(ROOT) or not target.is_file(): errors.append(f'{path.relative_to(ROOT)}: broken link {link}')
            elif u.fragment and target in parsed and u.fragment not in parsed[target].ids and 'coherence' not in target.parts: errors.append(f'{path.relative_to(ROOT)}: missing anchor {link}')
    assert not errors, '\n'.join(errors)
    print(json.dumps({'status':'PASS','pages':len(paths),'local_links':links,'page_sha256':{str(p.relative_to(ROOT)).replace('\\','/'):hashlib.sha256(p.read_bytes()).hexdigest() for p in paths}},indent=2))
if __name__=='__main__': validate()
