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

NOTES = (
    "CONSTRUCTION: MOTION CASE-FRAME ALTERNATIONS (Rule 94; Patz local cases, Rule 60/62/85/90/93). "
    "50 rows. DESIGN: construction-control batch after the Rule 93 motion/travel lexical batch. Vocabulary was "
    "kept familiar so the signal is case-frame choice rather than new lexemes. COVERED: LOC as allative/goal "
    "(`wawubaja-nga dungan`, `bayan-ba walan`, `madja-nga walan`), ABL source (`wawubaja-muny kadan`, "
    "`juku-muny daran`, `bayan-muny wandin`), PERL traversal (`wawubaja-burr marijin`, `madja-burr dungan`, "
    "`bana-burr marra-warrin`), COMIT accompaniment/tool (`kaya-nji`, `kalka-ji`, `jawun-unji`), PRIV absence "
    "(`kaya-kari`, `kalka-kari`, `jawun-kari`), ABESS fixed-vantage source (`wangkar-mundu`, `badabada-mundu`), "
    "purposive `-nka` after motion goals, transfer/escort DAT goals, LOC impact goal (`jina-nga`), and motion "
    "`-baja` return/back. SOURCE CAUTIONS: `baral` remains blocked; vehicle-loan rows deferred; ABESS `-mundu` "
    "is not privative; LOC/allative goal and DAT/purpose are kept distinct. Pre-close lint scanned 6897 rows "
    "with 0 issues; verified goal metric remained 6847 before close."
)

LESSONS = [
    ("case-frame", "LOC is the normal allative/goal case for motion to places: `wawubaja-nga dungan`, `bayan-ba walan`, `madja-nga walan`.", "cheatsheet Rule 94: LOC/allative goal."),
    ("case-frame", "ABL `-muny` marks motion source/from: `wawubaja-muny kadan`, `bayan-muny wandin`, `juku-muny daran`.", "cheatsheet Rule 94: ABL source."),
    ("case-frame", "PERL `-burr` marks traversal through/across/along a path in the project convention: `wawubaja-burr marijin`, `madja-burr dungan`, `bana-burr marra-warrin`.", "cheatsheet Rule 94: PERL traversal."),
    ("case-frame", "COMIT marks accompaniment or carried/equipped association in motion rows: `kaya-nji`, `kalka-ji`, `jawun-unji`, `mayi-ji`.", "cheatsheet Rule 94: COMIT accompaniment."),
    ("case-frame", "PRIV `-kari` is the 'without' construction. Do not use ABESS `-mundu` for absence.", "cheatsheet Rule 94: PRIV vs ABESS."),
    ("case-frame", "ABESS `-mundu` marks fixed vantage/source, as in `wangkar-mundu` and `badabada-mundu`; it is distinct from ABL source left behind.", "cheatsheet Rule 94: ABESS vantage."),
    ("case-frame", "A motion goal and a purposive complement can co-occur: `wawubaja-nga dungan kuyu dama-nka`; LOC is the place, `-nka` is the purpose.", "cheatsheet Rule 94: goal plus purpose."),
    ("case-frame", "Transfer/escort rows can combine motion with DAT goals: `bayan-ka wundin`, `bana-ka barrman`; keep them separate from LOC-place goals.", "cheatsheet Rule 94: DAT transfer/escort goal."),
    ("case-frame", "A complete route can stack source, path, and goal: `bayan-muny madja-burr wawubaja-nga dungan`.", "cheatsheet Rule 94: source-path-goal chain."),
    ("case-frame", "Motion `-baja` continues to mean back/again/on-again; it is not the adjective degree use of `-baja`.", "cheatsheet Rule 94: motion -baja."),
    ("process", "A construction batch after a lexical batch should reuse the new lexicon but keep rows short and contrastive.", "operator guide: construction after lexical cadence."),
    ("process", "`baral` remains blocked in new rows even though Patz has road examples; use route/case frames that do not depend on the unresolved lexeme.", "dictionary errata: baral remains blocked."),
]

LEXEMES = [
    ("-nga/-ba/-ngu", "suffix", None, "NA", "locative/allative goal allomorphs", "batch-136: LOC marks place at/in/on and goal of motion."),
    ("-muny", "suffix", None, "NA", "ablative source/from", "batch-136: ABL source in motion and fall/emerge rows."),
    ("-burr", "suffix", None, "NA", "perlative through/along/across", "batch-136: PERL traversal through river, scrub, grass, water."),
    ("-ji/-nji", "suffix", None, "NA", "comitative with/having", "batch-136: COMIT accompaniment/tool/carried association in motion rows."),
    ("-kari", "suffix", None, "NA", "privative without/lacking", "batch-136: PRIV absence of dog, spear, food, friend."),
    ("-mundu", "suffix", None, "NA", "abessive fixed vantage/source", "batch-136: ABESS vantage in wangkar-mundu and badabada-mundu."),
    ("-nka", "suffix", None, "NA", "purposive verb complement", "batch-136: motion-goal plus purpose rows with mani-nka, nuka-nka, dama-nka, nyaji-nka."),
    ("-baja", "suffix", None, "NA", "motion back/again/on-again", "batch-136: return/back rows with kadan-baja, dungan-baja, warrin-baja."),
    ("wawubaja", "noun", None, "neutral", "river", "batch-136: LOC, ABL, and PERL contrast on one place noun."),
    ("bayan", "noun", None, "neutral", "house; camp", "batch-136: LOC goal, ABL source, DAT transfer goal."),
    ("madja", "noun", None, "neutral", "scrub; rainforest", "batch-136: LOC goal, ABL source, PERL path."),
    ("juku", "noun", None, "neutral", "tree; wood", "batch-136: LOC climb, ABL source/fall, behind-source frame."),
    ("bana", "noun", None, "neutral", "water", "batch-136: PERL water traversal and DAT escort goal."),
    ("kudamundu", "locational", None, "NA", "behind; last", "batch-136: behind/following and behind-ABL source."),
    ("jawun", "noun", None, "both", "friend; family member", "batch-136: human companion COMIT/PRIV contrast."),
    ("jina", "noun", None, "neutral", "foot", "batch-136: LOC impact goal in drop row."),
]


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, LABEL,
            ),
        )
        db.execute(
            "INSERT INTO lexeme_log(headword, action, detail, created_at) VALUES(?,?,?,?)",
            (headword, "batch-136-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]
    lesson_count = db.execute("SELECT COUNT(*) FROM lessons WHERE batch_id=?", (batch_id,)).fetchone()[0]
    lexeme_logs = db.execute("SELECT COUNT(*) FROM lexeme_log WHERE action='batch-136-verify'").fetchone()[0]
    print(
        f"closed {LABEL}: 50 accepted rows, {reviews} review passes, "
        f"{lesson_count} lessons, {lexeme_logs} lexeme/source-log rows, verified corpus={verified}"
    )
    return 0


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