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

NOTES = (
    "INSECT-REFERENCE COMPLEMENTARY PERCEPTION DEBT SWEEP AFTER RULE 255 (Rule 256). 50 rows. TARGETS: balarr flea, "
    "dijaraban mayfly, kalburiji kalburiji bee, mawal mawal bee, munudumbun scorpion, munyurri sandfly, "
    "nakawarra nakawarra bee, ngalmnbu jumper ant, yarrka yarrka bee, and yiljun grasshopper. 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 169-170 or Rule 222 insect alternate target, no biting, "
    "stinging, sickness, vomiting, larvae, eggs, honey, nest, edible, food, medicine, seasonal-signal, "
    "collecting, antbed, body-part, human-body, tree/wood, mountain/habitat, pest-control, totem, "
    "life-force, dragonfly, smallest, bush, ecology, movement, danger, event, yam-readiness, singing, "
    "target case, target compound, productive reduplication, pronoun case, demonstrative case, perception "
    "compound, purposive, past, or support inflection was opened."
)

LESSONS = [
    ("source", "Rule 256 retained the ten checked Rule 212/255 insect noun heads: balarr, dijaraban, kalburiji, mawal, munudumbun, munyurri, nakawarra, ngalmnbu, yarrka, and yiljun.", "Rule 256: target inventory."),
    ("source", "Dictionary line readback was explicit: balarr 833-841, dijaraban 5542-5551, kalburiji 12474-12484, mawal 18743-18753, munudumbun 20816-20826, munyurri 20868-20889, nakawarra 21461-21470, ngalmnbu 21972-21980, yarrka 29551-29559, and yiljun 30019-30029.", "Rule 256: dictionary source lines."),
    ("source", "Patz grammar lines 2553-2603 supplied the bare nominative pronoun forms used as subject support in this batch.", "Rule 256: pronoun source."),
    ("source", "Patz Table 3.12 lines 2838-2845 supplied Yalanji yaluy 'here' and yinyay 'there'; Rule 256 used only the bare local demonstratives.", "Rule 256: demonstrative source."),
    ("source", "Patz section 3.8.3.2 lines 3043-3049 supplied nyaji-l 'see'; Rule 256 used only the nonpast form nyajil and did not build perception compounds or purposive rows.", "Rule 256: perception source."),
    ("process", "Hard exclusions retained: Rule 169-170 and Rule 222 insect alternates, synonyms and source-prose alternates, all behavior/use/ecology/body/event fields, and all target/support morphology traps.", "Rule 256: hard exclusions."),
    ("process", "Exact duplicate preflight over all 50 planned Rule 256 Kuku surfaces returned no accepted, revised, or under-review collisions.", "Rule 256: duplicate preflight."),
    ("process", "Token-aware target coverage before banking after Rule 255 was balarr 10, dijaraban 10, kalburiji 10, mawal 10, munudumbun 10, munyurri 10, nakawarra 10, ngalmnbu 10, yarrka 10, and yiljun 10.", "Rule 256: target coverage audit."),
    ("process", "Support coverage before banking after Rule 255 was ngayu 1273, nyulu 1754, yurra 203, bula 183, jana 1476, yaluy 2243, yinyay 2506, and nyajil 2617.", "Rule 256: support coverage audit."),
    ("lexicon", "Balarr was retained as flea only; human-body, body-part, bite, and biting readings stayed closed.", "Rule 256: balarr."),
    ("lexicon", "Dijaraban was retained as mayfly only; dragonfly expansion stayed closed.", "Rule 256: dijaraban."),
    ("lexicon", "Kalburiji was retained as kalburiji bee only; honey, nest, egg, larvae, and collecting readings stayed closed.", "Rule 256: kalburiji."),
    ("lexicon", "Mawal was retained as mawal bee only; honey, nest, egg, larvae, and collecting readings stayed closed.", "Rule 256: mawal."),
    ("lexicon", "Munudumbun was retained as scorpion only; munukurru synonym, sting, sickness, fear, and danger readings stayed closed.", "Rule 256: munudumbun."),
    ("lexicon", "Munyurri was retained as sandfly only; diri-diri synonym, biting, and sickness readings stayed closed.", "Rule 256: munyurri."),
    ("lexicon", "Nakawarra was retained as nakawarra bee only; honey, nest, egg, larvae, and collecting readings stayed closed.", "Rule 256: nakawarra."),
    ("lexicon", "Ngalmnbu was retained as jumper ant only; jumping, sting, bite, antbed, and body-event readings stayed closed.", "Rule 256: ngalmnbu."),
    ("lexicon", "Yarrka was retained as yarrka bee only; smallest, bush, and ecology readings stayed closed.", "Rule 256: yarrka."),
    ("lexicon", "Yiljun was retained as grasshopper only; singing, yam readiness, and seasonal-signal readings stayed closed.", "Rule 256: yiljun."),
    ("morphology", "All Rule 256 target nouns stayed bare: no LOC, DAT, ABL, PERL, ERG, INST, COMIT, POSS, PRIV, EXCESS, plural, derivation, or target suffix was admitted.", "Rule 256: bare targets."),
    ("morphology", "English modifiers inside insect labels, such as kalburiji, mawal, nakawarra, yarrka, and jumper, remained lexical-label material rather than Kuku morphology or separate predicates.", "Rule 256: label morphology guard."),
    ("morphology", "The subject support forms stayed bare nominatives: no pronoun case forms, possessive readings, or person/number extensions were introduced.", "Rule 256: 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 256: uninflected support."),
    ("morphology", "No target compound, lexicalized trap compound, or productive reduplication was built from the insect heads.", "Rule 256: no compounds or reduplication."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yaluy nyajil.", "Rule 256: 1sg here perception band."),
    ("syntax", "Rows 11-20 used Nyulu TARGET yinyay nyajil.", "Rule 256: 3sg there perception band."),
    ("syntax", "Rows 21-30 used Yurra TARGET yaluy nyajil.", "Rule 256: 2pl here perception band."),
    ("syntax", "Rows 31-40 used Bula TARGET yinyay nyajil.", "Rule 256: 3du there perception band."),
    ("syntax", "Rows 41-50 used Jana TARGET yaluy nyajil.", "Rule 256: 3pl here perception band."),
    ("fidelity", "English stayed literal perception/reference prose: subject pronoun, selected insect label, here/there, and see only.", "Rule 256: literal English."),
    ("fidelity", "The batch did not convert dictionary examples, gloss modifiers, synonyms, or source prose into body, biting, stinging, sickness, vomiting, larvae, egg, honey, nest, edible, food, medicine, seasonal, collecting, antbed, tree, wood, habitat, pest, totem, life-force, dragonfly, smallest, bush, ecology, movement, danger, event, yam-readiness, singing, or song claims.", "Rule 256: source-prose restraint."),
    ("register", "Rows remained plain elicitation-style perception clauses; no warning, medicine statement, food statement, gathering statement, ecology note, seasonal-signal report, pest-control claim, body-event statement, or lore register was introduced.", "Rule 256: register."),
    ("process", "Rules 149-255 carry-forward traps stayed closed, especially mammal, reptile/amphibian, fish, bird, dwelling/household, landform/geography, body-part, fire, shellfish, flora, artefact, weapon, weather, water, route/travel, implement, and insect source-prose drift.", "Rule 256: carry-forward closure."),
    ("handoff", "Next batch may continue from 14,997 if this closes; do not infer insect behavior, food, medicine, ecology, source-prose, synonym, target-case, pronoun-case, demonstrative-case, perception-compound, or support-inflection grammar from Rule 256.", "Rule 256: next cadence."),
]

LEXEMES = [
    ("balarr", "noun", None, "NA", "flea", "batch-298: complementary flea perception/reference only; human-body, body-part, bite, and biting readings closed."),
    ("dijaraban", "noun", None, "NA", "mayfly", "batch-298: complementary mayfly perception/reference only; dragonfly expansion closed."),
    ("kalburiji", "noun", None, "NA", "kalburiji bee", "batch-298: complementary kalburiji-bee perception/reference only; honey, nest, egg, larvae, and collecting readings closed."),
    ("mawal", "noun", None, "NA", "mawal bee", "batch-298: complementary mawal-bee perception/reference only; honey, nest, egg, larvae, and collecting readings closed."),
    ("munudumbun", "noun", None, "NA", "scorpion", "batch-298: complementary scorpion perception/reference only; munukurru synonym, sting, sickness, fear, and danger readings closed."),
    ("munyurri", "noun", None, "NA", "sandfly", "batch-298: complementary sandfly perception/reference only; diri-diri synonym, biting, and sickness readings closed."),
    ("nakawarra", "noun", None, "NA", "nakawarra bee", "batch-298: complementary nakawarra-bee perception/reference only; honey, nest, egg, larvae, and collecting readings closed."),
    ("ngalmnbu", "noun", None, "NA", "jumper ant", "batch-298: complementary jumper-ant perception/reference only; jumping, sting, bite, antbed, and body-event readings closed."),
    ("yarrka", "noun", None, "NA", "yarrka bee", "batch-298: complementary yarrka-bee perception/reference only; smallest, bush, and ecology readings closed."),
    ("yiljun", "noun", None, "NA", "grasshopper", "batch-298: complementary grasshopper perception/reference only; singing, yam readiness, and seasonal-signal readings closed."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-298: bare nominative subject support only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-298: bare nominative subject support only."),
    ("yurra", "pronoun", None, "NA", "second plural nominative", "batch-298: bare nominative subject support only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-298: bare nominative subject support only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-298: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-298: bare local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-298: bare local demonstrative support only."),
    ("nyajil", "verb", "l", "NA", "see", "batch-298: 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-298-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 256 rows. Morphology checked bare insect nouns, bare nominative pronouns, bare yaluy/yinyay, and nyajil nonpast only. Lexicon checked selected insect labels only. Syntax checked five complementary 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 169-170 or Rule 222 insect alternate target, no synonym expansion, no dragonfly expansion, no body/human/bite/sting/sickness/vomit row, no larvae/egg/honey/nest row, no edible/food/eat/medicine row, no seasonal/collecting/antbed row, no tree/wood/habitat/pest/totem/life-force row, no smallest/bush/ecology/movement/danger/event row, no yam-readiness/singing/song row, 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 256 lessons covering source checks, lexical target senses, hard exclusions, morphology, syntax, fidelity, register, process traps, and handoff.",
        artifact_path="batch_scripts/close_298.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 256 targets and support heads.",
        artifact_path="batch_scripts/close_298.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 298: 50 accepted Rule 256 insect-reference complementary perception rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_298.py",
        artifact_path="batch_scripts/close_298.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-298-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())
