#!/usr/bin/env python3
"""Export the dated reports and their linked local artifacts as a static site."""
from __future__ import annotations

import json
import shutil
from datetime import datetime, timezone
from html.parser import HTMLParser
from pathlib import Path
from urllib.parse import unquote, urlsplit

PROJECT = Path(__file__).resolve().parents[2]
HERE = Path(__file__).resolve().parent
OUTPUT = HERE / "share_site"
REPORT_NAMES = ("main", "preprocessing", "model", "me1a_comparison", "me1a_smoke_dashboard", "results")
ALLOWED_SUFFIXES = {".html", ".css", ".js", ".png", ".jpg", ".jpeg", ".svg",
                    ".csv", ".json", ".md", ".py", ".npz", ".pt"}


class References(HTMLParser):
    def __init__(self) -> None:
        super().__init__()
        self.refs: list[str] = []

    def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
        attributes = dict(attrs)
        for key in ("href", "src"):
            if attributes.get(key):
                self.refs.append(attributes[key])


def collect() -> tuple[set[Path], set[Path]]:
    seeds = [HERE / f"{name}.html" for name in REPORT_NAMES]
    seeds += [HERE / f"{name}.png" for name in REPORT_NAMES]
    seeds += [PROJECT / "experiments/preprocess_size_desicisions/page.png",
              PROJECT / "experiments/preprocess_size_desicisions/candidates/page.png"]
    files = set(seeds)
    pending = [HERE / f"{name}.html" for name in REPORT_NAMES]
    visited_html: set[Path] = set()
    missing: set[Path] = set()
    while pending:
        page = pending.pop().resolve()
        if page in visited_html:
            continue
        visited_html.add(page)
        parser = References()
        parser.feed(page.read_text(encoding="utf-8", errors="replace"))
        for ref in parser.refs:
            url = urlsplit(ref)
            if url.scheme or url.netloc or not url.path:
                continue
            target = (page.parent / unquote(url.path)).resolve()
            if not target.is_relative_to(PROJECT):
                continue
            if target.is_dir():
                target /= "index.html"
            if not target.exists():
                missing.add(target)
                continue
            if not target.is_file() or target.suffix.lower() not in ALLOWED_SUFFIXES:
                continue
            files.add(target)
            if target.suffix.lower() == ".html" and target not in visited_html:
                pending.append(target)
    return files, missing


def main() -> None:
    files, missing = collect()
    if OUTPUT.exists():
        shutil.rmtree(OUTPUT)
    OUTPUT.mkdir(parents=True)
    for source in sorted(files):
        relative = source.relative_to(PROJECT)
        destination = OUTPUT / relative
        destination.parent.mkdir(parents=True, exist_ok=True)
        shutil.copy2(source, destination)
    # Four links in historical diffusion galleries pointed to paths that were
    # absent in the source tree. Keep the shared navigation explicit.
    for source in sorted(missing):
        relative = source.relative_to(PROJECT)
        if source.suffix.lower() != ".html":
            destination = OUTPUT / relative / "index.html"
        else:
            destination = OUTPUT / relative
        destination.parent.mkdir(parents=True, exist_ok=True)
        destination.write_text('<!doctype html><html lang="en"><meta charset="utf-8">'
                               '<title>Original result unavailable</title>'
                               '<body style="font:16px system-ui;max-width:700px;margin:50px auto">'
                               '<h1>Original result unavailable</h1>'
                               '<p>This link was absent from the source experiment results.</p>'
                               '<p><a href="/reports/260929/main.html">Return to the report</a></p>'
                               '</body></html>')
    (OUTPUT / "index.html").write_text('<!doctype html><html lang="en"><meta charset="utf-8">'
                                       '<meta http-equiv="refresh" content="0;url=reports/260929/main.html">'
                                       '<title>AC28 + ME1a report</title>'
                                       '<p><a href="reports/260929/main.html">Open report</a></p>')
    manifest = {
        "built_utc": datetime.now(timezone.utc).isoformat(),
        "entrypoint": "reports/260929/main.html",
        "files": len(files),
        "size_bytes": sum(p.stat().st_size for p in files),
        "unavailable_source_links": [str(p.relative_to(PROJECT)) for p in sorted(missing)],
        "scope": "files reachable from the six dated report HTML pages, plus report and gallery PNG exports",
    }
    (OUTPUT / "share_manifest.json").write_text(json.dumps(manifest, indent=2))
    print(f"Built {OUTPUT}: {manifest['files']} linked files, {manifest['size_bytes']/1e6:.1f} MB, "
          f"{len(missing)} unavailable historical links identified")


if __name__ == "__main__":
    main()
