"""The stylesheet half of the playground's brand-adherence gate.

The design system's oxlint configuration rejects a raw hex colour, a raw px
value and an off-family font — but it matches string literals in JavaScript,
and the playground's declarations live in stylesheets it cannot see. This
check covers them: together the two are what makes "no component declares a
colour of its own" true; either alone leaves half the declarations unguarded.

Rules, per declaration:

- A hex colour may appear only in a custom-property definition (`--name: ...`).
  Components consume colours through var(); the tokens files — the design
  system's own, and the page's pending-promotion set — are where values live.
- A px length may appear in a custom-property definition, and as a hairline
  (1px, 1.5px or 2px) anywhere — a border width is structure, not scale.
  Every other size comes through a token.
- A font-family must resolve to the design system's families: a var() whose
  name starts with --font, or a literal naming an IBM Plex family.

Scope: every .css file under src/quber/playground/ui/src. The synced
design-system token files under static/tokens and the compiled static/app.css
are the definitions themselves and the bundle of already-checked sources.
"""

from __future__ import annotations

import re
import sys
from pathlib import Path

CSS_ROOT = Path("src/quber/playground/ui/src")

HEX = re.compile(r"#[0-9a-fA-F]{3,8}\b")
PX = re.compile(r"\b(\d+(?:\.\d+)?)px\b")
HAIRLINE = {"1", "1.5", "2"}
CUSTOM_PROP = re.compile(r"^\s*--[\w-]+\s*:")
FONT_FAMILY = re.compile(r"font-family\s*:\s*([^;]+)", re.IGNORECASE)
FONT_OK = re.compile(r"^(var\(--font-[\w-]+\)|inherit)$")


def strip_comments(text: str) -> str:
    return re.sub(r"/\*.*?\*/", "", text, flags=re.DOTALL)


def check(path: Path) -> list[str]:
    problems: list[str] = []
    for lineno, line in enumerate(strip_comments(path.read_text()).splitlines(), start=1):
        is_definition = bool(CUSTOM_PROP.match(line))
        if not is_definition:
            if HEX.search(line):
                problems.append(f"{path}:{lineno}: raw hex colour — use a token via var()")
            for m in PX.finditer(line):
                if m.group(1) not in HAIRLINE:
                    problems.append(f"{path}:{lineno}: raw px length {m.group(0)} — use a token via var()")
        fam = FONT_FAMILY.search(line)
        if fam and not FONT_OK.match(fam.group(1).strip()):
            problems.append(
                f"{path}:{lineno}: font-family must be a design-system font token (var(--font-*))"
            )
    return problems


def main() -> int:
    files = sorted(CSS_ROOT.rglob("*.css"))
    if not files:
        print(f"no stylesheets under {CSS_ROOT}", file=sys.stderr)
        return 1
    problems = [p for f in files for p in check(f)]
    for p in problems:
        print(p, file=sys.stderr)
    if problems:
        print(f"{len(problems)} declaration(s) off the token set", file=sys.stderr)
        return 1
    print(f"checked {len(files)} stylesheets: every declaration draws from the token set")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
