#!/usr/bin/env python3
"""
Optional CSS.spv token parser · SPEED path for Host/native
Browser still uses real CSS cascade for perfect display.
This only extracts :root custom properties + simple rules for push/WBF.

Use when: native engine / chain push needs tokens without full CSSOM.
Do NOT replace browser CSS for viewing.

Also reports 100% CSS endurance coverage vs HTML5 catalog tags.
"""
from __future__ import annotations

import re
from pathlib import Path
from typing import Any, Dict, List

ROOT = Path(__file__).resolve().parents[1]
SPV_CSS = ROOT / "css" / "spv.css"
SHELL_CSS = ROOT / "css" / "shell.css"

VAR_RE = re.compile(r"--([a-zA-Z0-9-]+)\s*:\s*([^;]+);")
RULE_RE = re.compile(r"([^{}@][^{]*)\{([^}]*)\}", re.S)

# HTML5 catalog tags that must have CSS endurance styling in spv.css
HTML5_CSS_NEED = [
    "article", "section", "nav", "aside", "header", "footer", "main", "address",
    "search", "hgroup", "h1", "h2", "h3", "h4", "h5", "h6", "p", "hr", "pre",
    "blockquote", "ul", "ol", "li", "dl", "dt", "dd", "menu",
    "a", "strong", "em", "b", "i", "u", "s", "small", "mark", "abbr", "dfn",
    "cite", "q", "code", "kbd", "samp", "var", "sub", "sup", "time", "data",
    "span", "bdi", "bdo", "ins", "del",
    "figure", "figcaption", "picture", "img", "audio", "video", "canvas", "svg",
    "table", "caption", "thead", "tbody", "tfoot", "tr", "th", "td",
    "form", "fieldset", "legend", "label", "input", "button", "select",
    "optgroup", "option", "textarea", "output", "progress", "meter", "datalist",
    "details", "summary", "dialog", "template", "slot",
    "object", "embed", "iframe", "map", "area",
    "ruby", "rt", "rp", "math", "noscript",
    "hidden",  # existence styling
]


def parse_tokens(css_text: str) -> Dict[str, str]:
    return {m.group(1): m.group(2).strip() for m in VAR_RE.finditer(css_text)}


def parse_rule_names(css_text: str) -> List[str]:
    names = []
    for m in RULE_RE.finditer(css_text):
        sel = " ".join(m.group(1).split())
        if sel.startswith("@") or not sel:
            continue
        names.append(sel)
    return names


def load_spv_css() -> str:
    parts = []
    for p in (SPV_CSS, SHELL_CSS):
        if p.exists():
            t = p.read_text()
            if p.name == "shell.css":
                t = t.replace('@import url("spv.css");', "")
            parts.append(t)
    return "\n".join(parts)


def css_endurance(css: str) -> Dict[str, Any]:
    """100% CSS endurance: every catalog tag appears in some selector."""
    low = css.lower()
    ok, miss = [], []
    for tag in HTML5_CSS_NEED:
        # match tag as selector word / type selector
        if re.search(rf"(^|[^\w-]){re.escape(tag)}([^\w-]|$)", low):
            ok.append(tag)
        else:
            miss.append(tag)
    total = len(HTML5_CSS_NEED)
    pct = int(round(100.0 * len(ok) / total)) if total else 0
    return {
        "need": total,
        "ok": len(ok),
        "miss": miss,
        "pct": pct,
        "css100": len(miss) == 0,
        "banner": "100% CSS ENDURANCE" if not miss else f"CSS endurance {pct}%",
    }


def summary() -> Dict[str, Any]:
    css = load_spv_css()
    tokens = parse_tokens(css)
    rules = parse_rule_names(css)
    grin = {k: v for k, v in tokens.items() if "grin" in k.lower()}
    bgf = {k: v for k, v in tokens.items() if k.startswith("bgf") or "bgf" in k}
    endurance = css_endurance(css)
    return {
        "mode": "token_parse_only",
        "perfect_display": "browser CSS cascade (spv.css) — not this parser",
        "parser_speed": "yes · Host/native push tokens",
        "token_count": len(tokens),
        "rule_count": len(rules),
        "grin_tokens": grin,
        "bgf_tokens": bgf,
        "has_spv_grin": "spv-grin" in tokens or any("grin" in k for k in tokens),
        "html5_selectors_sample": [
            r
            for r in rules
            if any(x in r for x in ("article", "nav", "video", "table", "hidden", "html5-all"))
        ][:20],
        "css_endurance": endurance,
        "bunny": "Big Buck Bunny free in mp4 plug · perfect display plays via <video>",
    }


if __name__ == "__main__":
    import json

    print(json.dumps(summary(), indent=2))
