#!/usr/bin/env python3
"""Regenerate INDEX.md for an ADR directory. Parses ADR-*.md frontmatter
(adr/status/date/decision/supersedes), writes INDEX.md, splits legacy
non-numbered ADRs into an Unnumbered table, hard-fails on duplicate
numbers, filename/frontmatter mismatch, or broken supersedes links."""
import argparse, re, sys
from pathlib import Path

NAMED = re.compile(r"^ADR-(\d{3})-([a-z0-9-]+)\.md$")
FM = re.compile(r"^---\n(.*?)\n---", re.DOTALL)
FIELD = re.compile(r"^([a-z_]+):\s*(.+?)\s*$", re.MULTILINE)
HEAD = "| # | Title | Status | Date | Supersedes |\n|---|---|---|---|---|"


def fm(t):
    m = FM.search(t)
    return {k: v.strip(" \"'") for k, v in FIELD.findall(m.group(1))} if m else {}


def scan(d):
    num, leg, errs, seen = [], [], [], {}
    for p in sorted(d.glob("ADR-*.md")):
        if p.name == "INDEX.md": continue
        meta, m = fm(p.read_text(encoding="utf-8")), NAMED.match(p.name)
        if not m:
            leg.append({"path": p.name, **meta}); continue
        n = m.group(1)
        if meta.get("adr") and meta["adr"].lstrip("0") != n.lstrip("0"):
            errs.append(f"{p.name}: adr={meta['adr']} != filename {n}")
        if n in seen: errs.append(f"ADR-{n} duplicate: {p.name} and {seen[n]}")
        seen[n] = p.name
        num.append({"num": n, "slug": m.group(2), "path": p.name, **meta})
    nums = {r["num"] for r in num}
    for r in num:
        s = r.get("supersedes", "—")
        if s and s != "—":
            t = s.replace("ADR-", "").lstrip("0").zfill(3)
            if t not in nums: errs.append(f"{r['path']}: supersedes ADR-{t} not found")
    return num, leg, errs


def row(r):
    title = r.get("decision", r.get("slug", "—")).replace("-", " ").title()
    label = f"ADR-{r['num']}" if "num" in r else r["path"][:-3]
    return (f"| [{label}]({r['path']}) | {title} | {r.get('status','—')} "
            f"| {r.get('date','—')} | {r.get('supersedes','—')} |")


def render(num, leg):
    out = ["# ADR Index", "", "_Auto-generated by `scripts/adr/regenerate_index.py`. Do not edit._", ""]
    if not num and not leg: return "\n".join(out + ["No ADRs yet.", ""])
    out += [HEAD, *(row(r) for r in num)]
    if leg: out += ["", "## Unnumbered (legacy)", "", HEAD, *(row(r) for r in leg)]
    return "\n".join(out + [""])


def main():
    ap = argparse.ArgumentParser(description="Regenerate ADR INDEX.md")
    ap.add_argument("--dir", default="docs/adr/")
    ap.add_argument("--check", action="store_true", help="exit 1 if INDEX.md is stale")
    a = ap.parse_args()
    d = Path(a.dir)
    if not d.is_dir():
        print(f"adr-dir not found: {d}", file=sys.stderr); return 2
    num, leg, errs = scan(d)
    for e in errs: print(f"error: {e}", file=sys.stderr)
    if errs: return 2
    rendered, idx = render(num, leg), d / "INDEX.md"
    if a.check:
        cur = idx.read_text(encoding="utf-8") if idx.exists() else ""
        if cur != rendered: print(f"stale: {idx}", file=sys.stderr); return 1
        return 0
    idx.write_text(rendered, encoding="utf-8")
    print(f"wrote {idx} ({len(num)} numbered, {len(leg)} legacy)")
    return 0


if __name__ == "__main__":
    sys.exit(main())
