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

NOTES = (
    "INSECT COMPLEMENTARY NON-SINGULAR PRONOUN PERCEPTION SWEEP AFTER RULE 270 (Rule 271). 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 ngali, ngaliny, yubal, nganjin, and ngana plus yaluy/yinyay and nyajil. FRAMES: Ngali TARGET "
    "yaluy nyajil, Ngaliny TARGET yinyay nyajil, Yubal TARGET yaluy nyajil, Nganjin TARGET yinyay nyajil, and "
    "Ngana TARGET yaluy nyajil. REVIEW: no Rule 169-170, Rule 222, Rule 255-256, or Rule 270 insect alternate "
    "target, synonym expansion, dragonfly expansion, biting, stinging, sickness, vomiting, larvae, eggs, honey, "
    "nest, edible, food, medicine, seasonal-signal, collecting, antbed, body-part, human-body, tree/wood, habitat, "
    "pest-control, totem, life-force, smallest, bush, ecology, movement, danger, event, yam-readiness, singing, "
    "target case, target compound, productive reduplication, pronoun case, demonstrative case, perception compound, "
    "purposive, past, support inflection, fish drift, bird drift, mammal drift, reptile/amphibian drift, shellfish "
    "drift, or recent dwelling/landform/body/fire drift was opened."
)

LESSONS = [
    ("source", "Rule 271 retained the ten checked Rule 212/255/256/270 insect noun heads: balarr, dijaraban, kalburiji, mawal, munudumbun, munyurri, nakawarra, ngalmnbu, yarrka, and yiljun.", "Rule 271: 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 271: dictionary source lines."),
    ("source", "Patz grammar lines 2577-2603 supplied bare nominative ngali, ngaliny, yubal, nganjin, and ngana; Rule 271 used no pronoun case forms.", "Rule 271: non-singular pronoun source."),
    ("source", "Patz grammar lines 2682-2684 supported ngali as 1du exclusive, ngaliny as 1du inclusive, yubal as 2du, nganjin as 1pl exclusive, and ngana as 1pl inclusive.", "Rule 271: inclusive/exclusive source."),
    ("source", "Patz Table 3.12 lines 2838-2845 supplied Yalanji yaluy 'here' and yinyay 'there'; Rule 271 used only the bare local demonstratives.", "Rule 271: demonstrative source."),
    ("source", "Patz section 3.8.3.2 lines 3043-3049 supplied nyaji-l 'see'; Rule 271 used only nyajil nonpast.", "Rule 271: perception source."),
    ("process", "Rule 271 closes the complementary non-singular-pronoun perception pair for the insect field opened by Rule 270.", "Rule 271: complementary pair."),
    ("process", "Exact duplicate preflight over all 50 planned Rule 271 Kuku surfaces returned no accepted, revised, or under-review collisions.", "Rule 271: duplicate preflight."),
    ("process", "Token-aware target coverage before banking after Rule 270 was 20 accepted rows for each target: balarr, dijaraban, kalburiji, mawal, munudumbun, munyurri, nakawarra, ngalmnbu, yarrka, and yiljun.", "Rule 271: target coverage audit."),
    ("process", "Support coverage before banking after Rule 270 was ngali 268, ngaliny 203, yubal 214, nganjin 218, ngana 968, yaluy 2617, yinyay 2871, and nyajil 3328.", "Rule 271: support coverage audit."),
    ("lexicon", "Balarr was admitted as flea only; human-body, body-part, bite, and biting readings stayed closed.", "Rule 271: balarr."),
    ("lexicon", "Dijaraban was admitted as mayfly only; dragonfly expansion stayed closed.", "Rule 271: dijaraban."),
    ("lexicon", "Kalburiji was admitted as kalburiji bee only; honey, nest, egg, larvae, and collecting readings stayed closed.", "Rule 271: kalburiji."),
    ("lexicon", "Mawal was admitted as mawal bee only; honey, nest, egg, larvae, and collecting readings stayed closed.", "Rule 271: mawal."),
    ("lexicon", "Munudumbun was admitted as scorpion only; munukurru synonym, sting, sickness, fear, and danger readings stayed closed.", "Rule 271: munudumbun."),
    ("lexicon", "Munyurri was admitted as sandfly only; diri-diri synonym, biting, and sickness readings stayed closed.", "Rule 271: munyurri."),
    ("lexicon", "Nakawarra was admitted as nakawarra bee only; honey, nest, egg, larvae, and collecting readings stayed closed.", "Rule 271: nakawarra."),
    ("lexicon", "Ngalmnbu was admitted as jumper ant only; jumping, sting, bite, antbed, and body-event readings stayed closed.", "Rule 271: ngalmnbu."),
    ("lexicon", "Yarrka was admitted as yarrka bee only; smallest, bush, and ecology readings stayed closed.", "Rule 271: yarrka."),
    ("lexicon", "Yiljun was admitted as grasshopper only; singing, yam readiness, and seasonal-signal readings stayed closed.", "Rule 271: yiljun."),
    ("morphology", "All Rule 271 target nouns stayed bare: no LOC, DAT, ABL, PERL, ERG, INST, COMIT, POSS, PRIV, EXCESS, plural, derivation, or target suffix was admitted.", "Rule 271: 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 271: label morphology guard."),
    ("morphology", "The subject support forms stayed bare nominatives: ngali, ngaliny, yubal, nganjin, and ngana were not inflected for accusative, dative, locative, ablative, comitative, or possessive.", "Rule 271: bare non-singular 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 271: uninflected support."),
    ("morphology", "No target compound, lexicalized trap compound, or productive reduplication was built from the insect heads.", "Rule 271: no compounds or reduplication."),
    ("syntax", "Rows 1-10 used Ngali TARGET yaluy nyajil.", "Rule 271: 1du exclusive here perception band."),
    ("syntax", "Rows 11-20 used Ngaliny TARGET yinyay nyajil.", "Rule 271: 1du inclusive there perception band."),
    ("syntax", "Rows 21-30 used Yubal TARGET yaluy nyajil.", "Rule 271: 2du here perception band."),
    ("syntax", "Rows 31-40 used Nganjin TARGET yinyay nyajil.", "Rule 271: 1pl exclusive there perception band."),
    ("syntax", "Rows 41-50 used Ngana TARGET yaluy nyajil.", "Rule 271: 1pl inclusive here perception band."),
    ("fidelity", "English stayed literal perception/reference prose: subject pronoun, selected insect label, here/there, and see only.", "Rule 271: 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 271: 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 271: register."),
    ("process", "Rules 149-270 carry-forward traps stayed closed, especially insect behavior/use/source-prose traps, fish use/action/body/habitat/source-prose traps, bird event/use/lore traps, mammal-source-prose traps, reptile/amphibian use/action traps, shellfish source-prose traps, dwelling action/use/source traps, fire action/use/homograph traps, landform route/water/event drift, and body-part possession/body-state drift.", "Rule 271: carry-forward closure."),
    ("handoff", "Next batch may continue from 15,747 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 271.", "Rule 271: next cadence."),
]

LEXEMES = [
    ("balarr", "noun", None, "NA", "flea", "batch-313: flea perception/reference only; human-body, body-part, bite, and biting readings closed."),
    ("dijaraban", "noun", None, "NA", "mayfly", "batch-313: mayfly perception/reference only; dragonfly expansion closed."),
    ("kalburiji", "noun", None, "NA", "kalburiji bee", "batch-313: kalburiji-bee perception/reference only; honey, nest, egg, larvae, and collecting readings closed."),
    ("mawal", "noun", None, "NA", "mawal bee", "batch-313: mawal-bee perception/reference only; honey, nest, egg, larvae, and collecting readings closed."),
    ("munudumbun", "noun", None, "NA", "scorpion", "batch-313: scorpion perception/reference only; munukurru synonym, sting, sickness, fear, and danger readings closed."),
    ("munyurri", "noun", None, "NA", "sandfly", "batch-313: sandfly perception/reference only; diri-diri synonym, biting, and sickness readings closed."),
    ("nakawarra", "noun", None, "NA", "nakawarra bee", "batch-313: nakawarra-bee perception/reference only; honey, nest, egg, larvae, and collecting readings closed."),
    ("ngalmnbu", "noun", None, "NA", "jumper ant", "batch-313: jumper-ant perception/reference only; jumping, sting, bite, antbed, and body-event readings closed."),
    ("yarrka", "noun", None, "NA", "yarrka bee", "batch-313: yarrka-bee perception/reference only; smallest, bush, and ecology readings closed."),
    ("yiljun", "noun", None, "NA", "grasshopper", "batch-313: grasshopper perception/reference only; singing, yam readiness, and seasonal-signal readings closed."),
    ("ngali", "pronoun", None, "NA", "first dual exclusive nominative", "batch-313: bare nominative subject support only."),
    ("ngaliny", "pronoun", None, "NA", "first dual inclusive nominative", "batch-313: bare nominative subject support only."),
    ("yubal", "pronoun", None, "NA", "second dual nominative", "batch-313: bare nominative subject support only."),
    ("nganjin", "pronoun", None, "NA", "first plural exclusive nominative", "batch-313: bare nominative subject support only."),
    ("ngana", "pronoun", None, "NA", "first plural inclusive nominative", "batch-313: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-313: bare local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-313: bare local demonstrative support only."),
    ("nyajil", "verb", "l", "NA", "see", "batch-313: 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-313-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 271 rows. Morphology checked bare insect nouns, bare nominative non-singular pronouns, bare yaluy/yinyay, and nyajil nonpast only. Lexicon checked selected insect labels only. Syntax checked five complementary non-singular 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="Five-lens detail: morphology no case or derivation; lexicon no Rule 169-170, Rule 222, Rule 255-256, or Rule 270 insect alternate target, no synonym expansion, no dragonfly expansion; syntax one bare nominative non-singular subject plus target plus local demonstrative plus nyajil; fidelity no body/bite/sting/sickness/larvae/egg/honey/nest/food/medicine/seasonal/collecting/antbed/tree/habitat/totem/source-prose claims; register no warning, medicine, food, gathering, ecology, or lore frame.",
        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 271 lessons covering source lines, target inventory, coverage, lexeme decisions, morphology, syntax, fidelity, register, carry-forward 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/updated {len(LEXEMES)} lexeme/source-log rows for the ten insect targets and eight support forms.",
        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 271 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-313-verify'"
    ).fetchone()[0]
    record_event(
        db,
        batch_label=LABEL,
        phase="close",
        event_type="close-success",
        actor="claude-main",
        detail=f"Closed Batch 313 / Rule 271 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_313.py",
        output_excerpt=f"closed batch-313: 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 {LABEL}: accepted={accepted_after}, reviews={review_count}, "
        f"lessons={lesson_count}, lexeme_logs={lexeme_logs}, "
        f"verified {verified_before}->{verified_after}, kuku_words {words_before}->{words_after}"
    )
    return 0


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