#!/usr/bin/env python3
"""Close batch-291 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-291"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-291-body-part-complementary-pronoun-expansion-after-rule248-process.md"
LENSES = ("morphology", "lexicon", "syntax", "fidelity", "register")

NOTES = (
    "BODY-PART COMPLEMENTARY PERCEPTION PRONOUN EXPANSION AFTER RULE 248 (Rule 249). 50 rows. "
    "TARGETS retained: bandin love handles, bari chin, bibar shin, birri fingernail, jiba liver, jandal leg, "
    "jibar stomach, kangkul cheek, kuwinyu posterior, and waba thigh. SUPPORT: bare nominative ngali, ngaliny, "
    "yubal, nganjin, and yurra plus yaluy/yinyay and nyajil. FRAMES: Ngali TARGET yinyay nyajil, "
    "Ngaliny TARGET yaluy nyajil, Yubal TARGET yinyay nyajil, Nganjin TARGET yaluy nyajil, and "
    "Yurra TARGET yinyay nyajil. REVIEW: no new body-part lexeme, no possession, possessor pronoun, body-state, "
    "pain, illness, medicine/healing, body-fluid, ritual/taboo/scar/initiation, animal-only, dialect-only, "
    "movement/use/event, jaw, ankle, toenail, insides/guts/organs, emotion, butchery/eating, locational jibarr, "
    "kangku valley, kangkul kulbal slap, rude-register, sitting-event, hip, target case, target compound, "
    "productive reduplication, pronoun case, perception compound, support inflection, or recent landform/dwelling/"
    "fire/fish/bird drift was opened."
)

LESSONS = [
    ("source", "Rule 249 retained the ten checked Rule 234 body-part noun heads: bandin, bari, bibar, birri, jiba, jandal, jibar, kangkul, kuwinyu, and waba.", "Rule 249: retained target inventory."),
    ("source", "Dictionary line readback confirmed bandin as love handles, bari as chin, bibar as shin, birri as fingernail, jiba as liver, jandal as leg, jibar as stomach, kangkul as cheek, kuwinyu as posterior, and waba as thigh.", "Rule 249: dictionary source readback."),
    ("source", "Direct dictionary readback used lines 1425-1434 for bandin, 1688-1698 for bari, 2131-2140 for bibar, 3190-3199 for birri, 8611-8623 for jiba, 7926-7934 for jandal, 8728-8736 for jibar, 13276-13284 for kangkul, 16806-16818 for kuwinyu, and 24975-24984 for waba.", "Rule 249: line-level source evidence."),
    ("source", "Patz section 3.5 Table 3.6 supplied the selected bare nominative pronouns ngali, ngaliny, yubal, nganjin, and yurra.", "Rule 249: pronoun source."),
    ("source", "Patz section 3.7 supplied Yalanji yaluy 'here' and yinyay 'there'; Rule 249 used only the bare local demonstratives and did not add case-marked local forms.", "Rule 249: demonstrative source."),
    ("source", "Patz section 3.8.3.2 supplied nyaji-l 'see'; Rule 249 used only nonpast nyajil and did not build perception compounds, past, purposive, or infinitive rows.", "Rule 249: perception source."),
    ("process", "Exact duplicate preflight over all 50 final Rule 249 Kuku surfaces returned no accepted, revised, or under-review collisions.", "Rule 249: duplicate preflight."),
    ("process", "Token-aware target coverage before banking after Rule 248 was bandin 15, bari 19, bibar 25, birri 23, jiba 56, jandal 39, jibar 57, kangkul 19, kuwinyu 15, and waba 19.", "Rule 249: target coverage audit."),
    ("process", "Pronoun coverage before banking was ngali 141, ngaliny 75, yubal 89, nganjin 91, and yurra 134; the batch added opposite-location signal for dual, exclusive, and second-plural nominative forms.", "Rule 249: pronoun coverage audit."),
    ("lexicon", "Bandin remained love handles only; lexical plural English did not open possession, body-state, pain, or medical rows.", "Rule 249: bandin."),
    ("lexicon", "Bari remained chin only; jaw extension from the source entry stayed closed.", "Rule 249: bari."),
    ("lexicon", "Bibar remained shin only; ankle extension from the source entry stayed closed.", "Rule 249: bibar."),
    ("lexicon", "Birri remained fingernail only; toenail extension from the source entry stayed closed.", "Rule 249: birri."),
    ("lexicon", "Jiba remained liver only; insides, guts, organs, emotion, butchery, eating, medical, and compound rows stayed closed.", "Rule 249: jiba."),
    ("lexicon", "Jandal remained leg only; walking, movement, injury, possession, and event rows stayed closed.", "Rule 249: jandal."),
    ("lexicon", "Jibar remained stomach only; locational jibarr, emotion, sickness, eating, and possession rows stayed closed.", "Rule 249: jibar."),
    ("lexicon", "Kangkul remained cheek only; kangku valley drift and kangkul kulbal slap rows stayed closed.", "Rule 249: kangkul."),
    ("lexicon", "Kuwinyu remained neutral posterior only; rude-register, ritual, taboo, sitting-event, and possession rows stayed closed.", "Rule 249: kuwinyu."),
    ("lexicon", "Waba remained thigh only; hip extension from the source entry stayed closed.", "Rule 249: waba."),
    ("morphology", "All Rule 249 target nouns stayed bare: no LOC, DAT, ABL, PERL, ERG, INST, COMIT, POSS, PRIV, EXCESS, plural, derivation, or target suffix was admitted.", "Rule 249: bare targets."),
    ("morphology", "The subject support forms stayed bare nominatives: no pronoun case forms, possessive readings, or person/number extensions were introduced.", "Rule 249: bare nominative pronouns."),
    ("morphology", "Yaluy, yinyay, and nyajil stayed uninflected support heads; no demonstrative case, local-derived form, verb nominalization, purposive, past, or support suffix was admitted.", "Rule 249: uninflected support."),
    ("morphology", "No target compound, lexicalized trap compound, possessive construction, body-state construction, or productive reduplication was built from the body-part heads.", "Rule 249: no compounds or reduplication."),
    ("syntax", "Rows 1-10 used Ngali TARGET yinyay nyajil.", "Rule 249: 1du exclusive there perception band."),
    ("syntax", "Rows 11-20 used Ngaliny TARGET yaluy nyajil.", "Rule 249: 1du inclusive here perception band."),
    ("syntax", "Rows 21-30 used Yubal TARGET yinyay nyajil.", "Rule 249: 2du there perception band."),
    ("syntax", "Rows 31-40 used Nganjin TARGET yaluy nyajil.", "Rule 249: 1pl exclusive here perception band."),
    ("syntax", "Rows 41-50 used Yurra TARGET yinyay nyajil.", "Rule 249: 2pl there perception band."),
    ("fidelity", "English stayed literal perception/reference prose: selected subject pronoun value, target label, here/there, and see only.", "Rule 249: literal English."),
    ("fidelity", "The batch did not convert dictionary alternate glosses or source prose into possession, illness, pain, emotion, jaw, ankle, toenail, hip, medical, body-fluid, movement, or event claims.", "Rule 249: source-prose restraint."),
    ("register", "Rows remained plain elicitation-style perception clauses; no rude-register, ritual, taboo, medical, injury, movement, or narrative register was introduced.", "Rule 249: register."),
    ("process", "Rules 149-248 carry-forward traps stayed closed, especially recent landform, dwelling, fire, fish, and bird perception traps plus body-part possession/body-state traps.", "Rule 249: carry-forward closure."),
    ("handoff", "Next batch may continue from 14,647 if this closes; do not infer possession, body-state, pain, illness, medical, body-fluid, movement, event, target-case, pronoun-case, perception-compound, or support-inflection grammar from Rule 249.", "Rule 249: next cadence."),
]

LEXEMES = [
    ("bandin", "noun", None, "NA", "love handles", "batch-291: love-handles perception/reference only; lexical plural English, no possession, body-state, pain, or medical row."),
    ("bari", "noun", None, "NA", "chin", "batch-291: chin perception/reference only; jaw extension closed."),
    ("bibar", "noun", None, "NA", "shin", "batch-291: shin perception/reference only; ankle extension closed."),
    ("birri", "noun", None, "NA", "fingernail", "batch-291: fingernail perception/reference only; toenail extension closed."),
    ("jiba", "noun", None, "NA", "liver", "batch-291: liver perception/reference only; insides/guts/organs/emotion/butchery/eating/medical/compound rows closed."),
    ("jandal", "noun", None, "NA", "leg", "batch-291: leg perception/reference only; walking, movement, injury, possession, and event rows closed."),
    ("jibar", "noun", None, "NA", "stomach", "batch-291: stomach perception/reference only; locational jibarr, emotion, sickness, eating, and possession rows closed."),
    ("kangkul", "noun", None, "NA", "cheek", "batch-291: cheek perception/reference only; kangku valley and kangkul kulbal slap rows closed."),
    ("kuwinyu", "noun", None, "NA", "posterior", "batch-291: neutral posterior perception/reference only; no rude-register, ritual, taboo, sitting-event, or possession row."),
    ("waba", "noun", None, "NA", "thigh", "batch-291: thigh perception/reference only; hip extension closed."),
    ("ngali", "pronoun", None, "NA", "first dual exclusive nominative", "batch-291: bare nominative subject support only."),
    ("ngaliny", "pronoun", None, "NA", "first dual inclusive nominative", "batch-291: bare nominative subject support only."),
    ("yubal", "pronoun", None, "NA", "second dual nominative", "batch-291: bare nominative subject support only."),
    ("nganjin", "pronoun", None, "NA", "first plural exclusive nominative", "batch-291: bare nominative subject support only."),
    ("yurra", "pronoun", None, "NA", "second plural nominative", "batch-291: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-291: bare local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-291: bare local demonstrative support only."),
    ("nyajil", "verb", "l", "NA", "see", "batch-291: nonpast perception support only."),
]


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:
        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}")

    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-291-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 249 rows. Morphology checked bare body-part nouns, bare nominative ngali/ngaliny/yubal/nganjin/yurra, bare yaluy/yinyay, and nyajil nonpast only. Lexicon checked selected target senses only. Syntax checked five opposite-location pronoun-perception frame bands. Fidelity checked literal 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 possession, possessor pronoun, body-state, pain, illness, medicine/healing, body-fluid, ritual/taboo/scar/initiation, animal-only, dialect-only, movement/use/event, jaw, ankle, toenail, insides/guts/organs, emotion, butchery/eating, locational jibarr, kangku valley, kangkul kulbal slap, rude-register, sitting-event, hip, target case, productive compound, productive reduplication, pronoun case, perception compound, support inflection, or recent landform/dwelling/fire/fish/bird 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 249 lessons covering source checks, coverage, lexical target senses, morphology, syntax, fidelity, register, process traps, and handoff.",
        artifact_path="batch_scripts/close_291.py",
        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 249 targets and support heads.",
        artifact_path="batch_scripts/close_291.py",
        created_at=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))
    record_event(
        db,
        batch_label=LABEL,
        phase="close",
        event_type="close-success",
        actor="claude-main",
        detail="Closed Batch 291: 50 accepted Rule 249 body-part complementary pronoun-expansion rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_291.py",
        artifact_path="batch_scripts/close_291.py",
        created_at=NOW,
    )
    db.commit()

    reviews = db.execute(
        "SELECT COUNT(*) FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)",
        (batch_id,),
    ).fetchone()[0]
    lessons = 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-291-verify'"
    ).fetchone()[0]
    verified_after, words_after = db.execute(
        """
        SELECT
          COUNT(*),
          SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1)
        FROM sentences
        WHERE status IN ('accepted','revised')
        """
    ).fetchone()
    print(
        f"closed {LABEL}: accepted=50, reviews={reviews}, lessons={lessons}, "
        f"lexeme_logs={lexeme_logs}, verified {verified_before}->{verified_after}, "
        f"kuku_words {words_before}->{words_after}"
    )
    return 0


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