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

NOTES = (
    "BIRD NON-SINGULAR PRONOUN PERCEPTION SWEEP AFTER RULE 265 (Rule 266). 50 rows. TARGETS: birmba "
    "straw-necked ibis, jamarbina goose, nili-nili duck, mabal swallow, wungku domestic turkey, kuludu dove, "
    "kururrungka kookaburra, karrambil king parrot, yinjul parrot, and kadanji black cockatoo. SUPPORT: bare "
    "nominative ngali, ngaliny, yubal, nganjin, and ngana plus yaluy/yinyay and nyajil. FRAMES: Ngali TARGET "
    "yinyay nyajil, Ngaliny TARGET yaluy nyajil, Yubal TARGET yinyay nyajil, Nganjin TARGET yaluy nyajil, and "
    "Ngana TARGET yinyay nyajil. REVIEW: no bird classifier dikal, alternate bird target, synonym expansion, "
    "kumurbina, diwan, wabul, older bird-field alternate, totem, moiety, sacred-bird, Dabu, Nyungkul, generic-bird "
    "row, story/place/country/myth/omen/ceremony row, flight/song/call/dance/warning/messenger/message row, nest/"
    "egg/feather/wing row, food/eating/hunting/catching row, habitat/water/river/sea/tree row, scrub-turkey, white-"
    "cockatoo, small-grey, bronze-wing, fig-parrot, colour predicate, source-prose row, target case, target compound, "
    "productive reduplication, pronoun case, demonstrative case, perception compound, purposive, past, support "
    "inflection, mammal drift, reptile/amphibian drift, fish drift, insect drift, shellfish drift, or recent dwelling/"
    "landform/body/fire drift was opened."
)

LESSONS = [
    ("source", "Rule 266 retained the ten checked Rule 241/242 bird noun heads: birmba, jamarbina, nili-nili, mabal, wungku, kuludu, kururrungka, karrambil, yinjul, and kadanji.", "Rule 266: target inventory."),
    ("source", "Dictionary line readback was explicit: birmba 3127-3147, jamarbina 7681-7689, nili-nili 24088-24114, mabal 16993-17003, wungku 28205-28227, kuludu 15402-15421, kururrungka 16755-16763, karrambil 13547-13555, yinjul 30248-30270, and kadanji 11898-11918.", "Rule 266: dictionary source lines."),
    ("source", "Patz grammar lines 2577-2603 supplied bare nominative ngali, ngaliny, yubal, nganjin, and ngana; Rule 266 used no pronoun case forms.", "Rule 266: non-singular pronoun source."),
    ("source", "Patz grammar lines 2682-2684 and corpus precedent supported the English alignment: ngali 1du exclusive, ngaliny 1du inclusive, yubal 2du, nganjin 1pl exclusive, and ngana 1pl inclusive.", "Rule 266: inclusive/exclusive source."),
    ("source", "Patz Table 3.12 lines 2838-2845 supplied Yalanji yaluy 'here' and yinyay 'there'; Rule 266 used only the bare local demonstratives.", "Rule 266: demonstrative source."),
    ("source", "Patz section 3.8.3.2 lines 3043-3049 supplied nyaji-l 'see'; Rule 266 used only the nonpast form nyajil and did not build perception compounds or purposive rows.", "Rule 266: perception source."),
    ("process", "Rule 266 opens the bird non-singular-pronoun perception pair after the bird single/third/plural perception rules 241-242.", "Rule 266: field rotation."),
    ("process", "Exact duplicate preflight over all 50 planned Rule 266 Kuku surfaces returned no accepted, revised, or under-review collisions.", "Rule 266: duplicate preflight."),
    ("process", "Token-aware target coverage before banking after Rule 265 was birmba 17, jamarbina 24, nili-nili 31, mabal 15, wungku 11, kuludu 18, kururrungka 17, karrambil 24, yinjul 17, and kadanji 17.", "Rule 266: target coverage audit."),
    ("process", "Support coverage before banking after Rule 265 was ngali 219, ngaliny 154, yubal 165, nganjin 171, ngana 919, yaluy 2503, yinyay 2746, and nyajil 3117.", "Rule 266: support coverage audit."),
    ("lexicon", "Birmba was admitted as straw-necked ibis only; totem/moiety and cockatoo alternate notes stayed closed.", "Rule 266: birmba."),
    ("lexicon", "Jamarbina was admitted as goose only; bird behavior, food, hunting, habitat, and story readings stayed closed.", "Rule 266: jamarbina."),
    ("lexicon", "Nili-nili was admitted as duck only; reduplication stayed lexical, not productive.", "Rule 266: nili-nili."),
    ("lexicon", "Mabal was admitted as swallow only; English verb/action semantics stayed closed.", "Rule 266: mabal."),
    ("lexicon", "Wungku was admitted as domestic turkey only; scrub-turkey, diwan synonym, and post-contact source-prose drift stayed closed.", "Rule 266: wungku."),
    ("lexicon", "Kuludu was admitted as dove only; small-grey descriptive prose and colour-property rows stayed closed.", "Rule 266: kuludu."),
    ("lexicon", "Kururrungka was admitted as kookaburra only; bronze-wing/body-colour prose stayed closed.", "Rule 266: kururrungka."),
    ("lexicon", "Karrambil was admitted as king parrot only; parrot behavior, habitat, and story readings stayed closed.", "Rule 266: karrambil."),
    ("lexicon", "Yinjul was admitted as parrot only; fig-parrot, tree, food, and habitat prose stayed closed.", "Rule 266: yinjul."),
    ("lexicon", "Kadanji was admitted as black cockatoo only; kumurbina, Nyungkul, Dabu/totem prose, and generic-bird expansion stayed closed.", "Rule 266: kadanji."),
    ("morphology", "All Rule 266 target nouns stayed bare: no LOC, DAT, ABL, PERL, ERG, INST, COMIT, POSS, PRIV, EXCESS, plural, derivation, or target suffix was admitted.", "Rule 266: bare targets."),
    ("morphology", "English modifiers inside bird labels, such as straw-necked, domestic, king, and black, remained lexical-label prose rather than Kuku morphology or separate predicates.", "Rule 266: 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 266: 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 266: uninflected support."),
    ("morphology", "No target compound, lexicalized trap compound, or productive reduplication was built from the bird heads.", "Rule 266: no compounds or reduplication."),
    ("syntax", "Rows 1-10 used Ngali TARGET yinyay nyajil.", "Rule 266: 1du exclusive there perception band."),
    ("syntax", "Rows 11-20 used Ngaliny TARGET yaluy nyajil.", "Rule 266: 1du inclusive here perception band."),
    ("syntax", "Rows 21-30 used Yubal TARGET yinyay nyajil.", "Rule 266: 2du there perception band."),
    ("syntax", "Rows 31-40 used Nganjin TARGET yaluy nyajil.", "Rule 266: 1pl exclusive here perception band."),
    ("syntax", "Rows 41-50 used Ngana TARGET yinyay nyajil.", "Rule 266: 1pl inclusive there perception band."),
    ("fidelity", "English stayed literal perception/reference prose: subject pronoun, selected bird label, here/there, and see only.", "Rule 266: literal English."),
    ("fidelity", "The batch did not convert dictionary examples, alternate glosses, or source prose into flight, song, call, dance, warning, messenger, totem, moiety, sacred-bird, story, nest, egg, feather, wing, food, hunting, catching, habitat, water, tree, colour, source-material, or event claims.", "Rule 266: source-prose restraint."),
    ("register", "Rows remained plain elicitation-style perception clauses; no bird-lore, warning, hunting report, food statement, habitat claim, or story register was introduced.", "Rule 266: register."),
    ("process", "Rules 149-265 carry-forward traps stayed closed, especially bird event/use/lore traps, mammal-source-prose traps, reptile/amphibian use/action traps, fish-use/action traps, insect and 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 266: carry-forward closure."),
    ("handoff", "Next batch may continue from 15,497 if this closes; do not infer bird behavior, use, habitat, lore, body-part, alternate target, source-prose, target-case, pronoun-case, demonstrative-case, perception-compound, purposive, past, or support-inflection grammar from Rule 266.", "Rule 266: next cadence."),
]

LEXEMES = [
    ("birmba", "noun", None, "NA", "straw-necked ibis", "batch-308: straw-necked-ibis perception/reference only; totem/moiety and cockatoo alternate notes closed."),
    ("jamarbina", "noun", None, "NA", "goose", "batch-308: goose perception/reference only; behavior/food/hunting/habitat/story readings closed."),
    ("nili-nili", "noun", None, "NA", "duck", "batch-308: duck perception/reference only; reduplication is lexical only."),
    ("mabal", "noun", None, "NA", "swallow", "batch-308: swallow bird perception/reference only; English verb/action semantics closed."),
    ("wungku", "noun", None, "NA", "domestic turkey", "batch-308: domestic-turkey perception/reference only; scrub-turkey/diwan/source-prose drift closed."),
    ("kuludu", "noun", None, "NA", "dove", "batch-308: dove perception/reference only; small-grey descriptive prose and colour rows closed."),
    ("kururrungka", "noun", None, "NA", "kookaburra", "batch-308: kookaburra perception/reference only; bronze-wing/body-colour prose closed."),
    ("karrambil", "noun", None, "NA", "king parrot", "batch-308: king-parrot perception/reference only; behavior/habitat/story readings closed."),
    ("yinjul", "noun", None, "NA", "parrot", "batch-308: parrot perception/reference only; fig-parrot/tree/food/habitat prose closed."),
    ("kadanji", "noun", None, "NA", "black cockatoo", "batch-308: black-cockatoo perception/reference only; kumurbina/Nyungkul/Dabu/totem/generic-bird expansion closed."),
    ("ngali", "pronoun", None, "NA", "first dual exclusive nominative", "batch-308: bare nominative subject support only."),
    ("ngaliny", "pronoun", None, "NA", "first dual inclusive nominative", "batch-308: bare nominative subject support only."),
    ("yubal", "pronoun", None, "NA", "second dual nominative", "batch-308: bare nominative subject support only."),
    ("nganjin", "pronoun", None, "NA", "first plural exclusive nominative", "batch-308: bare nominative subject support only."),
    ("ngana", "pronoun", None, "NA", "first plural inclusive nominative", "batch-308: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-308: bare local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-308: bare local demonstrative support only."),
    ("nyajil", "verb", "l", "NA", "see", "batch-308: 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-308-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 266 rows. Morphology checked bare bird nouns, bare nominative non-singular pronouns, bare yaluy/yinyay, and nyajil nonpast only. Lexicon checked selected bird labels only. Syntax checked five 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="Final review retained no bird classifier, no alternate bird target, no synonym expansion, no kumurbina/diwan/wabul drift, no totem/moiety/sacred/Dabu/Nyungkul/generic-bird row, no story/place/country/myth/omen/ceremony row, no flight/song/call/dance/warning/messenger/message row, no nest/egg/feather/wing row, no food/eating/hunting/catching row, no habitat/water/river/sea/tree row, no scrub-turkey/white-cockatoo/small-grey/bronze-wing/fig-parrot source-prose row, no colour predicate, no target case, no productive compound, no productive reduplication, no pronoun case, no demonstrative case, no perception compound, no purposive, no past, 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 266 lessons covering source checks, lexical target senses, field rotation, hard exclusions, morphology, syntax, fidelity, register, process traps, and handoff.",
        artifact_path="batch_scripts/close_308.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 266 targets and support heads.",
        artifact_path="batch_scripts/close_308.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 308: 50 accepted Rule 266 bird non-singular pronoun perception rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_308.py",
        artifact_path="batch_scripts/close_308.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-308-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())
