#!/usr/bin/env python3
"""Close batch-295 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-295"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-295-mammal-perception-debt-sweep-after-rule252-process.md"
LENSES = ("morphology", "lexicon", "syntax", "fidelity", "register")

NOTES = (
    "MAMMAL-REFERENCE PERCEPTION DEBT SWEEP AFTER RULE 252 (Rule 253). 50 rows. TARGETS: bala sugar glider, "
    "darrba grass wallaby, jarrabina tree kangaroo, jayju kangaroo rat, jungarr marsupial native cat, kukur rat, "
    "mali small bat, murramu dingo, ngumbi bandicoot, and yawa possum. SUPPORT: bare nominative ngayu, nyulu, "
    "yurra, bula, and jana plus yaluy/yinyay and nyajil. FRAMES: Ngayu TARGET yaluy nyajil, Nyulu TARGET yinyay "
    "nyajil, Yurra TARGET yaluy nyajil, Bula TARGET yinyay nyajil, and Jana TARGET yaluy nyajil. REVIEW: no "
    "Rule 177-178 exact-surface duplicate, skinny/weak/full/door/front homograph drift, dog/loan/domestic-cat drift, "
    "hunting/catching/trapping/killing row, biting/attack/spearing row, food/edible/cooking/meat row, skin/fur/tail/"
    "claw/body-part row, habitat/ecology/water/river/sea/cave/hollow/branch/tree-climbing row, story/place/totem/"
    "moiety/ceremony row, source-material row, colour predicate, target case, target compound, productive "
    "reduplication, pronoun case, demonstrative case, perception compound, support inflection, reptile/amphibian "
    "drift, fish-reference drift, or recent bird/dwelling/landform/body/fire drift was opened."
)

LESSONS = [
    ("source", "Rule 253 selected ten checked Rule 219 mammal noun heads: bala, darrba, jarrabina, jayju, jungarr, kukur, mali, murramu, ngumbi, and yawa.", "Rule 253: target inventory."),
    ("source", "Dictionary line readback was explicit: bala 720-738, darrba 5306-5315, jarrabina 8248-8259, jayju 8602-8610, jungarr 10882-10892, kukur 15002-15010, mali 17566-17577, murramu 21010-21020, ngumbi 23562-23572, and yawa 29634-29642.", "Rule 253: dictionary source lines."),
    ("source", "Patz grammar lines 2553-2603 supplied the bare nominative pronoun forms used as subject support in this batch.", "Rule 253: pronoun source."),
    ("source", "Patz Table 3.12 lines 2838-2845 supplied Yalanji yaluy 'here' and yinyay 'there'; Rule 253 used only the bare local demonstratives.", "Rule 253: demonstrative source."),
    ("source", "Patz section 3.8.3.2 lines 3043-3049 supplied nyaji-l 'see'; Rule 253 used only the nonpast form nyajil and did not build perception compounds or purposive rows.", "Rule 253: perception source."),
    ("process", "Hard exclusions retained: exact Rule 177-178 mammal surfaces, high-pressure mammal/polysemy traps, skinny/weak/full/door/front homographs, dog/loan/domestic-cat drift, source-material drift, and all action/use/habitat/story/body-part fields.", "Rule 253: hard exclusions."),
    ("process", "Exact duplicate preflight over all 50 planned Rule 253 Kuku surfaces returned no accepted, revised, or under-review collisions.", "Rule 253: duplicate preflight."),
    ("process", "Token-aware target coverage before banking after Rule 252 was bala 9, darrba 38, jarrabina 10, jayju 8, jungarr 7, kukur 11, mali 15, murramu 28, ngumbi 8, and yawa 34.", "Rule 253: target coverage audit."),
    ("process", "Support coverage before banking after Rule 252 was ngayu 1243, nyulu 1724, yurra 173, bula 153, jana 1446, yaluy 2173, yinyay 2426, and nyajil 2467.", "Rule 253: support coverage audit."),
    ("lexicon", "Bala was admitted as sugar glider only; skinny, weak, boney, illness, and hunger readings stayed closed.", "Rule 253: bala."),
    ("lexicon", "Darrba was admitted as grass wallaby only; narrow/small adjective drift from neighboring entries and hunting/use readings stayed closed.", "Rule 253: darrba."),
    ("lexicon", "Jarrabina was admitted as tree kangaroo only; tree-climbing behavior, branch/hollow/habitat, and murral cross-reference drift stayed closed.", "Rule 253: jarrabina."),
    ("lexicon", "Jayju was admitted as kangaroo rat only; broader kangaroo, rat behavior, and food/hunting prose stayed closed.", "Rule 253: jayju."),
    ("lexicon", "Jungarr was admitted as marsupial native cat only; quoll commentary did not open domestic-cat, introduced-cat, or predator/action rows.", "Rule 253: jungarr."),
    ("lexicon", "Kukur was admitted as rat only; talk/dialect, food, pest, and biting/action readings stayed closed.", "Rule 253: kukur."),
    ("lexicon", "Mali was admitted as small bat only; small stayed part of the lexical label rather than an independent size predicate.", "Rule 253: mali."),
    ("lexicon", "Murramu was admitted as dingo only; ngamu-murramu synonym, dog/loan, attack, hunting, and event readings stayed closed.", "Rule 253: murramu."),
    ("lexicon", "Ngumbi was admitted as bandicoot only; little and spotted source-prose modifiers stayed closed as independent predicates.", "Rule 253: ngumbi."),
    ("lexicon", "Yawa was admitted as possum only; tree/habitat, food, fur/skin, and story/lore readings stayed closed.", "Rule 253: yawa."),
    ("morphology", "All Rule 253 target nouns stayed bare: no LOC, DAT, ABL, PERL, ERG, INST, COMIT, POSS, PRIV, EXCESS, plural, derivation, or target suffix was admitted.", "Rule 253: bare targets."),
    ("morphology", "English modifiers inside animal labels, such as sugar, grass, tree, kangaroo, marsupial, native, and small, remained lexical-label material rather than Kuku morphology or separate predicates.", "Rule 253: label morphology guard."),
    ("morphology", "The subject support forms stayed bare nominatives: no pronoun case forms, possessive readings, or person/number extensions were introduced.", "Rule 253: bare nominative pronouns."),
    ("morphology", "Yaluy, yinyay, and nyajil stayed uninflected support heads; no demonstrative case, local-derived form, verb nominalization, purposive, or support suffix was admitted.", "Rule 253: uninflected support."),
    ("morphology", "No target compound, lexicalized trap compound, or productive reduplication was built from the mammal heads.", "Rule 253: no compounds or reduplication."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yaluy nyajil.", "Rule 253: 1sg here perception band."),
    ("syntax", "Rows 11-20 used Nyulu TARGET yinyay nyajil.", "Rule 253: 3sg there perception band."),
    ("syntax", "Rows 21-30 used Yurra TARGET yaluy nyajil.", "Rule 253: 2pl here perception band."),
    ("syntax", "Rows 31-40 used Bula TARGET yinyay nyajil.", "Rule 253: 3du there perception band."),
    ("syntax", "Rows 41-50 used Jana TARGET yaluy nyajil.", "Rule 253: 3pl here perception band."),
    ("fidelity", "English stayed literal perception/reference prose: subject pronoun, selected mammal label, here/there, and see only.", "Rule 253: literal English."),
    ("fidelity", "The batch did not convert dictionary examples, gloss modifiers, or source prose into hunting, catching, trapping, killing, biting, attack, food, cooking, skin, fur, tail, claw, habitat, water, river, sea, cave, hollow, branch, tree-climbing, story, totem, ceremony, source-material, homograph, or body-part claims.", "Rule 253: source-prose restraint."),
    ("register", "Rows remained plain elicitation-style perception clauses; no hunting report, food statement, habitat claim, warning, lore statement, initiation/ceremony register, or source-material register was introduced.", "Rule 253: register."),
    ("process", "Rules 149-252 carry-forward traps stayed closed, especially mammal-use/action traps, reptile-use/action traps, fish-use/action traps, bird event/use/lore traps, dwelling action/use/source traps, fire action/use/homograph traps, landform route/water/event drift, and body-part possession/body-state drift.", "Rule 253: carry-forward closure."),
    ("handoff", "Next batch may continue from 14,847 if this closes; do not infer mammal behavior, food, habitat, story, body-part, homograph, source-material, colour-predicate, target-case, pronoun-case, demonstrative-case, perception-compound, or support-inflection grammar from Rule 253.", "Rule 253: next cadence."),
]

LEXEMES = [
    ("bala", "noun", None, "NA", "sugar glider", "batch-295: sugar-glider perception/reference only; skinny/weak/boney homograph closed."),
    ("darrba", "noun", None, "NA", "grass wallaby", "batch-295: grass-wallaby perception/reference only; size/narrow and hunting/use readings closed."),
    ("jarrabina", "noun", None, "NA", "tree kangaroo", "batch-295: tree-kangaroo perception/reference only; tree-climbing, branch/hollow/habitat, and murral drift closed."),
    ("jayju", "noun", None, "NA", "kangaroo rat", "batch-295: kangaroo-rat perception/reference only; broader behavior/food/action readings closed."),
    ("jungarr", "noun", None, "NA", "marsupial native cat", "batch-295: marsupial-native-cat perception/reference only; domestic/introduced cat and predator/action drift closed."),
    ("kukur", "noun", None, "NA", "rat", "batch-295: rat perception/reference only; talk/dialect, food, pest, and biting/action readings closed."),
    ("mali", "noun", None, "NA", "small bat", "batch-295: small-bat perception/reference only; small as separate size predicate closed."),
    ("murramu", "noun", None, "NA", "dingo", "batch-295: dingo perception/reference only; ngamu-murramu synonym, dog/loan, attack, hunting, and event readings closed."),
    ("ngumbi", "noun", None, "NA", "bandicoot", "batch-295: bandicoot perception/reference only; little/spotted modifiers closed as independent predicates."),
    ("yawa", "noun", None, "NA", "possum", "batch-295: possum perception/reference only; tree/habitat, food, fur/skin, and story/lore readings closed."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-295: bare nominative subject support only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-295: bare nominative subject support only."),
    ("yurra", "pronoun", None, "NA", "second plural nominative", "batch-295: bare nominative subject support only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-295: bare nominative subject support only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-295: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-295: bare local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-295: bare local demonstrative support only."),
    ("nyajil", "verb", "l", "NA", "see", "batch-295: 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-295-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 253 rows. Morphology checked bare mammal nouns, bare nominative pronouns, bare yaluy/yinyay, and nyajil nonpast only. Lexicon checked selected animal labels only. Syntax checked five 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 Rule 177-178 exact surface duplicate, no skinny/weak/full/door/front homograph drift, no dog/loan/domestic-cat drift, no hunting/catching/trapping/killing row, no biting/attack/spearing row, no food/edible/cooking/meat row, no skin/fur/tail/claw/body-part row, no habitat/ecology/water/river/sea/cave/hollow/branch/tree-climbing row, no story/place/totem/moiety/ceremony row, no source-material row, no colour predicate, no target case, no productive compound, no productive reduplication, no pronoun case, no demonstrative case, no perception compound, and no support inflection.",
        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 253 lessons covering source checks, lexical target senses, hard exclusions, morphology, syntax, fidelity, register, process traps, and handoff.",
        artifact_path="batch_scripts/close_295.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 253 targets and support heads.",
        artifact_path="batch_scripts/close_295.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 295: 50 accepted Rule 253 mammal-reference perception rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_295.py",
        artifact_path="batch_scripts/close_295.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-295-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())

