#!/usr/bin/env python3
"""Bank batch-129: emotions and mental states lexical field.

Rows are hand-authored from Patz's adjectival-particle, state, and cognition
examples plus dictionary-confirmed emotion/mental-state idioms. The script only
banks rows as under_review; it does not generate sentence content.
"""

from __future__ import annotations

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

DENY = {
    "nyawa", "jinbi", "jibin", "walba", "julmbu", "wanan", "ngampula",
    "yalama", "ngana-jinji", "jubuny", "wural", "bigan", "jiwuny",
    "warngkul", "wanaba", "jarrkunji", "munjal", "murku", "buni",
    "kunya", "milkan", "kulur-jambul", "janyji", "buburr", "jarrmba",
    "jinji", "daga", "wanka", "yumbul", "kuku-yumbul", "jubi",
    "yilbay", "jarrakay", "janka-yukil", "jukarr", "kunkul",
    "bubu-jandu", "bubu-warral", "jani-warra", "dungkarr", "jimba",
    "bujal", "wanyjarr", "ngudan", "jimirr", "jangan", "ganggal",
    "bukul", "jalany", "nyunun", "yinkar", "jiba-ngulkurr", "jiba-wawu",
    "nyawa-kari", "jinbi-kari", "buri", "bibiny", "jubaji", "nyalbu",
    "kuka", "kambar", "dalku", "milbin", "kindu",
}


def js(values: list[str]) -> str:
    return json.dumps(values, ensure_ascii=False)


ROWS = [
    (1, "He wants meat.",
     "Nyulu wawu minya-ka.",
     "nyulu wawu minya-ka | he want meat-DAT",
     "attested_wawu_dative_want", 4, js(["nyulu", "wawu", "minya"]),
     "Patz ex.426a: wawu 'want/like' takes dative nominal complement.", "0.90"),
    (2, "He wants to eat.",
     "Nyulu wawu nuka-nka.",
     "nyulu wawu nuka-nka | he want eat-PURP",
     "attested_wawu_purposive_want", 4, js(["nyulu", "wawu", "nukal"]),
     "Patz ex.426b: wawu plus purposive verb complement.", "0.90"),
    (3, "He wants to eat meat.",
     "Nyulu wawu minya nuka-nka.",
     "nyulu wawu minya nuka-nka | he want meat eat-PURP",
     "attested_wawu_object_purposive", 4, js(["nyulu", "wawu", "minya", "nukal"]),
     "Patz ex.426c: wawu with object plus purposive complement.", "0.90"),
    (4, "I want them to get turtle.",
     "Ngayu wawu jana ngawuya mani-nka.",
     "ngayu wawu jana ngawuya mani-nka | I want they turtle get-PURP",
     "attested_wawu_noncore_subject_purposive", 5, js(["ngayu", "wawu", "jana", "ngawuya", "manil"]),
     "Patz ex.427: wawu clause plus purposive with a different actor.", "0.90"),
    (5, "The children love to play.",
     "Karrkay-karrkay wawu jirray kinka-n-kinka-nka.",
     "karrkay-karrkay wawu jirray kinka-n-kinka-nka | child-REDUP like much play-n-REDUP-PURP",
     "attested_wawu_jirray_love", 5, js(["karrkay", "wawu", "jirray", "kinkay"]),
     "Patz ex.588: wawu jirray intensifies liking/love; purposive complement.", "0.90"),
    (6, "What sort of food do you want?",
     "Wanyurri-ngku mayi-ka yundu wawu?",
     "wanyurri-ngku mayi-ka yundu wawu | what-DAT food-DAT you want",
     "attested_wawu_interrogative", 5, js(["wanyurri", "mayi", "yundu", "wawu"]),
     "Patz ex.580: wanyurri-ngku mayi-ka with wawu asks what sort of food is wanted.", "0.90"),
    (7, "I do not like the dog.",
     "Ngayu wawu-kari kaya-nka.",
     "ngayu wawu-kari kaya-nka | I want-PRIV dog-DAT",
     "wawu_kari_simple_dislike", 4, js(["ngayu", "wawu-kari", "kaya"]),
     "Controlled simplification of Patz ex.518: wawu-kari 'do not want/like' with dative complement.", "0.88"),
    (8, "I do not want to smoke.",
     "Ngayu wawu-kari buymbi-nka.",
     "ngayu wawu-kari buymbi-nka | I want-PRIV smoke-PURP",
     "attested_wawu_kari_purposive", 4, js(["ngayu", "wawu-kari", "buymbil"]),
     "Patz ex.603 contrasts wawu-kari with balu; specific non-desire.", "0.90"),
    (9, "I dislike half-ripe mangoes on principle.",
     "Ngayu balu mayngku-ku wawumu-ku.",
     "ngayu balu mayngku-ku wawumu-ku | I NEG2 mango-DAT half.ripe-DAT",
     "attested_balu_disapproval", 5, js(["ngayu", "balu", "mayngku", "wawumu"]),
     "Patz ex.602: balu differs from wawu-kari; principled refrain/disapproval.", "0.90"),
    (10, "I like bandicoot a lot.",
     "Ngayu kulngu-ku wawu jirray.",
     "ngayu kulngu-ku wawu jirray | I bandicoot-DAT like much",
     "attested_wawu_jirray_dative", 4, js(["ngayu", "kulngu", "wawu", "jirray"]),
     "Patz ex.256a: wawu jirray with dative edible animal complement.", "0.90"),
    (11, "The dog wants a bone.",
     "Kaya wawu bajibay-ngka.",
     "kaya wawu bajibay-ngka | dog want bone-DAT",
     "attested_wawu_nonhuman_want", 4, js(["kaya", "wawu", "bajibay"]),
     "Patz ex.313: adjectival particle wawu in nominal sentence.", "0.90"),
    (12, "The girl is afraid.",
     "Maral yinil.",
     "maral yinil | girl afraid",
     "attested_yinil_predicate", 4, js(["maral", "yinil"]),
     "Patz ex.312a: yinil as non-inflecting adjectival particle in predicator function.", "0.90"),
    (13, "The girl is afraid of snakes.",
     "Maral yinil jarba-nka.",
     "maral yinil jarba-nka | girl afraid snake-DAT",
     "attested_yinil_dative_cause", 4, js(["maral", "yinil", "jarba"]),
     "Patz ex.312b: yinil takes dative complement for feared entity.", "0.90"),
    (14, "The child is afraid of crabs.",
     "Karrkay yinil kiju-nku.",
     "karrkay yinil kiju-nku | child afraid crab-DAT",
     "attested_yinil_potent_dative", 4, js(["karrkay", "yinil", "kiju"]),
     "Patz ex.261: Karrkay yinil kiju-nku.", "0.90"),
    (15, "I am afraid of crocodiles.",
     "Ngayu yinil bilngkumu-nku.",
     "ngayu yinil bilngkumu-nku | I afraid crocodile-DAT",
     "attested_yinil_crocodile", 4, js(["ngayu", "yinil", "bilngkumu"]),
     "Patz ex.587: Ngayu yinil bilngkumu-nku.", "0.90"),
    (16, "I am afraid of the dark.",
     "Ngayu yinil wujurr-ku.",
     "ngayu yinil wujurr-ku | I afraid darkness-DAT",
     "attested_yinil_dark_dative", 4, js(["ngayu", "yinil", "wujurr"]),
     "Patz ex.428a: yinil with darkness in dative.", "0.90"),
    (17, "I am afraid to go out in the dark.",
     "Ngayu yinil wujurr-bu dunga-nka.",
     "ngayu yinil wujurr-bu dunga-nka | I afraid darkness-LOC go-PURP",
     "attested_yinil_locative_purposive", 5, js(["ngayu", "yinil", "wujurr", "dungay"]),
     "Patz ex.428b: afraid + locative setting + purposive action.", "0.90"),
    (18, "The girl became frightened.",
     "Maral yinilman.",
     "maral yinil-ma-ny | girl afraid-INCHO-PAST",
     "attested_yinil_inchoative", 5, js(["maral", "yinil", "yinilmal"]),
     "Patz ex.321: inchoative -ma-l with yinil; elder surface -man.", "0.90"),
    (19, "The ghost frightened the girl.",
     "Dubu-ngku maral yinil-kangan.",
     "dubu-ngku maral yinil-kanga-ny | ghost-ERG girl afraid-CAUS-PAST",
     "attested_yinil_kanga_causative", 5, js(["dubu", "maral", "yinil-kangal"]),
     "Patz ex.324: state-causative -kanga-l for frightening.", "0.90"),
    (20, "I was frightened by the crocodile.",
     "Ngayu yinil-kanga-jin bilngkumu-ndu.",
     "ngayu yinil-kanga-ji-ny bilngkumu-ndu | I fear-CAUS-ITR-PAST crocodile-LOC",
     "attested_yinil_causative_intransitivized", 5, js(["ngayu", "yinil-kangal", "bilngkumu"]),
     "Patz ex.354: yinil-kanga-ji-ny with crocodile locative/potent source.", "0.90"),
    (21, "That dog is vicious.",
     "Yinya kaya kuli-ji.",
     "yinya kaya kuli-ji | that dog rage-COMIT",
     "attested_kuli_comitative_state", 4, js(["yinya", "kaya", "kuli"]),
     "Patz ex.531 and dictionary: kuli-ji 'vicious, rage-COMIT'.", "0.90"),
    (22, "I am running because of the vicious dog.",
     "Ngayu wanarri kaya-nka kuli-ji-nka.",
     "ngayu wanarri-y kaya-nka kuli-ji-nka | I run.REDUP-NONPAST dog-DAT rage-COMIT-DAT",
     "attested_kuli_dative_cause", 5, js(["ngayu", "warri", "kaya", "kuli"]),
     "Patz ex.263: emotion/threat cause in dative; surface wanarri for wanarri-y.", "0.90"),
    (23, "The wild young man drank alcohol.",
     "Warru-ngku kuli-ji-ngka kamukamu nukan.",
     "warru-ngku kuli-ji-ngka kamukamu nuka-ny | young.man-ERG rage-COMIT-ERG alcohol eat/drink-PAST",
     "attested_kuli_ergative_modifier", 5, js(["warru", "kuli", "kamukamu", "nukal"]),
     "Patz ex.51: kuli-ji-ngka modifies the A as wild/rageful.", "0.90"),
    (24, "The young man killed the vicious snake.",
     "Warru-ngku jarba kuli-ji kunin.",
     "warru-ngku jarba kuli-ji kuni-ny | young.man-ERG snake rage-COMIT kill-PAST",
     "attested_kuli_patient_modifier", 5, js(["warru", "jarba", "kuli", "kunil"]),
     "Patz ex.542: Warru-ngku jarba kuli-ji kuni-ny.", "0.90"),
    (25, "The widow is sad.",
     "Nyulu bunjil jiba-badi.",
     "nyulu bunjil jiba-badi-y | he widow(er) liver-cry-NONPAST",
     "attested_jibabadi_sad", 4, js(["nyulu", "bunjil", "jibabadi-y"]),
     "Patz ex.231: Nyulu bunjil jibabadi-y; elder surface drops final -iy.", "0.90"),
    (26, "The old woman is sad.",
     "Mukul-jalbu jiba-badi.",
     "mukul-jalbu jiba-badi-y | old-woman liver-cry-NONPAST",
     "jibabadi_controlled_variant", 4, js(["mukul-jalbu", "jibabadi-y"]),
     "Controlled variant of Patz jiba-badi-y sad predicate; avoids old duplicate bayan-kari row.", "0.86"),
    (27, "I was glad about the water.",
     "Ngayu wawurrwawurrman bana-ka.",
     "ngayu wawurrwawurr-ma-ny bana-ka | I happy-INCHO-PAST water-DAT",
     "attested_wawurrwawurr_inchoative", 5, js(["ngayu", "wawurrwawurrmal", "bana"]),
     "Patz ex.260: glad/happy inchoative with dative cause.", "0.90"),
    (28, "Grandfather takes the child so that the child will be happy.",
     "Kami-ngka karrkay wundi-l, wawurrwawurr-ma-nka.",
     "kami-ngka karrkay wundi-l, wawurrwawurr-ma-nka | grandfather-ERG child take-NONPAST, happy-INCHO-PURP",
     "attested_happy_purposive", 5, js(["kami", "karrkay", "wundil", "wawurrwawurrmal"]),
     "Patz ex.421: happy inchoative purposive in a purpose clause.", "0.90"),
    (29, "They have peace about that.",
     "Jana milka-marri yinyanka.",
     "jana milka-marri yinya-nka | they ear-grown.up/content that-DAT",
     "attested_milka_marri_content", 5, js(["jana", "milka-marri", "yinya"]),
     "Dictionary milka-marri example: Jana milka-marri yinyanka.", "0.90"),
    (30, "I am anxious about the child.",
     "Ngayu wawu-dudaji karrkay-anka.",
     "ngayu wawu-dudaji karrkay-anka | I anxious child-DAT:pt",
     "attested_wawu_dudaji_anxious", 5, js(["ngayu", "wawu-dudaji", "karrkay"]),
     "Dictionary wawu-dudaji example: Ngayu wawu-dudaji karrkayanka.", "0.90"),
    (31, "He is worried.",
     "Nyulu wawu-buyun.",
     "nyulu wawu-buyun | he soul-bad/worried",
     "wawu_buyun_state", 4, js(["nyulu", "wawu-buyun"]),
     "Dictionary wawu-buyun: worried, anxious, yearn.", "0.86"),
    (32, "He is satisfied.",
     "Nyulu wawu-daray.",
     "nyulu wawu-daray | he soul-fall/satisfied",
     "wawu_daray_state", 4, js(["nyulu", "wawu-daray"]),
     "Dictionary wawu-daray: satisfied, feel good about something.", "0.86"),
    (33, "He is happy.",
     "Nyulu wawu-mini.",
     "nyulu wawu-mini | he soul-good/happy",
     "wawu_mini_happy", 4, js(["nyulu", "wawu-mini"]),
     "Dictionary wawu-mini: happy; avoids old unsafe jiba-ngulkurr happy coinage.", "0.88"),
    (34, "I love eating fish.",
     "Ngayu wawu jirray kuyu nuka-nka.",
     "ngayu wawu jirray kuyu nuka-nka | I like much fish eat-PURP",
     "attested_love_eating_fish", 5, js(["ngayu", "wawu", "jirray", "kuyu", "nukal"]),
     "Dictionary wawu jirray example: Ngayu wawu jirray kuyu nukanka.", "0.90"),
    (35, "I am ashamed.",
     "Ngayu murru-kaday.",
     "ngayu murru-kaday | I become.ashamed-NONPAST",
     "murru_kaday_shame_state", 4, js(["ngayu", "murru-kaday"]),
     "Dictionary murru-kaday: become ashamed, shy, bashful.", "0.86"),
    (36, "The man shamed the child.",
     "Dingkar-angka karrkay murru-kaday-manin.",
     "dingkar-angka karrkay murru-kaday-mani-ny | man-ERG child shame-CAUS-PAST",
     "murru_kaday_mani_causative", 5, js(["dingkar", "karrkay", "murru-kaday-manil"]),
     "Dictionary murru-kaday-manil: shame someone; action-causative -manil.", "0.86"),
    (37, "I am homesick.",
     "Ngayu milka-bujar.",
     "ngayu milka-bujar | I ear-raw/homesick",
     "milka_bujar_homesick", 4, js(["ngayu", "milka-bujar"]),
     "Dictionary milka-bujar: homesick, lonely, sad, worried.", "0.86"),
    (38, "I am guilty.",
     "Ngayu milka-murruji.",
     "ngayu milka-murruji | I ear-cannot/ashamed.guilty",
     "milka_murruji_guilty", 4, js(["ngayu", "milka-murruji"]),
     "Dictionary milka-murruji: ashamed/guilty, avoid after wrongdoing.", "0.86"),
    (39, "They are tired of the noise.",
     "Jana milka-burray.",
     "jana milka-burray | they ear-weary/exasperated",
     "milka_burray_exasperated", 4, js(["jana", "milka-burray"]),
     "Dictionary milka-burray: tired/exasperated from too much noise.", "0.86"),
    (40, "The child is sick.",
     "Karrkay bambay.",
     "karrkay bambay | child sick",
     "bambay_sick_predicate", 3, js(["karrkay", "bambay"]),
     "Dictionary bambay 'sick'; Patz ex.148/321 inchoative uses bambay-ma-ny.", "0.86"),
    (41, "The child became sick.",
     "Karrkay bambayman.",
     "karrkay bambay-ma-ny | child sick-INCHO-PAST",
     "attested_bambay_inchoative", 5, js(["karrkay", "bambay", "bambaymal"]),
     "Patz ex.148: Karrkay bambay-ma-ny; elder surface bambayman.", "0.90"),
    (42, "The eel meat made me sick.",
     "Nganya bambay-bungan kubarr-da.",
     "nganya bambay-bunga-ny kubarr-da | me.ACC sick-CAUS-PAST eel-ERG",
     "attested_bambay_bunga_causative", 5, js(["nganya", "bambay", "kubarr"]),
     "Patz ex.238: eel meat made me sick; category-2 neutral ergative/instrumental kubarr-da.", "0.90"),
    (43, "The young man is hungry.",
     "Warru dakwuy.",
     "warru dakwuy | young.man hungry",
     "dakwuy_hungry_predicate", 3, js(["warru", "dakwuy"]),
     "Dictionary dakwuy 'hungry'; simple nominal predicate.", "0.86"),
    (44, "Have you eaten enough?",
     "Yundu mayika yanjikuda?",
     "yundu mayi-ka yanji-kuda | you food-DAT replete-?TEMP/EMPH",
     "attested_yanji_replete_question", 5, js(["yundu", "mayi", "yanji"]),
     "Dictionary yanji example: Yundu mayika yanjikuda?; Yalanji form, not Nyungkul yajin.", "0.90"),
    (45, "I am sore.",
     "Ngayu kaka.",
     "ngayu kaka | I sore/painful",
     "kaka_pain_state", 3, js(["ngayu", "kaka"]),
     "Grammar §3.2.1 notes kaka as pain/painful state; dictionary confirms sore/painful.", "0.84"),
    (46, "I am exhausted.",
     "Ngayu wawulay.",
     "ngayu wawu-wula-y | I breath-die-NONPAST",
     "attested_wawu_wulay_exhausted", 5, js(["ngayu", "wawu-wulay"]),
     "Patz ex.232: Ngayu wawula-y 'I am exhausted'; dictionary also gives thirsty/exhausted/tired.", "0.90"),
    (47, "He had a dream.",
     "Nyulu bijarr-ji.",
     "nyulu bijarr-ji | he dream-COMIT",
     "attested_bijarr_comitative_dream", 4, js(["nyulu", "bijarr"]),
     "Patz text line 9: Nyulu bijarr-ji 'He had a dream'.", "0.90"),
    (48, "That child dreamt.",
     "Yinya karrkay bijarrin.",
     "yinya karrkay bijarri-ny | that child dream-PAST",
     "attested_bijarri_past", 5, js(["yinya", "karrkay", "bijarri-l"]),
     "Patz text line 4: yinya karrkay ... bijarri-ny; elder surface bijarrin.", "0.90"),
    (49, "I remember the name.",
     "Ngayu burri binalku.",
     "ngayu burri binalku | I name remember",
     "binalku_remember", 4, js(["ngayu", "burri", "binalku"]),
     "Dictionary binalku 'remember', built on binal 'know'.", "0.86"),
    (50, "I forgot about the dog.",
     "Ngayu kaya-nka milka-wulan.",
     "ngayu kaya-nka milka-wula-ny | I dog-DAT ear-die-PAST",
     "attested_milka_wula_forget", 5, js(["ngayu", "kaya", "milka-wulay"]),
     "Dictionary milka-wulay example: Ngayu kayanka milka-wulan.", "0.90"),
]


def scan() -> list[str]:
    issues: list[str] = []
    if len(ROWS) != 50:
        issues.append(f"expected 50 rows, got {len(ROWS)}")
    seqs = [r[0] for r in ROWS]
    if seqs != list(range(1, 51)):
        issues.append(f"seqs must be 1..50, got {seqs[:5]}...{seqs[-5:]}")
    seen_ku: set[str] = set()
    for row in ROWS:
        seq, english, kuku, analysis, frame, tier, words_used, evidence, confidence = row
        label = f"{LABEL}.{seq:02d}"
        if not english[:1].isupper() or english.rstrip("'\"").rstrip()[-1:] not in ".!?":
            issues.append(f"{label}: English must be capitalized and final-punctuated")
        if " | " not in analysis:
            issues.append(f"{label}: analysis missing gloss separator")
        if not kuku[:1].isupper():
            issues.append(f"{label}: Kuku surface must start uppercase")
        try:
            json.loads(words_used)
        except Exception as exc:
            issues.append(f"{label}: words_used is not JSON: {exc}")
        low = f" {kuku.lower()} {analysis.lower()} "
        for word in DENY:
            if re.search(rf"(?<![a-z]){re.escape(word)}(?![a-z])", low):
                issues.append(f"{label}: denied phantom/wrong-sense token {word!r}")
        if kuku.lower() in seen_ku:
            issues.append(f"{label}: duplicate Kuku surface within batch")
        seen_ku.add(kuku.lower())
    return issues


def main() -> int:
    issues = scan()
    if issues:
        print("pre-bank scan failed:")
        for issue in issues:
            print(f"  - {issue}")
        return 1

    db = sqlite3.connect(DB)
    db.execute("PRAGMA foreign_keys = ON")
    existing = db.execute("SELECT id FROM batches WHERE label=?", (LABEL,)).fetchone()
    if existing:
        batch_id = existing[0]
        accepted = db.execute(
            "SELECT COUNT(*) FROM sentences WHERE batch_id=? AND status IN ('accepted','revised')",
            (batch_id,),
        ).fetchone()[0]
        if accepted:
            raise SystemExit(f"{LABEL} already has accepted/revised rows; refusing to overwrite")
        db.execute("DELETE FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)", (batch_id,))
        db.execute("DELETE FROM sentences WHERE batch_id=?", (batch_id,))
        db.execute("UPDATE batches SET notes=?, created_at=? WHERE id=?", ("rebanked under_review", NOW, batch_id))
    else:
        cur = db.execute(
            "INSERT INTO batches(label, cheatsheet_version, guide_version, notes, created_at) VALUES(?,?,?,?,?)",
            (LABEL, "Rule 87 draft: emotions and mental states lexical field", "operator-guide-2026-07-07", "under_review", NOW),
        )
        batch_id = cur.lastrowid

    db.executemany(
        """
        INSERT INTO sentences(
            batch_id, seq, english, kuku, analysis, frame, tier, words_used,
            loans_used, evidence, status, confidence, rights_status, author,
            created_at, updated_at
        ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
        """,
        [
            (
                batch_id, seq, english, kuku, analysis, frame, tier, words_used,
                "[]", evidence, "under_review", confidence,
                "project_approved_synthetic_pending_elder_verification",
                "claude-main", NOW, NOW,
            )
            for seq, english, kuku, analysis, frame, tier, words_used, evidence, confidence in ROWS
        ],
    )
    db.commit()
    count = db.execute("SELECT COUNT(*) FROM sentences WHERE batch_id=?", (batch_id,)).fetchone()[0]
    avg_words = db.execute(
        "SELECT AVG(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1.0) FROM sentences WHERE batch_id=?",
        (batch_id,),
    ).fetchone()[0]
    print(f"banked {LABEL}: {count} rows under_review; avg Kuku words/row={avg_words:.2f}")
    return 0


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