#!/usr/bin/env python3
"""ASCII normalization for the delivery. Word-level pre-passes, then a complete char map.
JSON files are parsed and rewritten so quote replacement cannot break syntax.
Fails loudly if any non-ASCII survives."""
import json
import re
import sys
from pathlib import Path

PRE = [
    ("AΩ", "AQ"),
    ("◐", "Mode"),
    (" →</a>", "</a>"), (" →</a>", "</a>"), (" ↗</a>", "</a>"), (" ↗</a>", "</a>"),
    ("Raw ↓</a>", "Raw</a>"),
    ("├──", "+--"), ("└──", "+--"), ("└─", "+-"), ("├─", "+-"),
    ("⟨", "("), ("⟩", ")"),
    ("2×", "2x"), ("×", "x"),
    ("≈", "~"), ("≠", "!="), ("≥", ">="), ("≤", "<="),
    ("±", "+/-"), ("…", "..."), ("§ ", "Sec. "), ("§", "Sec. "),
    ("€", "EUR "), ("²", "^2"), ("∃x P(x)", "'there exists x with P(x)'"), ("∃", "there-exists"),
    ("↔", "<->"), ("→", "->"), ("↓", "v"), ("↑", "^"), ("↗", ""),
    ("✓", "+"), ("•", "-"), ("‣", "-"),
    ("─", "-"), ("│", "|"), ("├", "+"), ("└", "+"),
    ("α≥", "alpha >= "), ("α", "alpha"), ("κ", "kappa"), ("λ", "lambda"), ("μ", "mu"),
    ("β", "beta"), ("ρ", "rho"), ("σ", "sigma"), ("Δ", "Delta"), ("Ω", "Omega"),
    ("—", " - "), ("–", "-"), ("‐", "-"), ("−", "-"),
    ("“", '"'), ("”", '"'), ("‘", "'"), ("’", "'"), ("′", "'"),
    (" ", " "), (" ", " "), ("​", ""), ("·", "-"),
    ("ö", "o"), ("é", "e"), ("ñ", "n"), ("á", "a"), ("í", "i"), ("ê", "e"), ("ó", "o"),
    ("ä", "a"), ("ü", "u"), ("â", "a"), ("è", "e"), ("à", "a"), ("î", "i"), ("ú", "u"),
    ("õ", "o"), ("å", "a"), ("ø", "o"), ("Ø", "O"), ("ç", "c"), ("š", "s"), ("č", "c"),
    ("Č", "C"), ("ř", "r"), ("ý", "y"), ("ī", "i"), ("ă", "a"), ("ą", "a"), ("ų", "u"),
    ("ė", "e"), ("ź", "z"), ("ś", "s"), ("ș", "s"), ("ț", "t"), ("ā", "a"), ("ě", "e"),
    ("ż", "z"), ("Ż", "Z"), ("ħ", "h"), ("ć", "c"), ("Ú", "U"), ("©", "(c)"), ("®", "(R)"),
    ("†", "*"), ("‡", "**"), ("‖", "||"), ("∈", " in "), ("∑", "sum"), ("∫", "integral"),
    ("∩", " intersect "), ("∣", "|"), ("∼", "~"), ("≫", ">>"), ("∞", "infinity"),
]


def collapse(text):
    text = re.sub(r"[ \t]{2,}", " ", text)
    text = re.sub(r" +\n", "\n", text)
    return text


def asciify_str(s):
    for old, new in PRE:
        if old in s:
            s = s.replace(old, new)
    # any residual non-ASCII: strict fold or fail
    out = []
    bad = set()
    for ch in s:
        if ord(ch) < 128:
            out.append(ch)
        else:
            bad.add(ch)
    if bad:
        raise ValueError(f"unmapped chars: {[f'U+{ord(c):04X} {c!r}' for c in sorted(bad)]}")
    return "".join(out)


def walk_json(x):
    if isinstance(x, dict):
        return {asciify_str(k): walk_json(v) for k, v in x.items()}
    if isinstance(x, list):
        return [walk_json(v) for v in x]
    if isinstance(x, str):
        return collapse(asciify_str(x))
    return x


def process(path: Path):
    raw = path.read_text(encoding="utf-8")
    if not any(ord(c) > 127 for c in raw):
        return False
    if path.suffix == ".json":
        data = json.loads(raw)
        path.write_text(json.dumps(walk_json(data), indent=2, ensure_ascii=True), encoding="utf-8")
    else:
        path.write_text(collapse(asciify_str(raw)), encoding="utf-8")
    return True


def main(paths):
    changed = 0
    for p in paths:
        p = Path(p)
        if process(p):
            changed += 1
    print(f"asciified {changed}/{len(paths)} files")


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