#!/usr/bin/env python3
"""Close batch-331 after main-loop five-lens review."""

from __future__ import annotations

import datetime as dt
import json
import sqlite3

from process_ledger import ensure_schema, record_event

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-331"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-331-visible-traditional-weapon-tool-singular-pronoun-nonpast-perception-after-rule288-process.md"
LENSES = ("morphology", "lexicon", "syntax", "fidelity", "register")

NOTES = (
    "VISIBLE TRADITIONAL WEAPON/TOOL SINGULAR-AND-THIRD PRONOUN NONPAST PERCEPTION SWEEP AFTER RULE 288 "
    "(Rule 289). 50 rows. TARGETS: bangkal tongs, kurrajan spear point, dara bamboo spear stick, jaba stick, "
    "kunjuri shield, nambarr bamboo stick, wangal boomerang, manbir spear barb, wakay wooden sword, and wulburr "
    "bamboo spear stick. SUPPORT: bare nominative ngayu, yundu, nyulu, bula, and jana plus yaluy/yinyay and nyajil. "
    "FRAMES: Ngayu TARGET yaluy nyajil, Yundu TARGET yinyay nyajil, Nyulu TARGET yaluy nyajil, Bula TARGET yinyay "
    "nyajil, and Jana TARGET yaluy nyajil. REVIEW: prior collided heads durray, jinil, mirru, kurajan, ngurmu, "
    "birungubay and Nyungkal-labelled biyul stayed excluded. No cooking, earth-oven/vine source, turtle spearing, "
    "fire-hardening, nose-piercing, weapon use, throwing, hunting, fighting, piercing, cutting, material-source, "
    "target case, pronoun case, demonstrative case, target compound, productive reduplication, perception compound, "
    "past/purposive/reduplicated perception drift, support inflection, or carried water/landform/sky/fire/fauna/body/"
    "dwelling drift was opened."
)

LESSONS = [
    ("source", "Rule 289 selected ten visible traditional weapon/tool target heads: bangkal, kurrajan, dara, jaba, kunjuri, nambarr, wangal, manbir, wakay, and wulburr.", "Rule 289: visible target inventory."),
    ("source", "Direct dictionary line readback was explicit: bangkal 1478-1489, kurrajan 16196-16207, dara 5215-5226, jaba 6843-6857, kunjuri 15915-15923, nambarr 21516-21526, wangal 25943-25951, manbir 17699-17707, wakay 25192-25202, and wulburr 27767-27776.", "Rule 289: dictionary source lines."),
    ("source", "Patz grammar lines 2577-2586 and 2592-2603 supplied the personal pronoun table and base forms for bare nominative ngayu, yundu, nyulu, bula, and jana.", "Rule 289: pronoun source."),
    ("source", "Patz grammar lines 2674-2686 supplied the non-singular person/number contrasts used here for bula third dual and jana third plural.", "Rule 289: non-singular source."),
    ("source", "Patz Table 3.12 lines 2838-2845 supplied Yalanji yaluy 'here' and yinyay 'there'; Rule 289 used only bare local demonstratives.", "Rule 289: demonstrative source."),
    ("source", "Patz section 3.8.3.2 lines 3043-3049 supplied nyaji-l 'see'; Rule 289 used corpus-conventional nyajil as the nonpast visual-perception surface only.", "Rule 289: nonpast perception source."),
    ("source", "Rule 289 deliberately excluded Nyungkal-labelled biyul, using Yalanji-safe kurrajan and kurrajan's separate dictionary entry instead.", "Rule 289: dialect restraint."),
    ("process", "Rule 289 was scoped as a fresh lexical-field audit after the Rule 285-288 artefact/tool consolidation cycle, not as another extension of the prior ten-head set.", "Rule 289: fresh lexical audit."),
    ("process", "Exact preflight found prior collisions for durray, jinil, mirru, kurajan, and ngurmu in Batches 231/232; those heads were replaced before banking.", "Rule 289: collision replacement."),
    ("process", "Final preflight over the 50 traditional weapon/tool surfaces returned 50 unique strings and no accepted, revised, or under-review collisions.", "Rule 289: duplicate preflight."),
    ("process", "Token-aware target coverage before banking after Rule 288 was bangkal 94, kurrajan 8, dara 12, jaba 29, kunjuri 37, nambarr 7, wangal 52, manbir 0, wakay 1, and wulburr 1.", "Rule 289: target coverage audit."),
    ("process", "Support coverage before banking after Rule 288 was ngayu 1211, yundu 807, nyulu 482, bula 278, jana 993, yaluy 3042, yinyay 3344, and nyajil 3197 by words_used JSON.", "Rule 289: support coverage audit."),
    ("lexicon", "Bangkal remained visible tongs only; cooking, kurrma earth-oven, voya vine, gathering, and action rows stayed closed.", "Rule 289: bangkal."),
    ("lexicon", "Kurrajan remained visible spear point only; turtle spearing, wattle source, fire-hardening, piercing, and use rows stayed closed.", "Rule 289: kurrajan."),
    ("lexicon", "Dara remained visible bamboo spear stick only; spear use, bamboo-source, hunting, fighting, throwing, and material-source rows stayed closed.", "Rule 289: dara."),
    ("lexicon", "Jaba remained visible stick only; sapling, post, horn, walking-use, and plant rows stayed closed.", "Rule 289: jaba."),
    ("lexicon", "Kunjuri remained visible shield only; fighting, defence, body-covering, ownership, and weapon-use rows stayed closed.", "Rule 289: kunjuri."),
    ("lexicon", "Nambarr remained visible bamboo stick only; nose-piercing and implement-use rows stayed closed.", "Rule 289: nambarr."),
    ("lexicon", "Wangal remained visible boomerang only; throwing, hunting, fighting, play, return, and travel rows stayed closed.", "Rule 289: wangal."),
    ("lexicon", "Manbir remained visible spear barb only; stabbing, hooking, piercing, injury, spear-use, and component-manufacture rows stayed closed.", "Rule 289: manbir."),
    ("lexicon", "Wakay remained visible wooden sword only; people-group source prose, fighting, cutting, and use rows stayed closed.", "Rule 289: wakay."),
    ("lexicon", "Wulburr remained visible bamboo spear stick only; spear use, bamboo-source, hunting, fighting, throwing, and material-source rows stayed closed.", "Rule 289: wulburr."),
    ("morphology", "All Rule 289 target nouns stayed bare: no LOC, DAT, ABL, PERL, ERG, INST, COMIT, POSS, PRIV, EXCESS, plural, derivation, or target suffix was admitted.", "Rule 289: bare targets."),
    ("morphology", "The subject support forms stayed bare nominatives: ngayu, yundu, nyulu, bula, and jana were not inflected for accusative, dative, locative, ablative, comitative, or possessive.", "Rule 289: bare nominative pronouns."),
    ("morphology", "Yaluy, yinyay, and nyajil stayed uninflected support heads; no demonstrative case, local-derived form, past nyajin, purposive nyaji-nka, reduplicated watching form, or support suffix was admitted.", "Rule 289: uninflected support."),
    ("morphology", "No target compound, object-use construction, material-source construction, place-name compound, pronoun-case construction, or productive reduplication was built from the Rule 289 heads.", "Rule 289: no compounds or reduplication."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yaluy nyajil for first singular here nonpast visual perception.", "Rule 289: 1sg here band."),
    ("syntax", "Rows 11-20 used Yundu TARGET yinyay nyajil for second singular there nonpast visual perception.", "Rule 289: 2sg there band."),
    ("syntax", "Rows 21-30 used Nyulu TARGET yaluy nyajil for third singular here nonpast visual perception.", "Rule 289: 3sg here band."),
    ("syntax", "Rows 31-40 used Bula TARGET yinyay nyajil for third dual there nonpast visual perception.", "Rule 289: 3du there band."),
    ("syntax", "Rows 41-50 used Jana TARGET yaluy nyajil for third plural here nonpast visual perception.", "Rule 289: 3pl here band."),
    ("fidelity", "English stayed literal visual nonpast perception/reference prose: selected subject pronoun value, target label, here/there, and see only.", "Rule 289: literal English."),
    ("fidelity", "The batch did not convert dictionary source prose into cooking, vine source, earth-oven use, turtle spearing, fire-hardening, nose-piercing, throwing, hunting, fighting, piercing, cutting, ownership, place, story, or use claims.", "Rule 289: source-prose restraint."),
    ("register", "Rows remained plain elicitation-style visual nonpast perception clauses; no action narrative, object-use instruction, weapon account, manufacturing prose, warning, mythic narrative, or story register was introduced.", "Rule 289: register."),
    ("process", "Rules 149-288 carry-forward traps stayed closed, especially recent artefact/tool perception traps plus older sky, water/landform, fire, fauna, body, dwelling, source-prose, homograph, target-case, pronoun-case, demonstrative-case, perception-compound, target-compound, productive-reduplication, and support-inflection traps.", "Rule 289: carry-forward closure."),
    ("handoff", "Next batch may continue from 16,647 if this closes; do not infer weapon action, cooking, turtle spearing, material source, nose piercing, target case, pronoun case, perception compound, past/purposive/reduplicated perception, productive reduplication, or support-inflection grammar from Rule 289.", "Rule 289: next cadence."),
]

LEXEMES = [
    ("bangkal", "noun", None, "NA", "tongs", "batch-331: visible tongs nonpast perception/reference only; cooking, vine, kurrma, and action rows closed."),
    ("kurrajan", "noun", None, "NA", "spear point", "batch-331: visible spear-point nonpast perception/reference only; turtle-spearing, wattle, fire-hardening, piercing, and use rows closed."),
    ("dara", "noun", None, "NA", "bamboo spear stick", "batch-331: visible bamboo-spear-stick nonpast perception/reference only; spear-use and material-source rows closed."),
    ("jaba", "noun", None, "NA", "stick", "batch-331: visible stick nonpast perception/reference only; sapling, post, horn, walking-use, and plant rows closed."),
    ("kunjuri", "noun", None, "NA", "shield", "batch-331: visible shield nonpast perception/reference only; fighting, defence, body-covering, ownership, and use rows closed."),
    ("nambarr", "noun", None, "NA", "bamboo stick", "batch-331: visible bamboo-stick nonpast perception/reference only; nose-piercing and implement-use rows closed."),
    ("wangal", "noun", None, "NA", "boomerang", "batch-331: visible boomerang nonpast perception/reference only; throwing, hunting, fighting, play, return, and travel rows closed."),
    ("manbir", "noun", None, "NA", "spear barb", "batch-331: visible spear-barb nonpast perception/reference only; stabbing, hooking, piercing, injury, spear-use, and manufacture rows closed."),
    ("wakay", "noun", None, "NA", "wooden sword", "batch-331: visible wooden-sword nonpast perception/reference only; people-group source prose, fighting, cutting, and use rows closed."),
    ("wulburr", "noun", None, "NA", "bamboo spear stick", "batch-331: visible bamboo-spear-stick nonpast perception/reference only; spear-use and material-source rows closed."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-331: bare nominative subject support only."),
    ("yundu", "pronoun", None, "NA", "second singular nominative", "batch-331: bare nominative subject support only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-331: bare nominative subject support only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-331: bare nominative subject support only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-331: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-331: bare local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-331: bare local demonstrative support only."),
    ("nyajil", "verb", "l", "NA", "see", "batch-331: nonpast visual perception support only, corpus-conventional surface from nyaji-l see-NONPAST."),
]


def main() -> int:
    db = sqlite3.connect(DB)
    db.execute("PRAGMA foreign_keys = ON")
    db.execute("BEGIN")
    ensure_schema(db)
    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 or under_review != 50 or accepted:
        raise SystemExit(f"{LABEL} close precheck failed: total={total}, under_review={under_review}, accepted={accepted}")

    total_rows = db.execute("SELECT COUNT(*) FROM sentences WHERE status!='rejected'").fetchone()[0]
    verified_before, words_before = db.execute(
        """
        SELECT COUNT(*), SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1)
        FROM sentences
        WHERE status IN ('accepted','revised')
        """
    ).fetchone()
    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.execute("DELETE FROM lessons WHERE batch_id=?", (batch_id,))
    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-331-verify", note, NOW),
        )

    record_event(db, batch_label=LABEL, phase="lint", event_type="under-review-lint-green", actor="claude-main", detail=f"After banking, lint scanned {total_rows} rows and found 0 issues; verified total remained {verified_before} before close.", command="python3 lint_corpus.py", output_excerpt=f"lint: {total_rows} rows scanned, 0 issues flagged; GOAL METRIC: {verified_before} / 20000 verified sentences ({words_before or 0} Kuku words)", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="review", event_type="five-lens-pass", actor="claude-main", detail="Manual five-lens review passed all 50 Rule 289 rows. Morphology checked bare traditional weapon/tool nouns, bare nominative ngayu/yundu/nyulu/bula/jana, bare yaluy/yinyay, and nyajil nonpast only. Lexicon checked selected visible target senses only, with bangkal cooking/vine, kurrajan turtle/fire/piercing, dara/wulburr use/source, jaba sapling/post/horn, kunjuri defence/use, nambarr nose-piercing, wangal throwing/hunting, manbir injury/use, and wakay fighting/cutting extensions closed. Syntax checked five pronoun-perception frame bands. Fidelity checked literal visual nonpast reference/perception English. Register stayed plain elicitation-style.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="review", event_type="review-detail", actor="claude-main", detail="Final review retained no collided durray/jinil/mirru/kurajan/ngurmu/birungubay heads, Nyungkal biyul, cooking, earth-oven/vine source, turtle spearing, fire-hardening, nose-piercing, weapon use, throwing, hunting, fighting, piercing, cutting, target case, productive compound, productive reduplication, demonstrative case, pronoun case, perception compound, past/purposive/reduplicated perception drift, support inflection, or recent water/landform/sky/fire/fauna/body/dwelling drift.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="review", event_type="lesson-inventory", actor="claude-main", detail=f"Inserted {len(LESSONS)} Rule 289 lessons covering source checks, dialect restraint, duplicate avoidance, lexical field scope, coverage, lexical target senses, morphology, syntax, fidelity, register, process traps, and handoff.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="review", event_type="lexeme-source-log", actor="claude-main", detail=f"Inserted {len(LEXEMES)} lexeme/source-log rows for Rule 289 targets and support heads.", artifact_path=PROCESS_LOG, created_at=NOW)
    db.execute("UPDATE sentences SET status='accepted', updated_at=? WHERE batch_id=?", (NOW, batch_id))
    db.execute("UPDATE batches SET notes=?, cheatsheet_version=?, guide_version=? WHERE id=?", (NOTES, "Rule 289 accepted", "operator-guide-2026-07-09", batch_id))
    verified_after, words_after = db.execute(
        """
        SELECT COUNT(*), SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1)
        FROM sentences
        WHERE status IN ('accepted','revised')
        """
    ).fetchone()
    accepted_after = db.execute("SELECT COUNT(*) FROM sentences WHERE batch_id=? AND status='accepted'", (batch_id,)).fetchone()[0]
    review_count = db.execute("SELECT COUNT(*) FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)", (batch_id,)).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-331-verify'").fetchone()[0]
    record_event(db, batch_label=LABEL, phase="close", event_type="close-success", actor="claude-main", detail=f"Closed Batch 331 / Rule 289 with {accepted_after} accepted rows, {review_count} review passes, {lesson_count} lessons, and {lexeme_logs} lexeme/source-log rows. Verified sentences moved {verified_before}->{verified_after}; Kuku words moved {words_before}->{words_after}.", command="python3 batch_scripts/close_331.py", output_excerpt=f"closed batch-331: accepted={accepted_after}, reviews={review_count}, lessons={lesson_count}, lexeme_logs={lexeme_logs}, verified {verified_before}->{verified_after}, kuku_words {words_before}->{words_after}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit()
    print(
        f"closed batch-331: accepted={accepted_after}, reviews={review_count}, lessons={lesson_count}, "
        f"lexeme_logs={lexeme_logs}, verified {verified_before}->{verified_after}, kuku_words {words_before}->{words_after}"
    )
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
