"""Convert TOKEN:-shaped eprintln! sites to the single-write emitter.

Per-site and verified, never a sweep: 200 of the 487 calls span multiple lines,
so a regex over the file would mangle 41% of the population. This edits ONE
macro token per named site, after re-finding it from the census line, and
refuses anything it cannot place exactly.
"""
import re
import subprocess
import sys

ROOT = r"C:/Users/decid/Documents/projects/spt-core/.worktrees/emit-single-write"
SITES = r"C:/Users/decid/AppData/Local/Temp/claude/C--Users-decid-Documents-projects-spt-core/43af483b-6d22-46cb-9d99-8b7713a6ff46/scratchpad/cut-4d6007ac/census_sites.txt"
MACRO = re.compile(r"\b(eprintln!|eprint!)\s*\(")

crates = sys.argv[1:]
if not crates:
    sys.exit("usage: convert.py <crate> [crate...]")

rows = [l.split("\t") for l in open(SITES, encoding="utf-8").read().splitlines()]
rows = [r for r in rows if r[0].split("/")[1] in crates]

by_file = {}
for loc, tok, mac in rows:
    path, ln = loc.rsplit(":", 1)
    by_file.setdefault(path, []).append((int(ln), tok, mac))

converted = 0
for path, sites in sorted(by_file.items()):
    full = ROOT + "/" + path
    lines = open(full, encoding="utf-8", newline="").read().split("\n")
    # descending, so earlier line numbers stay valid
    for ln, tok, mac in sorted(sites, reverse=True):
        j = ln - 1
        start = None
        for k in range(j, max(-1, j - 5), -1):
            if MACRO.search(lines[k]):
                start = k
                break
        if start is None:
            sys.exit(f"REFUSE: no macro token within 5 lines above {path}:{ln} ({tok})")
        before = lines[start]
        new = MACRO.sub("spt_proto::emit_line_err!(", before, count=1)
        if new == before:
            sys.exit(f"REFUSE: substitution changed nothing at {path}:{start+1}")
        lines[start] = new
        converted += 1
        print(f"  {path}:{start+1}  {tok}")
    open(full, "w", encoding="utf-8", newline="").write("\n".join(lines))

print(f"converted {converted} sites across {len(by_file)} files in {crates}")
