#!/usr/bin/env python3
"""Close batch-127 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-127"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")

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

NOTES = (
    "LEXICAL: LANDSCAPE AND GEOGRAPHY (Patz §3.2.2 case tables, §3.3 location "
    "words, §4.1.4 locative/ablative/abessive/perlative examples, §5.6 spatial "
    "setting in narrative; dictionary.yaml land/water/location entries; cheatsheet "
    "Rule 85 draft). 50 rows, avg 2.98 Kuku words/row. DESIGN: deliberately short "
    "lexical-control rows, because this batch's job is to pin safe spatial nouns, "
    "location words, and local-case morphology before denser landscape narratives. "
    "CORE LEXICON: bubu country/ground/place; bana water; wawubaja river; yilki "
    "creek; jalun sea; jukar sand; madja rainforest/scrub; manjal mountain; "
    "jalkaraburr mountain peak; jalkar high bank; kangku valley/pass; jirka spring; "
    "janku hole; jalngarr flat rock; kulji stone; dajali deep water; yalkan shallow "
    "water; dulngku reef; balar high tide; ngajal low tide; yira tide. LOCATION "
    "WORDS: wangkar up/upriver, wangkarwangkar up there/above, bada down/downriver, "
    "badabada down there/underneath, ngundu close by/this side, ngubar other side of "
    "river, kudamundu behind, yarra that way. MORPHOLOGY: bubu-ngu and dulngku-ngu "
    "use u-final LOC -ngu; jukar-a uses single-r LOC -a; manjal-ba/yalkan-ba use "
    "consonant LOC -ba; jalun-bu is the attested sea-LOC; wawubaja-burr is PERL; "
    "bayan-muny/jalun-muny/ngubar-muny are ABL; badabada-mundu is ABESS. PROCESS "
    "NOTES: avoided productive new baral='road/path' rows because the corpus errata "
    "records a live dictionary/grammar conflict even though Patz has baral-darr in "
    "ex.397-398; used jina only as already-verified foot/track elsewhere, not in "
    "this batch. Lint caught and fixed two elder-surface traps before close: "
    "janji-ny -> janjin, wanarri-y -> wanarri. Review also tightened row 4's "
    "English to reflect emphatic -bi and row 50's dual-pronoun gloss for bula. "
    "Lint GREEN 6447 scanned; verified corpus now 6447."
)

LESSONS = [
    (
        "lexicon",
        "Bubu is the core spatial/cultural noun: ground, earth, place, and country. It must not be flattened to English 'dirt' when the context is descent-group country or belonging.",
        "cheatsheet Rule 85: bubu country/ground/place distinction.",
    ),
    (
        "morphology",
        "Local-case allomorphy is part of the lexical target: bubu-ngu and dulngku-ngu after u, jukar-a after single r, manjal-ba/yalkan-ba after consonants, and jalun-bu as the attested sea locative.",
        "cheatsheet Rule 85: landscape locative allomorphy grid.",
    ),
    (
        "syntax",
        "Kuku Yalanji location words are a closed class whose bare root can already be locative/directional: wangkar 'up', wangkarwangkar 'up there', bada 'down', badabada 'down there', ngundu 'close by', yarra 'that way'.",
        "cheatsheet Rule 85: location words behave differently from ordinary nouns.",
    ),
    (
        "morphology",
        "Ablative, abessive, and perlative must not be collapsed into generic English 'from/through': jalun-muny and ngubar-muny are source, badabada-mundu is action-from-location, and wawubaja-burr is traversal through the river.",
        "cheatsheet Rule 85: source/traversal spatial cases.",
    ),
    (
        "semantics",
        "The water vocabulary is layered: bana water, wawubaja river, yilki creek, jalun sea, dajali deep water, yalkan shallow water, dulngku reef, balar high tide, ngajal low tide, and yira tide itself.",
        "errata Batch-127: water and tide vocabulary inventory.",
    ),
    (
        "syntax",
        "Motion verbs in spatial setting keep their Patz perspective: dunga-y follows participant movement/departure, while kada-y frames motion toward a goal or arrival; exact rows from Patz were retained for river/creek movement.",
        "cheatsheet Rule 85: spatial motion with dunga-y/kada-y.",
    ),
    (
        "process",
        "Baral remains a documented road/path conflict: Patz grammar has baral-darr 'along the road', but the project errata warns against productive new baral-road rows. This batch avoided new baral use and records the reason.",
        "operator guide process note: prefer conflict-free spatial anchors unless an exact attested form is being quoted and documented.",
    ),
    (
        "process",
        "Surface-form review matters even on exact Patz evidence: analysis may retain janji-ny and wanarri-y, but elder surface must be janjin and wanarri. Row 4 and row 50 also show why English/gloss tightening belongs in the review pass.",
        "errata Batch-127: surface fixes and review-tightening notes.",
    ),
]

LEXEMES = [
    ("bubu", "noun", None, "neutral", "ground; earth; place; country", "batch-127: core country/ground/place lexeme; locative bubu-ngu"),
    ("bana", "noun", None, "neutral", "water; liquid", "batch-127: water lexeme; locative bana-nga"),
    ("wawubaja", "noun", None, "neutral", "river", "batch-127: river lexeme; locative wawubaja-nga, perlative wawubaja-burr"),
    ("yilki", "noun", None, "neutral", "creek", "batch-127: creek lexeme; locative yilki-nga"),
    ("jalun", "noun", None, "neutral", "sea", "batch-127: sea lexeme; ablative jalun-muny, locative jalun-bu"),
    ("jukar", "noun", None, "neutral", "sand", "batch-127: sand; single-r locative jukar-a"),
    ("madja", "noun", None, "neutral", "scrub; jungle; rainforest", "batch-127: rainforest/scrub; locative madja-nga"),
    ("manjal", "noun", None, "neutral", "mountain", "batch-127: mountain; locative manjal-ba"),
    ("jalkaraburr", "noun", None, "neutral", "mountain peak; high reaches of the mountains", "batch-127: mountain peak lexeme"),
    ("jalkar", "noun", None, "neutral", "high bank", "batch-127: high bank lexeme"),
    ("kangku", "noun", None, "neutral", "valley; low gap; mountain pass", "batch-127: valley/pass lexeme"),
    ("jamba", "noun", None, "neutral", "hillside", "batch-127: hillside; V-final locative jamba-nga"),
    ("jirka", "noun", None, "neutral", "spring; water source", "batch-127: spring/water-source lexeme"),
    ("janku", "noun", None, "neutral", "hole in the ground", "batch-127: hole-in-ground lexeme"),
    ("jalngarr", "noun", None, "neutral", "flat rock", "batch-127: flat-rock lexeme"),
    ("kulji", "noun", None, "neutral", "stone; rock; pebbles", "batch-127: stone/pebble lexeme"),
    ("dajali", "noun", None, "neutral", "deep water", "batch-127: deep-water lexeme; exact Patz dajali-mun-bu row"),
    ("yalkan", "noun/adjective", None, "neutral", "shallow water", "batch-127: shallow-water lexeme; locative yalkan-ba"),
    ("dulngku", "noun", None, "neutral", "reef", "batch-127: reef lexeme; u-final locative dulngku-ngu"),
    ("balar", "noun", None, "neutral", "high tide", "batch-127: tide lexeme; high tide"),
    ("ngajal", "noun", None, "neutral", "low tide", "batch-127: tide lexeme; low tide"),
    ("yira", "noun", None, "neutral", "tide; fruit juice", "batch-127: tide lexeme; water sense used"),
    ("wangkar", "locational", None, "NA", "up; upriver; inland", "batch-127: location word; bare form directional/locative"),
    ("wangkarwangkar", "locational", None, "NA", "up there; above", "batch-127: reduplicated location word, lexicalized solid form"),
    ("bada", "locational", None, "NA", "down; downriver; downhill", "batch-127: location word; directional down/downriver"),
    ("badabada", "locational", None, "NA", "down there; underneath", "batch-127: reduplicated location word, lexicalized solid form; abessive badabada-mundu"),
    ("ngundu", "locational", None, "NA", "close by; this side", "batch-127: location word; Patz ngundu jana-y pattern"),
    ("ngubar", "locational", None, "NA", "other side of the river", "batch-127: location word; ablative ngubar-muny"),
    ("kudamundu", "locational", None, "NA", "behind; last", "batch-127: location word; behind/from behind"),
    ("yarra", "locational", None, "NA", "that way; over there in that direction", "batch-127: general direction word, gesture-dependent in Patz"),
    ("janji-l", "verb-itr", "l", "NA", "bathe; swim", "batch-127: water activity; surface past janjin, analysis janji-ny"),
    ("mariji-y", "verb-itr", "y", "NA", "swim through or across water", "batch-127: Patz river perlative swim row"),
    ("dunga-y", "verb-itr", "y", "NA", "go; move from participant perspective", "batch-127: spatial motion verb with river/creek examples"),
    ("kada-y", "verb-itr", "y", "NA", "come; arrive toward goal", "batch-127: spatial motion verb with goal/arrival perspective"),
    ("kida-l", "verb-tr", "l", "NA", "sweep; scrape; remove", "batch-127: bubu kida-l ground-sweeping for camp"),
    ("wukurri-l", "verb-tr", "l", "NA", "follow; track; weave", "batch-127: followed from behind, kudamundu"),
    ("warri", "verb-itr", None, "NA", "run; fly", "batch-127: wanarri surface for reduplicated nonpast running"),
    ("julbarr", "adjective", None, "NA", "slippery", "batch-127: bubu julbarr-bi emphatic ground condition"),
    ("duna", "adjective", None, "NA", "wet", "batch-127: jukar duna, wet sand"),
]


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