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

NOTES = (
    "FISH COMPLEMENTARY NON-SINGULAR PRONOUN PERCEPTION SWEEP AFTER RULE 268 (Rule 269). 50 rows. TARGETS: "
    "kubija barracuda, mujarrka archerfish, barrbal black bream, wuyumbu toadfish, bayil perch, dalmbal flathead, "
    "balarri queenfish, bilmbin black-tip shark, jalkay salmon, and jijirr red bream. 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 garfish alternate, spotted-Jewfish prose, Nyungkul dalku, striped-toby alternate, "
    "black-tip ray alternate, dukul-barangka synonym, freshwater/saltwater/King Plains/mangrove/river/generic-fish "
    "source prose, catching, netting, hook/line, spearing, eating, cooking, bait, taboo, storm/thunder, story/place, "
    "water/river/sea/reef/habitat, fish body-part, tail, nose, fin, whisker, scale, colour predicate, danger, poison, "
    "bite, injury, target case, target compound, productive reduplication, pronoun case, demonstrative case, "
    "perception compound, purposive, past, support inflection, bird drift, mammal drift, reptile/amphibian drift, "
    "insect drift, shellfish drift, or recent dwelling/landform/body/fire drift was opened."
)

LESSONS = [
    ("source", "Rule 269 retained the ten checked fish noun heads: kubija, mujarrka, barrbal, wuyumbu, bayil, dalmbal, balarri, bilmbin, jalkay, and jijirr.", "Rule 269: target inventory."),
    ("source", "Dictionary line readback was explicit: balarri 842-858, barrbal 1810-1826, bayil 1992-2008, bilmbin 2553-2574, dalmbal 4947-4966, jalkay 7465-7481, jijirr 8937-8953, kubija 14673-14691, mujarrka 20152-20175, and wuyumbu 28647-28663.", "Rule 269: dictionary source lines."),
    ("source", "Patz grammar lines 2577-2603 supplied bare nominative ngali, ngaliny, yubal, nganjin, and ngana; Rule 269 used no pronoun case forms.", "Rule 269: 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 269: inclusive/exclusive source."),
    ("source", "Patz Table 3.12 lines 2838-2845 supplied Yalanji yaluy 'here' and yinyay 'there'; Rule 269 used only the bare local demonstratives.", "Rule 269: demonstrative source."),
    ("source", "Patz section 3.8.3.2 lines 3043-3049 supplied nyaji-l 'see'; Rule 269 used only nyajil nonpast.", "Rule 269: perception source."),
    ("process", "Rule 269 closes the complementary non-singular-pronoun perception pair for the fish field opened by Rule 268.", "Rule 269: complementary pair."),
    ("process", "Exact duplicate preflight over all 50 planned Rule 269 Kuku surfaces returned no accepted, revised, or under-review collisions.", "Rule 269: duplicate preflight."),
    ("process", "Token-aware target coverage before banking after Rule 268 was kubija 15, mujarrka 15, barrbal 21, wuyumbu 15, bayil 16, dalmbal 16, balarri 18, bilmbin 18, jalkay 21, and jijirr 21.", "Rule 269: target coverage audit."),
    ("process", "Support coverage before banking after Rule 268 was ngali 249, ngaliny 184, yubal 195, nganjin 201, ngana 949, yaluy 2573, yinyay 2826, and nyajil 3267.", "Rule 269: support coverage audit."),
    ("lexicon", "Kubija was admitted as barracuda only; garfish alternate and source-prose drift stayed closed.", "Rule 269: kubija."),
    ("lexicon", "Mujarrka was admitted as archerfish only; spotted-Jewfish, Nyungkul dalku, King Plains, fresh/saltwater, river, and habitat prose stayed closed.", "Rule 269: mujarrka."),
    ("lexicon", "Barrbal was admitted as black bream only; colour-predicate, reef, catching, and food readings stayed closed.", "Rule 269: barrbal."),
    ("lexicon", "Wuyumbu was admitted as toadfish only; striped-toby and generic-fish source prose stayed closed.", "Rule 269: wuyumbu."),
    ("lexicon", "Bayil was admitted as perch only; freshwater/jungle prose and bayilbayil drift stayed closed.", "Rule 269: bayil."),
    ("lexicon", "Dalmbal was admitted as flathead only; dukul-barangka synonym/source prose stayed closed.", "Rule 269: dalmbal."),
    ("lexicon", "Balarri was admitted as queenfish only; catching, water, and habitat readings stayed closed.", "Rule 269: balarri."),
    ("lexicon", "Bilmbin was admitted as black-tip shark only; black-tip ray, mangrove, river, danger, bite, and habitat prose stayed closed.", "Rule 269: bilmbin."),
    ("lexicon", "Jalkay was admitted as salmon only; fish-use, food, water, and habitat readings stayed closed.", "Rule 269: jalkay."),
    ("lexicon", "Jijirr was admitted as red bream only; colour-predicate, reef/habitat, catching, and food readings stayed closed.", "Rule 269: jijirr."),
    ("morphology", "All Rule 269 target nouns stayed bare: no LOC, DAT, ABL, PERL, ERG, INST, COMIT, POSS, PRIV, EXCESS, plural, derivation, or target suffix was admitted.", "Rule 269: bare targets."),
    ("morphology", "English modifiers inside fish labels, such as black, red, queen, black-tip, and archer, remained lexical-label prose rather than Kuku morphology or separate predicates.", "Rule 269: 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 269: 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 269: uninflected support."),
    ("morphology", "No target compound, lexicalized trap compound, or productive reduplication was built from the fish heads.", "Rule 269: no compounds or reduplication."),
    ("syntax", "Rows 1-10 used Ngali TARGET yaluy nyajil.", "Rule 269: 1du exclusive here perception band."),
    ("syntax", "Rows 11-20 used Ngaliny TARGET yinyay nyajil.", "Rule 269: 1du inclusive there perception band."),
    ("syntax", "Rows 21-30 used Yubal TARGET yaluy nyajil.", "Rule 269: 2du here perception band."),
    ("syntax", "Rows 31-40 used Nganjin TARGET yinyay nyajil.", "Rule 269: 1pl exclusive there perception band."),
    ("syntax", "Rows 41-50 used Ngana TARGET yaluy nyajil.", "Rule 269: 1pl inclusive here perception band."),
    ("fidelity", "English stayed literal perception/reference prose: subject pronoun, selected fish label, here/there, and see only.", "Rule 269: literal English."),
    ("fidelity", "The batch did not convert dictionary examples, alternate glosses, or source prose into catching, netting, hook/line, spearing, eating, cooking, bait, taboo, storm/thunder, story/place, water/river/sea/reef/habitat, fish body-part, colour, danger, bite, injury, source-material, or event claims.", "Rule 269: source-prose restraint."),
    ("register", "Rows remained plain elicitation-style perception clauses; no fishing report, food statement, habitat claim, danger warning, taboo, story, or storm register was introduced.", "Rule 269: register."),
    ("process", "Rules 149-268 carry-forward traps stayed closed, especially fish use/action/body/habitat/source-prose traps, bird event/use/lore traps, mammal-source-prose traps, reptile/amphibian 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 269: carry-forward closure."),
    ("handoff", "Next batch may continue from 15,647 if this closes; do not infer fish catching, eating, cooking, water, reef, habitat, body-part, alternate target, source-prose, target-case, pronoun-case, demonstrative-case, perception-compound, purposive, past, or support-inflection grammar from Rule 269.", "Rule 269: next cadence."),
]

LEXEMES = [
    ("kubija", "noun", None, "NA", "barracuda", "batch-311: barracuda perception/reference only; garfish alternate and source prose closed."),
    ("mujarrka", "noun", None, "NA", "archerfish", "batch-311: archerfish perception/reference only; spotted-Jewfish/Nyungkul-dalku/fresh-saltwater/habitat prose closed."),
    ("barrbal", "noun", None, "NA", "black bream", "batch-311: black-bream perception/reference only; colour/habitat/catching/food readings closed."),
    ("wuyumbu", "noun", None, "NA", "toadfish", "batch-311: toadfish perception/reference only; striped-toby and generic-fish prose closed."),
    ("bayil", "noun", None, "NA", "perch", "batch-311: perch perception/reference only; freshwater/jungle/bayilbayil drift closed."),
    ("dalmbal", "noun", None, "NA", "flathead", "batch-311: flathead perception/reference only; dukul-barangka synonym/source prose closed."),
    ("balarri", "noun", None, "NA", "queenfish", "batch-311: queenfish perception/reference only; catching/water/habitat readings closed."),
    ("bilmbin", "noun", None, "NA", "black-tip shark", "batch-311: black-tip-shark perception/reference only; black-tip-ray/mangrove/river/danger/bite/habitat prose closed."),
    ("jalkay", "noun", None, "NA", "salmon", "batch-311: salmon perception/reference only; fish-use/food/water/habitat readings closed."),
    ("jijirr", "noun", None, "NA", "red bream", "batch-311: red-bream perception/reference only; colour/habitat/catching/food readings closed."),
    ("ngali", "pronoun", None, "NA", "first dual exclusive nominative", "batch-311: bare nominative subject support only."),
    ("ngaliny", "pronoun", None, "NA", "first dual inclusive nominative", "batch-311: bare nominative subject support only."),
    ("yubal", "pronoun", None, "NA", "second dual nominative", "batch-311: bare nominative subject support only."),
    ("nganjin", "pronoun", None, "NA", "first plural exclusive nominative", "batch-311: bare nominative subject support only."),
    ("ngana", "pronoun", None, "NA", "first plural inclusive nominative", "batch-311: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-311: bare local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-311: bare local demonstrative support only."),
    ("nyajil", "verb", "l", "NA", "see", "batch-311: 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-311-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 269 rows. Morphology checked bare fish nouns, bare nominative non-singular pronouns, bare yaluy/yinyay, and nyajil nonpast only. Lexicon checked selected fish 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 garfish/spotted-Jewfish/dalku/striped-toby/black-tip-ray/dukul-barangka drift; syntax one bare nominative non-singular subject plus target plus local demonstrative plus nyajil; fidelity no fish use/habitat/source prose; register no story, taboo, warning, fishing, or food 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 269 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 fish 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 269 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-311-verify'"
    ).fetchone()[0]
    record_event(
        db,
        batch_label=LABEL,
        phase="close",
        event_type="close-success",
        actor="claude-main",
        detail=f"Closed Batch 311 / Rule 269 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_311.py",
        output_excerpt=f"closed batch-311: 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())
