#!/usr/bin/env python3
"""Required-field checker for handbook record templates (stdlib only).

Each record kind declares a title prefix plus required ``##`` headings.
Files under a ``filled`` directory additionally must carry no TODO marker.
Prints one line per file plus a total; exits 1 on any failure.

Usage:
    python3 check_templates.py [path ...]   # files or directories
    python3 check_templates.py              # templates/ + filled/ beside this script
"""

import argparse
import re
import sys
from pathlib import Path

TITLE_RE = re.compile(r"^#(?!#)\s+(.*\S)\s*$", re.MULTILINE)
SECTION_RE = re.compile(r"^##\s+(.*\S)\s*$", re.MULTILINE)

REQUIRED = {
    "scope-card": (
        "# Scope card:",
        ["Question", "Case categories", "Applicability", "In scope",
         "Out of scope", "Inputs", "Dependencies", "External data",
         "Human decisions", "Limits", "Provenance", "Readiness"],
    ),
    "source-inventory": (
        "# Source inventory:",
        ["Edition", "Fate map", "Unprocessed", "Decision flags"],
    ),
    "decision-record": (
        "# Decision record:",
        ["Status", "Context", "Question", "Options considered",
         "Position", "Justification", "Distinguishing scenario",
         "Assumptions", "Consequences", "Open questions", "Review"],
    ),
    "review-record": (
        "# Review record:",
        ["Scope", "Identity", "Reviewers", "Kind", "Method",
         "Findings", "Disposition", "Verdict"],
    ),
}


def kind_of(path: Path) -> str | None:
    name = path.name
    if "scope-card" in name:
        return "scope-card"
    if "source-inventory" in name:
        return "source-inventory"
    if "decision" in name:
        return "decision-record"
    if "review" in name:
        return "review-record"
    return None


def check_file(path: Path) -> list[str]:
    errors: list[str] = []
    kind = kind_of(path)
    if kind is None:
        return [f"unknown record kind for {path.name}"]
    title_prefix, required = REQUIRED[kind]
    try:
        text = path.read_text(encoding="utf-8")
    except OSError as exc:
        return [f"unreadable: {exc}"]
    titles = [m.group(1) for m in TITLE_RE.finditer(text)]
    sections = [m.group(1) for m in SECTION_RE.finditer(text)]
    if not titles or not titles[0].startswith(title_prefix[2:]):
        errors.append(f"title must start with {title_prefix!r}")
    for heading in required:
        count = sections.count(heading)
        if count == 0:
            errors.append(f"missing ## {heading}")
        elif count > 1:
            errors.append(f"duplicated ## {heading}")
    if "filled" in path.parts and "TODO" in text:
        errors.append("filled record still carries a TODO marker")
    return errors


def collect(paths: list[str]) -> tuple[list[Path], int]:
    if not paths:
        here = Path(__file__).resolve().parent
        paths = [str(here / "templates"), str(here / "filled")]
    found: list[Path] = []
    missing = 0
    for raw in paths:
        target = Path(raw)
        if target.is_dir():
            found.extend(sorted(target.glob("*.md")))
        elif target.is_file():
            found.append(target)
        else:
            missing += 1
            print(f"FAIL {raw}: no such file or directory")
    return found, missing


def main(argv: list[str]) -> int:
    parser = argparse.ArgumentParser(description="Check handbook record templates.")
    parser.add_argument("paths", nargs="*", help="files or directories to check")
    args = parser.parse_args(argv)
    files, missing = collect(args.paths)
    failed = 0
    for path in files:
        errors = check_file(path)
        if errors:
            failed += 1
            print(f"FAIL {path}: {'; '.join(errors)}")
        else:
            print(f"ok {path}")
    if not files and not missing:
        print("FAIL: no documents found under the given paths")
    print(f"total: {len(files)} checked, {len(files) - failed} passed, {failed} failed")
    return 1 if (failed or missing or not files) else 0


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))
