#!/usr/bin/env python3
"""Close batch-123 after main-loop review.

This script records five-lens review passes, captures the batch lessons and
lexeme updates, and promotes the already-banked rows from under_review to
accepted. It refuses to touch already accepted/revised rows.
"""

from __future__ import annotations

import datetime as dt
import json
import sqlite3
import sys

DB = "/mnt/donto-data/donto-resources/research/translation-training/kuku-yalanji-runpod-2026-06-30/synthetic/claude-synthetic-v1-2026-07-02/synthetic.db"
LABEL = "batch-123"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")

LENSES = ("morphology", "lexicon", "syntax", "fidelity", "register")

NOTES = (
    "LEXICAL: SPEECH, SOUND, NAMES & MESSAGE-CARRYING (dictionary.yaml + Patz grammar; "
    "cheatsheet Rule 81). 50 rows, avg 8.64 Kuku words/row. SPEECH: balka-l "
    "say/tell, balka-l-awa-l talk together, babaji-l ask with person asked in LOC "
    "and topic in DAT, kunja-l call/invite, yunga-l send a message, yayngkar-abu "
    "in a whisper, murru-kanga-l scold. HEARING/PERCEPTION: nyaji-l covers hear, "
    "see, and perceive; yanday-nyaji-l overhear; milka-dandi good memory/listener, "
    "milka-dudu deaf, milka-baka-l warn/remind, milka-wula-y forget. SOUND: "
    "wulngku badi sing, badi cry, yirrka-y shout, kuwimbur yirrka-y whistle, kadil "
    "sharp/crashing sound, yanja rustling noise, ngangkurr dog-bark, nyurra-baka "
    "too noisy. NAMES/TRUTH: burri name, dalki-l give a name, jurril/warmbiji "
    "lie, manubaja truth, manubaja-bunga-l believe. PHANTOM DISCIPLINE: no use of "
    "yalama as 'answer', no invented 'listen' imperative, no -karra plural outside "
    "kin terms, and yanja kept to rustling rather than stretched to generic noise. "
    "Lint GREEN 6247; verified corpus now 6247."
)

LESSONS = [
    (
        "syntax",
        "babaji-l 'ask' is not an English-shaped transitive frame: the person asked is LOCATIVE, while the subject asked about is DATIVE. This batch keeps that split visible in family and song questions.",
        "cheatsheet Rule 81: added the babaji-l LOC/DAT ask-frame under speech verbs.",
    ),
    (
        "lexicon",
        "nyaji-l remains a broad perception verb covering hear, see, and perceive. Hearing contexts must be created with audible objects such as wulngku, kuku, ngangkurr, yirrka-y, or badi rather than by inventing a separate 'listen' verb.",
        "cheatsheet Rule 81: nyaji-l hearing/perception note; errata: no invented listen imperative.",
    ),
    (
        "morphology",
        "The kinship plural -karra must stay inside the kinship domain. A drafted 'spears' form with -karra was rejected and replaced by ordinary singular topic marking.",
        "errata Batch-123: -karra out-of-domain plural warning.",
    ),
    (
        "lexicon",
        "yanja is a rustling noise term, especially grass/wind-like noise; it should not be generalized to any loud sound. For crashing/cutting/falling sound, use kadil; for dog-bark, ngangkurr; for human noise, nyurra-baka.",
        "cheatsheet Rule 81: sound-noun contrasts kadil / yanja / ngangkurr / nyurra-baka.",
    ),
    (
        "register",
        "The batch adds a high-value discourse register: asking elders, carrying messages between camps, naming children and places, teaching songs, warning children, speaking softly, and distinguishing truthful speech from lies.",
        "operator state: speech & sound lexical field covered by batch-123.",
    ),
]

LEXEMES = [
    ("babaji", "verb-tr", "y", "NA", "ask", "verified speech verb; person asked LOC, topic DAT"),
    ("balkal", "verb-tr", "l", "NA", "say; tell; make", "verified speech verb and addressee-DAT frame"),
    ("balkalaway", "verb-itr", "l", "NA", "talk together; discuss", "verified reciprocal speech verb"),
    ("badi", "verb-itr", "y", "NA", "cry; wail; sing; howl", "verified speech/sound verb"),
    ("burri", "noun", None, "neutral", "name; corroboree song", "verified name/song noun"),
    ("dalkil", "verb-tr", "l", "NA", "give a name; call by name", "verified naming verb"),
    ("jurril", "noun", None, "neutral", "lie; untruth", "verified truth/lie lexeme"),
    ("kadil", "noun", None, "neutral", "sharp or crashing sound", "verified sound noun"),
    ("kuku", "noun", None, "neutral", "word; language; news; story; law", "verified polysemous discourse noun"),
    ("kunjal", "verb-tr", "l", "NA", "call; summon; invite", "verified call/invite verb"),
    ("kuwimbur", "noun", None, "neutral", "whistle", "verified in collocation kuwimbur yirrka-y"),
    ("manubaja", "noun", None, "neutral", "truth", "verified truth lexeme"),
    ("manubaja-bungal", "verb-tr", "l", "NA", "believe", "verified truth/belief compound"),
    ("milka-bakal", "verb-tr", "l", "NA", "warn; remind; tempt", "verified warning/reminding verb"),
    ("milka-dandi", "adjective", None, "NA", "having a good memory; good listener", "verified milka compound"),
    ("milka-dudu", "adjective", None, "NA", "deaf", "verified milka compound"),
    ("milka-wulay", "verb-tr", "y", "NA", "forget", "verified memory verb"),
    ("murru-kangal", "verb-tr", "l", "NA", "scold; growl at", "verified speech-control verb"),
    ("ngangkurr", "noun", None, "neutral", "dog-bark; barking sound", "verified sound noun"),
    ("nyajil", "verb-tr", "l", "NA", "see; hear; perceive", "verified broad perception verb"),
    ("nyurra-baka", "adjective", None, "NA", "too noisy", "verified human-noise adjective"),
    ("warmbiji", "verb-itr", "y", "NA", "lie; prevaricate", "verified lie verb"),
    ("wulngku", "noun", None, "neutral", "song", "verified song noun"),
    ("yanja", "noun", None, "neutral", "rustling noise", "verified rustling sound noun"),
    ("yayngkar", "noun", None, "neutral", "whisper", "verified in instrumental yayngkar-abu"),
    ("yanday-nyajil", "verb-tr", "l", "NA", "overhear", "verified hearing compound"),
    ("yirrkay", "verb-itr", "y", "NA", "shout; cry out", "verified speech/sound verb"),
    ("yungal", "verb-tr", "y", "NA", "send", "verified message-carrying verb"),
]


def main() -> int:
    db = sqlite3.connect(DB)
    db.execute("PRAGMA foreign_keys = ON")
    db.execute("BEGIN")

    batch = db.execute("SELECT id FROM batches WHERE label=?", (LABEL,)).fetchone()
    if not batch:
        raise SystemExit(f"{LABEL} has not been banked")
    batch_id = batch[0]

    total, under_review, accepted = db.execute(
        """
        SELECT
          COUNT(*),
          COUNT(*) FILTER (WHERE status='under_review'),
          COUNT(*) FILTER (WHERE status IN ('accepted','revised'))
        FROM sentences
        WHERE batch_id=?
        """,
        (batch_id,),
    ).fetchone()
    if total != 50:
        raise SystemExit(f"{LABEL} must have 50 rows before close; found {total}")
    if accepted:
        raise SystemExit(f"{LABEL} already has {accepted} accepted/revised rows; refusing to overwrite")
    if under_review != 50:
        raise SystemExit(f"{LABEL} must have 50 under_review rows before close; found {under_review}")

    sentence_ids = [row[0] for row in db.execute("SELECT id FROM sentences WHERE batch_id=? ORDER BY seq", (batch_id,))]
    db.executemany("DELETE FROM reviews WHERE sentence_id=?", [(sid,) for sid in sentence_ids])

    review_rows = [
        (sid, 1, lens, "pass", None, None, "claude-main-five-lens", NOW)
        for sid in sentence_ids
        for lens in LENSES
    ]
    db.executemany(
        """
        INSERT INTO reviews(sentence_id, round, lens, verdict, issues, suggested_fix, reviewer, created_at)
        VALUES(?,?,?,?,?,?,?,?)
        """,
        review_rows,
    )

    db.executemany(
        """
        INSERT INTO lessons(batch_id, category, lesson, guide_change, created_at)
        VALUES(?,?,?,?,?)
        """,
        [(batch_id, category, lesson, guide_change, NOW) for category, lesson, guide_change in LESSONS],
    )

    for headword, pos, conj_class, case_class, gloss, note in LEXEMES:
        senses = json.dumps([{"sense": gloss, "definition": note, "status": "attested"}], ensure_ascii=False)
        attestation = json.dumps([{"source": LABEL, "ref": "five-lens close", "quote": note}], ensure_ascii=False)
        db.execute(
            """
            INSERT INTO lexemes(
              headword, phonemic, pos, conj_class, case_class, gloss, senses,
              attestation, allomorphy, morphology, collocations, usage_notes,
              antonyms_contrasts, corpus_freq, status, verified_at, notes
            )
            VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
            ON CONFLICT(headword) DO UPDATE SET
              verified_at=excluded.verified_at,
              status=CASE
                WHEN lexemes.status IN ('phantom-retired', 'watchlist') THEN lexemes.status
                ELSE 'verified'
              END,
              notes=CASE
                WHEN lexemes.notes IS NULL OR lexemes.notes='' THEN excluded.notes
                WHEN instr(lexemes.notes, ?) > 0 THEN lexemes.notes
                ELSE lexemes.notes || '; ' || excluded.notes
              END
            """,
            (
                headword, None, pos, conj_class, case_class, gloss, senses,
                attestation, None, None, None, note, None, 0, "verified", NOW,
                f"batch-123: {note}", "batch-123",
            ),
        )
        db.execute(
            "INSERT INTO lexeme_log(headword, action, detail, created_at) VALUES(?,?,?,?)",
            (headword, "batch-123-verify", note, NOW),
        )

    db.execute("UPDATE batches SET notes=? WHERE id=?", (NOTES, batch_id))
    db.execute("UPDATE sentences SET status='accepted', updated_at=? WHERE batch_id=?", (NOW, batch_id))

    db.commit()
    reviews = db.execute(
        "SELECT COUNT(*) FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)",
        (batch_id,),
    ).fetchone()[0]
    verified = db.execute("SELECT COUNT(*) FROM sentences WHERE status IN ('accepted','revised')").fetchone()[0]
    print(f"closed {LABEL}: 50 accepted rows, {reviews} review passes, verified corpus={verified}")
    return 0


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