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

NOTES = (
    "CONSTRUCTION: HANDLING ARGUMENT STRUCTURE AND CASE-FRAME ALTERNATIONS (Rule 96; Patz §3.2.1, §3.2.2, "
    "§4.1.4.4, §4.2.4.2-4, §4.3.1, §4.5.5, §4.9.2, §5.4.1). 50 rows. DESIGN: construction-control batch after "
    "Rule 95 handling lexicon. Vocabulary was deliberately kept familiar so the signal is grammar: ERG/ABS transitive "
    "frames, pronoun A behavior, O/LOC/recipient fronting, LOC:pt recipient with `dajil`, possessive-object giving "
    "(`ngamu-mu mayi dajin`), INST implements (`naybu-bu`, `kulji-bu`, `karra-bu`), predicate-vs-subject negation "
    "with `kari`, topic/agentless passive and reflexive `-ji-` where Patz gives close models, and same-agent/"
    "same-object handling sequences with repeated O omitted. SOURCE CAUTIONS: no table/gate/bucket/cassette/torch/"
    "brake/truck/motorcar/store rows; no productive antipassive generation; no unsupported passives for `dajil`, "
    "`yijarril`, `walngal`, or `wuljil`; `nanda-ji-y` surfaces as `nandaji` by final-y drop after i. Pre-close lint "
    "scanned 6997 rows with 0 issues; verified goal metric remained 6947 before close."
)

LESSONS = [
    ("case-frame", "Common-noun A takes ERG in handling transitives, but pronoun A remains nominative: `Dingkar-angka kalka manin` vs `Ngayu kalka manin`.", "cheatsheet Rule 96: ERG/ABS and pronoun A."),
    ("case-frame", "Object and locative fronting are information-structure choices, not new case frames: `Kalka dingkar-angka manin`, `Bubu-ngu dingkar-angka kulji yijarrin`.", "cheatsheet Rule 96: fronting."),
    ("case-frame", "`yijarril` and `buyandi-l` can both use LOC container/place targets, but `buyandi-l` should stay literal container placement.", "cheatsheet Rule 96: placement/container LOC."),
    ("case-frame", "`dajil` supports LOC:pt recipients and the special possessive-object construction: `Ngayu mayi ngamu-ndu dajin` vs `Ngayu ngamu-mu mayi dajin`.", "cheatsheet Rule 96: dajil recipient alternation."),
    ("case-frame", "Instrumental implements remain distinct from ERG agents in handling rows: `naybu-bu`, `kulji-bu`, `karra-bu`.", "cheatsheet Rule 96: instrumental implements."),
    ("syntax", "`kari` placement controls negation scope; predicate negation and subject-constituent negation should be taught as separate rows.", "cheatsheet Rule 96: kari scope."),
    ("voice", "Passive `-ji-` is source-shaped and semantically constrained; use close Patz models like `mani-ji-ny`, `karrba-ji-ny`, `yaka-ji-ny`, `nanda-ji-y`.", "cheatsheet Rule 96: passive constraints."),
    ("voice", "Reflexive/instrumental handling rows keep the affected person in S/ABS and the implement in INST: `Jalbu naybu-bu yakajin`.", "cheatsheet Rule 96: reflexive instrument."),
    ("morphology", "`nanda-ji-y` surfaces as `nandaji`; final `y` drops after `i`, matching the corpus lint rule.", "dictionary errata: nanda-ji-y surface."),
    ("syntax", "Same-agent/same-object handling sequences may introduce O once and omit it in following verbs: `kulji manin, yijarrin`; `nambarr kulban, kajan`.", "cheatsheet Rule 96: zero object in sequences."),
    ("process", "Do not create new `-ji-` voice forms just because English has a passive; require a close source model or defer.", "operator guide: passive rigor."),
    ("process", "Construction batches after lexical batches should reuse the lexicon and vary the grammar, not smuggle in unvetted lexical breadth.", "operator guide: construction-after-lexical cadence."),
]

LEXEMES = [
    ("handling-erg-abs", "construction", None, "NA", "ERG common-noun A plus ABS object in handling transitives", "batch-138: Dingkar-angka kalka manin; Karrkay-ngku mayi manin."),
    ("handling-pronoun-a", "construction", None, "NA", "nominative pronoun A in transitive handling clauses", "batch-138: Ngayu kalka manin."),
    ("handling-fronting", "construction", None, "NA", "object/locative/recipient fronting under localised highlighting", "batch-138: Kalka dingkar-angka manin; Bubu-ngu ... yijarrin."),
    ("handling-loc-placement", "construction", None, "NA", "LOC placement target for yijarril and buyandi-l", "batch-138: kurrma-nga, bubu-ngu, kurmun-ba."),
    ("dajil-loc-recipient", "construction", None, "NA", "dajil with LOC:pt recipient", "batch-138: ngamu-ndu, dingkar-anda, karrkay-anda, jalbu-ndu."),
    ("dajil-possessive-object", "construction", None, "NA", "dajil with possessive NP in O function", "batch-138: Ngayu ngamu-mu mayi dajin."),
    ("handling-instrumental", "construction", None, "NA", "INST implement in handling clauses", "batch-138: naybu-bu, kulji-bu, karra-bu."),
    ("kari-scope-handling", "construction", None, "NA", "kari scope contrast in handling predicates", "batch-138: jungkalu kari dumbarrin vs dingkar-angka kari jungkalu dumbarrin."),
    ("handling-topic-passive", "construction", None, "NA", "topic passive -ji- with patient S and agent LOC:pt", "batch-138: Warru wara-nda manijin; Karrkay bilngkumu-ndu karrbajin."),
    ("handling-agentless-passive", "construction", None, "NA", "agentless passive -ji- in handling/state rows", "batch-138: Minya yakajin; Kurmun nandaji nyiku."),
    ("handling-reflexive-instrument", "construction", None, "NA", "reflexive -ji- with implement retained in INST", "batch-138: Jalbu naybu-bu yakajin; Dingkar baduru-bu kajajin."),
    ("handling-sequence-zero-object", "construction", None, "NA", "same object omitted in sequential handling verbs", "batch-138: kulji manin, yijarrin; nambarr kulban, kajan."),
    ("nanda-ji-y", "verb-form", "intransitivized", "NA", "close-ITR-NONPAST surfaces as nandaji", "batch-138: fixed pre-close lint catch; final y drops after i."),
    ("buyandi-l", "verb-tr", "l", "NA", "put in container", "batch-138: container LOC case-frame contrast."),
    ("wuljil", "verb-tr", "l", "NA", "empty out; bail out", "batch-138: ABL source with buwun-muny and object/source fronting."),
]


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-138-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-138-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())
