#!/usr/bin/env python3
"""Close batch-133 after main-loop five-lens 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-133"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
LENSES = ("morphology", "lexicon", "syntax", "fidelity", "register")

NOTES = (
    "LEXICAL: PLANTS, TREES, BARK, LEAVES, ROOTS, VINES, AND PLANT MATERIALS (Patz ex.524-526, "
    "ex.544-546, text 51 Leichhardt fruit passage, text 51 ground-oven bark/paperbark passage, "
    "dictionary flora entries). 50 rows. DESIGN: lexical-control batch after Rule 90 construction. "
    "CORE DISTINCTION: plant parts on a tree use locative (`juku-ngu`), while parts from/fallen/plucked from a tree "
    "use ablative (`juku-muny`), following Patz ex.524-525. INVENTORY: `juku` tree/wood, `birra` leaf/lung, "
    "`dakil` branch/arm/wing, `nganka` flower, `diburr` seed/egg, `ngara` root, `dingal` tree base, `dimbir` hollow "
    "trunk, `dumbul` bark/hard covering, `dubal` bark in the text 51 ground-oven passage, `jalban` tree top, `kabal` "
    "Leichhardt-tree fruit, `buyku` paperbark, `wanjakan` ti-tree, `warrur` tree bark usable as vine/fishnet material, "
    "`jaba` stick/sapling, `mawar` lawyer-cane vine, `waji-waji` stinging vine, `kunjarri` palm, `duwar` black palm, "
    "`dulmbil` umbrella palm, `wawuburra` cottontree, `bilar` candlenut tree, `yarun` black wattle, `yalngkal` white "
    "wattle, and `yumu` bottlebrush. SOURCE TENSIONS: dictionary headword is `jujabala` ironwood, while some living-book "
    "and grammar prose has `jujubala`; batch 133 used dictionary headword `jujabala` and logs the variant. `dumbul` and "
    "`dubal` are both attested in bark/hard-covering contexts but should not be blindly merged. Full corpus lint passed "
    "before close with 6747 rows scanned and 0 issues."
)

LESSONS = [
    ("morphology", "For plant parts on a tree, Patz ex.524 uses locative `juku-ngu`; for parts from/plucked/fallen from a tree, use ablative `juku-muny`.", "cheatsheet Rule 91: tree-part LOC vs ABL."),
    ("semantics", "`juku` covers tree/wood down to splinter; do not force separate English tree/timber/wood lexemes unless the dictionary gives a species or material word.", "cheatsheet Rule 91: juku scope."),
    ("lexicon", "Core plant-part inventory pinned: `birra` leaf, `dakil` branch, `nganka` flower, `diburr` seed, `ngara` root, `dingal` tree base, `dimbir` hollow trunk, `jalban` tree top.", "cheatsheet Rule 91: plant parts."),
    ("semantics", "`diburr` is seed in plant contexts and egg in animal contexts; a tree-source frame disambiguates the plant sense.", "errata Batch-133: diburr seed/egg context."),
    ("semantics", "`ngara` as plant root must be kept separate from `ngara-l` set up/build camp and from old wrong-sense hearing/listening drift.", "errata Batch-133: ngara root."),
    ("lexicon", "`dumbul` is dictionary bark/hard covering; `dubal` is Patz text 51 bark in the ground-oven passage. Both are logged; do not silently collapse them.", "errata Batch-133: dumbul/dubal bark split."),
    ("lexicon", "`kabal` Leichhardt-tree fruit has an extended text 51 passage; it is safe for fruit-finding, climbing, and eating frames.", "cheatsheet Rule 91: kabal text frame."),
    ("lexicon", "`buyku` paperbark is part of the ground-oven covering frame; it is not just generic bark.", "cheatsheet Rule 91: buyku paperbark."),
    ("lexicon", "`warrur` is tree bark usable as vine/fishnet material; keep it distinct from `warru` young man.", "errata Batch-133: warrur/warru distinction."),
    ("lexicon", "Dictionary headword `jujabala` ironwood conflicts with earlier `jujubala` spelling in prose/books. Batch 133 used `jujabala` and logs the variant instead of normalizing silently.", "errata Batch-133: jujabala/jujubala spelling tension."),
    ("process", "This was a lexical-control batch with short rows by design. The job was to pin safe flora/material forms before longer craft, food, and country narratives.", "operator guide: controlled lexical batch rationale."),
    ("process", "The living process log continues: source pass, rejected/source-tension decisions, lint, close, export, and live-doc verification must be stored outside the DB too.", "operator guide: process-log requirement."),
]

LEXEMES = [
    ("juku", "noun", None, "neutral", "tree; wood; splinter", "batch-133: generic tree/wood scope"),
    ("birra", "noun", None, "neutral", "leaf; lungs", "batch-133: leaf in plant-part frames"),
    ("dakil", "noun", None, "neutral", "arm; branch; wing", "batch-133: tree branch sense"),
    ("dakil-dakil", "noun", None, "neutral", "branches of a tree", "batch-133: plural/reduplicated branch form"),
    ("nganka", "noun", None, "neutral", "flower; blossom", "batch-133: flower on/from tree"),
    ("diburr", "noun", None, "neutral", "seed; egg", "batch-133: seed sense in tree-source frame"),
    ("ngara", "noun", None, "neutral", "root", "batch-133: plant root, not ngara-l build/listen drift"),
    ("dingal", "noun", None, "neutral", "base of a tree", "batch-133: tree base"),
    ("dimbir", "noun", None, "neutral", "hollow trunk of a tree", "batch-133: hollow trunk"),
    ("dumbul", "noun", None, "neutral", "bark; hard covering; crust; shell", "batch-133: dictionary bark/hard covering"),
    ("dubal", "noun", None, "neutral", "bark", "batch-133: Patz text 51 bark passage"),
    ("jalban", "noun", None, "neutral", "tree top", "batch-133: tree-top locative"),
    ("kabal", "noun", None, "neutral", "Leichhardt tree/fruit", "batch-133: text 51 fruit passage"),
    ("warrmba-bungal", "verb-tr", "l", "NA", "uncover; find by uncovering", "batch-133: kabal fruit finding frame"),
    ("buyku", "noun", None, "neutral", "paperbark", "batch-133: ground-oven covering"),
    ("wanjakan", "noun", None, "neutral", "ti tree", "batch-133: bark for roof/painting"),
    ("warrur", "noun", None, "neutral", "tree bark usable as vine/fishnet material", "batch-133: material lexeme"),
    ("jaba", "noun", None, "neutral", "stick; sapling; post; walking stick", "batch-133: sapling/stick"),
    ("jujabala", "noun", None, "neutral", "ironwood tree", "batch-133: dictionary spelling; compare jujubala variant"),
    ("nganjirr", "noun", None, "neutral", "grass tree", "batch-133: grass tree burned against thunder"),
    ("mawar", "noun", None, "neutral", "lawyer-cane vine", "batch-133: vine"),
    ("waji-waji", "noun", None, "neutral", "stinging vine", "batch-133: stinging vine"),
    ("kunjarri", "noun", None, "neutral", "palm; palm tree", "batch-133: palm"),
    ("duwar", "noun", None, "neutral", "black palm", "batch-133: black palm"),
    ("dulmbil", "noun", None, "neutral", "umbrella palm", "batch-133: umbrella palm"),
    ("wawuburra", "noun", None, "neutral", "cottontree", "batch-133: cottontree and canoe material"),
    ("bilar", "noun", None, "neutral", "candlenut tree; candlenut", "batch-133: canoe material/candlenut"),
    ("yarun", "noun", None, "neutral", "black wattle tree", "batch-133: wattle with flower"),
    ("yalngkal", "noun", None, "neutral", "white wattle", "batch-133: white wattle"),
    ("yumu", "noun", None, "neutral", "bottlebrush tree", "batch-133: bottlebrush"),
]


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