#!/usr/bin/env python3
"""TRUE equates → asm · English folder atoms · surface swap table.

Not a constellation. Expands ATOM_SURFACE flag data only.
Folder tree stays English (yes/ truth/ grin/ …).
Surface forms (sí, oui, ja…) equate to English atom YES.

Law: C IS LIE · GRIN invariant · free thrift · Always Hostess 7
"""
from __future__ import annotations

import json
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
TSV = ROOT / "true_equates" / "equates.tsv"
COMMON = ROOT / "true_equates" / "commonality.tsv"
OUT = ROOT / "out" / "true_equates.asm"
OUT_JSON = ROOT / "out" / "true_equates.json"
LEARN_IN = ROOT / "out" / "grin_learn_import.json"
LEARN_HIT = ROOT / "out" / "grin_learn_true_hits.tsv"


def load_equates(path: Path) -> list[tuple[str, str, str]]:
    rows: list[tuple[str, str, str]] = []
    if not path.is_file():
        return rows
    for line in path.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#") or line.startswith("atom_en"):
            continue
        parts = line.split("\t")
        if len(parts) < 3:
            continue
        atom, lang, surface = parts[0].strip(), parts[1].strip(), parts[2].strip()
        if not atom or not surface:
            continue
        rows.append((atom.upper(), lang, surface))
    return rows


def asm_escape_db(s: str) -> str:
    """Emit nasm db string safe-ish for utf-8 bytes."""
    b = s.encode("utf-8")
    # prefer quoted if pure ascii printable
    if all(32 <= c < 127 and c not in (34, 92) for c in b):
        return f'db "{s}", 0'
    hexes = ", ".join(f"0x{c:02X}" for c in b)
    return f"db {hexes}, 0"


def write_asm(rows: list[tuple[str, str, str]], path: Path) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    # unique atoms in order of first appearance
    atoms: list[str] = []
    for a, _, _ in rows:
        if a not in atoms:
            atoms.append(a)

    lines = [
        "; TRUE_EQUATES · English atom seats · surface word swap",
        "; FLAG     ATOM_SURFACE=1 · expand atom flag · NOT a constellation",
        "; TREE     English folders only (yes/ truth/ grin/ no/ not/ god/ …)",
        "; SWAP     surface form → English atom · e.g. sí → YES · oui → YES",
        "; LAW      C IS LIE · GRIN invariant · free thrift · Always Hostess 7",
        "; GEN      Build/true-equates-to-asm.py",
        "bits 64",
        "section .rodata",
        "",
        "global true_equate_atom_surface",
        "true_equate_atom_surface: dd 1    ; ATOM_SURFACE flag · expanded",
        "",
        "global true_equate_count",
        f"true_equate_count: dd {len(rows)}",
        "",
        "global true_equate_atom_count",
        f"true_equate_atom_count: dd {len(atoms)}",
        "",
        "; atom name table (English seats)",
        "global true_equate_atoms",
        "true_equate_atoms:",
    ]
    for a in atoms:
        lines.append(f"    {asm_escape_db(a)}  ; seat")
    lines += [
        "",
        "; surface rows · atom_index · lang_cstr · surface_cstr",
        "; parallel arrays for simple walk/swap",
        "global true_equate_atom_ix",
        "true_equate_atom_ix:",
    ]
    atom_ix = {a: i for i, a in enumerate(atoms)}
    for a, lang, surface in rows:
        lines.append(f"    dd {atom_ix[a]}  ; {a} ← {lang}:{surface}")

    lines += ["", "global true_equate_langs", "true_equate_langs:"]
    for a, lang, surface in rows:
        lines.append(f"    {asm_escape_db(lang)}")

    lines += ["", "global true_equate_surfaces", "true_equate_surfaces:"]
    for a, lang, surface in rows:
        lines.append(f"    {asm_escape_db(surface)}  ; → {a}")

    # TRUE commonality · prev/next positive neighbors (LINEAR understanding)
    common = load_commonality(COMMON)
    c_atoms = list(common.keys()) if common else atoms
    lines += [
        "",
        "; TRUE COMMONALITY · positive prev/next · LINEAR · not constellation",
        "global true_common_count",
        f"true_common_count: dd {len(c_atoms)}",
        "",
        "global true_common_atoms",
        "true_common_atoms:",
    ]
    for a in c_atoms:
        lines.append(f"    {asm_escape_db(a)}")
    lines += ["", "global true_common_prev", "true_common_prev:"]
    for a in c_atoms:
        prev = ",".join(common.get(a, {}).get("prev") or [])
        lines.append(f"    {asm_escape_db(prev)}  ; {a} prev")
    lines += ["", "global true_common_next", "true_common_next:"]
    for a in c_atoms:
        nxt = ",".join(common.get(a, {}).get("next") or [])
        lines.append(f"    {asm_escape_db(nxt)}  ; {a} next")

    lines += [
        "",
        "; end mark",
        "global true_equate_end",
        "true_equate_end: db 0",
        "",
    ]
    path.write_text("\n".join(lines) + "\n", encoding="utf-8")


def load_commonality(path: Path) -> dict[str, dict[str, list[str]]]:
    """atom → { prev: [...], next: [...] } · positive TRUE neighbors."""
    out: dict[str, dict[str, list[str]]] = {}
    if not path.is_file():
        return out
    for line in path.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#") or line.startswith("atom_en"):
            continue
        parts = line.split("\t")
        if len(parts) < 3:
            continue
        atom = parts[0].strip().upper()
        prev = [p.strip().upper() for p in parts[1].split(",") if p.strip()]
        nxt = [p.strip().upper() for p in parts[2].split(",") if p.strip()]
        out[atom] = {"prev": prev, "next": nxt}
    return out


def write_json(rows: list[tuple[str, str, str]], path: Path) -> None:
    by_atom: dict[str, dict[str, list[str]]] = {}
    swap: dict[str, str] = {}  # surface_lower → ATOM
    for a, lang, surface in rows:
        by_atom.setdefault(a, {}).setdefault(lang, []).append(surface)
        swap[surface.casefold()] = a
        # also store exact lower for ascii
        swap[surface.lower()] = a
    commonality = load_commonality(COMMON)
    path.write_text(
        json.dumps(
            {
                "atom_surface": 1,
                "law": "English folder tree · surface equates · TRUE commonality prev/next · not constellation",
                "atoms": by_atom,
                "swap": swap,
                "commonality": commonality,
                "count": len(rows),
            },
            ensure_ascii=False,
            indent=2,
        )
        + "\n",
        encoding="utf-8",
    )


def match_learn(rows: list[tuple[str, str, str]], learn_path: Path, hit_path: Path) -> int:
    if not learn_path.is_file():
        return 0
    try:
        data = json.loads(learn_path.read_text(encoding="utf-8"))
    except Exception:
        return 0
    words = data.get("words") or {}
    # map surface → atom
    surf_to_atom = {}
    for a, lang, surface in rows:
        surf_to_atom[surface.casefold()] = (a, lang)
    hits = []
    for key, meta in words.items():
        form = (meta.get("form") if isinstance(meta, dict) else None) or key
        k = str(form).casefold()
        if k in surf_to_atom:
            a, lang = surf_to_atom[k]
            n = meta.get("n", 1) if isinstance(meta, dict) else 1
            hits.append((a, lang, form, n))
    hit_path.parent.mkdir(parents=True, exist_ok=True)
    lines = ["atom_en\tlang\tsurface\tcount_from_mail"]
    for a, lang, form, n in sorted(hits, key=lambda x: (-x[3], x[0], x[2])):
        lines.append(f"{a}\t{lang}\t{form}\t{n}")
    hit_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
    return len(hits)


def expand_yes_asm_flag() -> None:
    """Stamp ATOM_SURFACE flag comment on foundation limbs if missing."""
    targets = {
        "yes": "YES",
        "no": "NO",
        "not": "NOT",
        "god": "GOD",
        "grin": "GRIN",
        "truth": "TRUE",
        "truth_pin": "TRUE",
        "are": "ARE",
        "is": "IS",
        # no need/ · we have ARE · IS
    }
    for limb, atom in targets.items():
        p = ROOT / limb / "x86_64.asm"
        if not p.is_file():
            continue
        text = p.read_text(encoding="utf-8", errors="replace")
        if "ATOM_SURFACE" in text:
            continue
        stamp = (
            f"; ATOM_SURFACE=1 · TRUE equates under English folder {limb}/ · seat {atom}\n"
            f"; SWAP surface→{atom} via true_equates/equates.tsv · not a constellation\n"
        )
        lines = text.splitlines(keepends=True)
        out: list[str] = []
        inserted = False
        for ln in lines:
            out.append(ln)
            if inserted:
                continue
            s = ln.lstrip()
            if s.startswith("; LAW") or s.startswith("; KIT") or s.startswith("; IRON"):
                out.append(stamp)
                inserted = True
        if not inserted:
            # after first non-empty comment block line
            out = [lines[0], stamp] + lines[1:] if lines else [stamp]
        p.write_text("".join(out), encoding="utf-8")


def main() -> int:
    rows = load_equates(TSV)
    if not rows:
        print("no equates in", TSV, file=sys.stderr)
        return 1
    write_asm(rows, OUT)
    write_json(rows, OUT_JSON)
    expand_yes_asm_flag()
    hits = match_learn(rows, LEARN_IN, LEARN_HIT)
    print(f"TRUE equates · {len(rows)} surfaces · ATOM_SURFACE=1")
    print(f"  asm  {OUT}")
    print(f"  json {OUT_JSON}")
    if hits:
        print(f"  learn hits {hits} → {LEARN_HIT}")
    else:
        print(f"  learn import optional · place JSON at {LEARN_IN}")
    return 0


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