#!/usr/bin/env python3
"""Do the repo paths cited in `docs/port/*.md` actually resolve?

    tools/port/check-citations              # assert
    tools/port/check-citations --selftest   # can it fail?

`audit-kinds` checks citations in `authored/`. Nothing checked the PROSE, and
prose is where this port explains itself. A first run found **37 of 91**
non-resolving, 41 %, in two very different classes:

  * **19 on the Decoder's topic branch** — real files, not merged here. Not
    errors. A reader in this checkout still cannot follow them, which is worth
    reporting and not worth failing on; the fix is a merge, not an edit.
  * **7 that resolve NOWHERE** — `docs/BLOCKED.md`, `docs/FORMAT.md`,
    `port/manifest.json`, `port/screens/title/*.json`. Left behind by the
    monorepo move and the `export/` rename. Those are simply wrong: a reader
    following one gets nothing, and nothing had ever told anyone.

So the two classes are separated and only the second fails. A check that failed
on the first would be red for a state nobody in this container can fix, which is
the shape the display guard exists to prevent.

⚠️ THE PEER-BRANCH CLASS IS THE OTHER AGENT'S POINT, TURNED ON MYSELF. They
observed that everything they hand over links into `docs/re/` files that live
only on their branch, so every link they send is dangling from here. The same is
true in reverse and neither of us was counting.
"""
import os
import re
import subprocess
import sys
import glob

# A repo path with a file extension, optionally in backticks or a markdown link.
CITE = re.compile(
    r"`?((?:docs|crates|port|tools|authored|export)/[\w./-]+"
    r"\.(?:md|rs|gd|json|txt|py|tsv|csv))`?"
)
PEER_REFS = ("origin/auto/frame-blend-draw-path", "origin/main")


def on_a_ref(path: str) -> str | None:
    """The first ref that carries `path`, or None."""
    for ref in PEER_REFS:
        if subprocess.run(["git", "cat-file", "-e", f"{ref}:{path}"],
                          capture_output=True).returncode == 0:
            return ref
    return None


def scan(files):
    resolves, peer, nowhere = 0, {}, {}
    for p in files:
        try:
            text = open(p, encoding="utf-8").read()
        except OSError:
            continue
        for m in sorted(set(CITE.findall(text))):
            if os.path.exists(m):
                resolves += 1
            elif (ref := on_a_ref(m)):
                peer.setdefault(m, (p, ref))
            else:
                nowhere.setdefault(m, p)
    return resolves, peer, nowhere


def main() -> int:
    if "--selftest" in sys.argv:
        # 🔴 A CHECK THAT CANNOT FAIL IS NOT A CHECK. This plants a citation of a
        # path that exists on no ref and requires the scanner to catch it, and a
        # citation of a real file and requires it NOT to. Both directions,
        # because a scanner that flagged everything would also "pass" the first.
        tmp = os.path.join(os.environ.get("TMPDIR", "/tmp"), "check-citations-selftest")
        os.makedirs(tmp, exist_ok=True)
        bad = os.path.join(tmp, "bad.md")
        open(bad, "w").write("see `docs/port/this-file-does-not-exist-anywhere.md`\n")
        good = os.path.join(tmp, "good.md")
        open(good, "w").write("see `docs/port/PORT-MISSION.md`\n")
        _, _, nb = scan([bad])
        r, _, ng = scan([good])
        ok = len(nb) == 1 and len(ng) == 0 and r == 1
        print("selftest: planted dangling caught=%s, real citation passed=%s -> %s"
              % (len(nb) == 1, len(ng) == 0 and r == 1, "ok" if ok else "🔴 BROKEN"))
        return 0 if ok else 2

    files = sorted(glob.glob("docs/port/*.md"))
    resolves, peer, nowhere = scan(files)
    total = resolves + len(peer) + len(nowhere)
    print("citations of repo paths in docs/port/*.md: %d" % total)
    print("  resolve here                : %d" % resolves)
    print("  on a peer branch, not merged: %d  (reported, not failed)" % len(peer))
    for m, (src, ref) in sorted(peer.items()):
        print("      %-52s %s  <- %s" % (m, ref.split("/")[-1], os.path.basename(src)))
    if nowhere:
        print("  🔴 resolve NOWHERE          : %d" % len(nowhere))
        for m, src in sorted(nowhere.items()):
            print("      %-52s <- %s" % (m, os.path.basename(src)))
        print("\n🔴 a reader following those gets nothing. Fix the path or drop the citation.")
        return 1
    print("  🔴 resolve nowhere          : 0")
    return 0


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