#!/usr/bin/env python3
"""demo-postwrite-pattern-gate — PostToolUse check: composite demos cite a pattern source.

Composite demos authored without surveying a canonical page produced the
2026-05 broken-demo cohort; the repo's no-merge CI gate
(`npm run audit:demo-pattern-source:strict`) enforces a `Pattern source:`
citation. This hook moves that feedback from CI-time to write-time: when a
`packages/web-modules/**/*.{examples,contents}.html` file is written without
the citation, it feeds the repair back immediately.

It checks only the deterministic residue (citation present). Whether the
cited pattern is APPROPRIATE stays judgment — the primitive-authoring skill's
composite-demo reference owns that.

Usage:
  demo-postwrite-pattern-gate --hook       # PostToolUse mode: event JSON on stdin
  demo-postwrite-pattern-gate selftest     # prove matcher + content check on fixtures
"""
import json
import os
import sys

MARKER = "Pattern source:"


def in_scope(path):
    return "packages/web-modules/" in path and (
        path.endswith(".examples.html") or path.endswith(".contents.html")
    )


def check_content(text):
    return MARKER in text


def hook_mode():
    try:
        event = json.load(sys.stdin)
    except Exception:
        return 0
    tool_input = event.get("tool_input") or {}
    path = tool_input.get("file_path") or ""
    if not in_scope(path):
        return 0
    try:
        with open(path, encoding="utf-8", errors="replace") as f:
            text = f.read()
    except OSError:
        return 0
    if check_content(text):
        return 0
    reason = (
        f"demo-postwrite-pattern-gate · {path} has no `Pattern source:` citation. "
        "Composite demos must cite the canonical page they pattern from — survey "
        "apps/<area>/app/**.contents.html + catalog/ui-patterns/ first, then add "
        "`<!-- Pattern source: <path> -->` near the top (see primitive-authoring's "
        "composite-demo reference). CI enforces this via "
        "`npm run audit:demo-pattern-source:strict`. If a citation is genuinely "
        "impossible, document the carve-out in the file header instead."
    )
    print(json.dumps({"decision": "block", "reason": reason}))
    return 0


def selftest():
    scope_cases = [
        ("packages/web-modules/shell/admin/admin.examples.html", True),
        ("packages/web-modules/chat/input/input.contents.html", True),
        ("packages/web-components/components/badge/badge.html", False),
        ("apps/tasks/app/index.contents.html", False),
    ]
    for path, expected in scope_cases:
        if in_scope(path) != expected:
            print(f"selftest: FAIL scope {path}")
            return 1
    content_cases = [
        ("<!-- Pattern source: apps/saas/app/admin/admin.contents.html -->\n<div>", True),
        ("<div>no citation here</div>", False),
    ]
    for text, expected in content_cases:
        if check_content(text) != expected:
            print(f"selftest: FAIL content {text[:30]!r}")
            return 1
    print("selftest: PASS")
    return 0


if __name__ == "__main__":
    if "selftest" in sys.argv:
        sys.exit(selftest())
    if "--hook" in sys.argv:
        sys.exit(hook_mode())
    print(__doc__)
    sys.exit(0)
