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

NOTES = (
    "COMPLEMENTARY SHELLFISH/CRUSTACEAN PERCEPTION DEBT SWEEP AFTER RULE 257 (Rule 258). 50 rows. TARGETS: "
    "baymbay large mud clam, darkay clam, kaduy snail, karraway karraway snail, karruku ghost crab, kulil "
    "jellyfish, kuyalin small conical shellfish, marrkabina oyster, ngarrakaja shellfish, and nuwi squid. SUPPORT: "
    "bare nominative ngayu, nyulu, yurra, bula, and jana plus yaluy/yinyay and nyajil. FRAMES: Ngayu TARGET yinyay "
    "nyajil, Nyulu TARGET yaluy nyajil, Yurra TARGET yinyay nyajil, Bula TARGET yaluy nyajil, and Jana TARGET "
    "yinyay nyajil. REVIEW: no Rule 171 or Rule 223 shellfish alternate target, no jirrum, no synonym expansion, "
    "no edible, food, eating, bait, use, cooking, frying, gathering, collecting, catching, fishing, spearing, "
    "netting, sea, reef, rock, night, habitat, water, shell/body-part, sting, burn, ink/action, movement, danger, "
    "event, species expansion, secondary label, target case, target compound, productive reduplication, pronoun "
    "case, demonstrative case, perception compound, purposive, past, or support inflection was opened."
)

LESSONS = [
    ("source", "Rule 258 retained the same ten checked Rule 213 shellfish/crustacean noun heads as Rule 257: baymbay, darkay, kaduy, karraway, karruku, kulil, kuyalin, marrkabina, ngarrakaja, and nuwi.", "Rule 258: target inventory."),
    ("source", "Dictionary line readback was explicit: baymbay 2122-2130, darkay 5280-5289, kaduy 11964-11974, karraway 13592-13601, karruku 13701-13709, kulil 15209-15220, kuyalin 16857-16866, marrkabina 18639-18647, ngarrakaja 22791-22801, and nuwi 24261-24271.", "Rule 258: dictionary source lines."),
    ("source", "Patz grammar lines 2553-2603 supplied the bare nominative pronoun forms used as subject support in this batch.", "Rule 258: pronoun source."),
    ("source", "Patz Table 3.12 lines 2838-2845 supplied Yalanji yaluy 'here' and yinyay 'there'; Rule 258 used only the bare local demonstratives.", "Rule 258: demonstrative source."),
    ("source", "Patz section 3.8.3.2 lines 3043-3049 supplied nyaji-l 'see'; Rule 258 used only the nonpast form nyajil and did not build perception compounds or purposive rows.", "Rule 258: perception source."),
    ("process", "Hard exclusions retained: Rule 171 and Rule 223 shellfish/crustacean alternates, jirrum, synonyms and source-prose alternates, all food/use/habitat/body/event fields, and all target/support morphology traps.", "Rule 258: hard exclusions."),
    ("process", "Exact duplicate preflight over all 50 planned Rule 258 Kuku surfaces returned no accepted, revised, or under-review collisions.", "Rule 258: duplicate preflight."),
    ("process", "Token-aware target coverage before banking after Rule 257 was baymbay 11, darkay 16, kaduy 11, karraway 10, karruku 11, kulil 12, kuyalin 10, marrkabina 10, ngarrakaja 10, and nuwi 11.", "Rule 258: target coverage audit."),
    ("process", "Support coverage before banking after Rule 257 was ngayu 1293, nyulu 1774, yurra 223, bula 203, jana 1496, yaluy 2303, yinyay 2546, and nyajil 2717.", "Rule 258: support coverage audit."),
    ("lexicon", "Baymbay was admitted as large mud clam only; gathering, cooking, eating, sea, reef, and habitat readings stayed closed.", "Rule 258: baymbay."),
    ("lexicon", "Darkay was admitted as clam only; small-mud-clam source detail did not open independent size, mud, water, or habitat claims.", "Rule 258: darkay."),
    ("lexicon", "Kaduy was admitted as snail only; night and nocturnal source detail stayed closed.", "Rule 258: kaduy."),
    ("lexicon", "Karraway was admitted as karraway snail only; edible and food readings stayed closed.", "Rule 258: karraway."),
    ("lexicon", "Karruku was admitted as ghost crab only; fiddler-crab expansion, movement, and habitat readings stayed closed.", "Rule 258: karruku."),
    ("lexicon", "Kulil was admitted as jellyfish only; mili and wuybur synonyms, sting, burn, danger, and event readings stayed closed.", "Rule 258: kulil."),
    ("lexicon", "Kuyalin was admitted as small conical shellfish only; bait and use readings stayed closed.", "Rule 258: kuyalin."),
    ("lexicon", "Marrkabina was admitted as oyster only; edible and food readings stayed closed.", "Rule 258: marrkabina."),
    ("lexicon", "Ngarrakaja was admitted as shellfish only; species and edible prose stayed closed.", "Rule 258: ngarrakaja."),
    ("lexicon", "Nuwi was admitted as squid only; ink-throwing action/event prose stayed closed.", "Rule 258: nuwi."),
    ("morphology", "All Rule 258 target nouns stayed bare: no LOC, DAT, ABL, PERL, ERG, INST, COMIT, POSS, PRIV, EXCESS, plural, derivation, or target suffix was admitted.", "Rule 258: bare targets."),
    ("morphology", "English modifiers inside shellfish labels, such as large, mud, karraway, ghost, small, and conical, remained lexical-label material rather than Kuku morphology or separate predicates.", "Rule 258: label morphology guard."),
    ("morphology", "The subject support forms stayed bare nominatives: no pronoun case forms, possessive readings, or person/number extensions were introduced.", "Rule 258: 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 258: uninflected support."),
    ("morphology", "No target compound, lexicalized trap compound, or productive reduplication was built from the shellfish/crustacean heads.", "Rule 258: no compounds or reduplication."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yinyay nyajil.", "Rule 258: 1sg there perception band."),
    ("syntax", "Rows 11-20 used Nyulu TARGET yaluy nyajil.", "Rule 258: 3sg here perception band."),
    ("syntax", "Rows 21-30 used Yurra TARGET yinyay nyajil.", "Rule 258: 2pl there perception band."),
    ("syntax", "Rows 31-40 used Bula TARGET yaluy nyajil.", "Rule 258: 3du here perception band."),
    ("syntax", "Rows 41-50 used Jana TARGET yinyay nyajil.", "Rule 258: 3pl there perception band."),
    ("fidelity", "English stayed literal perception/reference prose: subject pronoun, selected shellfish/crustacean label, here/there, and see only.", "Rule 258: literal English."),
    ("fidelity", "The batch did not convert dictionary examples, gloss modifiers, synonyms, or source prose into edible, food, eating, bait, use, cooking, frying, gathering, collecting, catching, fishing, spearing, netting, sea, reef, rock, night, habitat, water, shell/body-part, sting, burn, ink/action, movement, danger, event, species, or secondary-label claims.", "Rule 258: source-prose restraint."),
    ("register", "Rows remained plain elicitation-style perception clauses; no fishing report, food statement, gathering statement, habitat note, warning, injury statement, source-prose note, or lore register was introduced.", "Rule 258: register."),
    ("process", "Rules 149-257 carry-forward traps stayed closed, especially insect, mammal, reptile/amphibian, fish, bird, dwelling/household, landform/geography, body-part, fire, flora, artefact, weapon, weather, water, route/travel, implement, and shellfish source-prose drift.", "Rule 258: carry-forward closure."),
    ("handoff", "Next batch may continue from 15,097 if this closes; do not infer shellfish/crustacean behavior, food, use, habitat, source-prose, synonym, target-case, pronoun-case, demonstrative-case, perception-compound, or support-inflection grammar from Rule 258.", "Rule 258: next cadence."),
]

LEXEMES = [
    ("baymbay", "noun", None, "NA", "large mud clam", "batch-300: large-mud-clam perception/reference only; gathering, cooking, eating, sea, reef, and habitat readings closed."),
    ("darkay", "noun", None, "NA", "clam", "batch-300: clam perception/reference only; size, mud, water, and habitat claims closed."),
    ("kaduy", "noun", None, "NA", "snail", "batch-300: snail perception/reference only; night/nocturnal prose closed."),
    ("karraway", "noun", None, "NA", "karraway snail", "batch-300: karraway-snail perception/reference only; edible and food readings closed."),
    ("karruku", "noun", None, "NA", "ghost crab", "batch-300: ghost-crab perception/reference only; fiddler-crab expansion, movement, and habitat readings closed."),
    ("kulil", "noun", None, "NA", "jellyfish", "batch-300: jellyfish perception/reference only; mili/wuybur synonyms, sting, burn, danger, and event readings closed."),
    ("kuyalin", "noun", None, "NA", "small conical shellfish", "batch-300: small-conical-shellfish perception/reference only; bait and use readings closed."),
    ("marrkabina", "noun", None, "NA", "oyster", "batch-300: oyster perception/reference only; edible and food readings closed."),
    ("ngarrakaja", "noun", None, "NA", "shellfish", "batch-300: shellfish perception/reference only; species and edible prose closed."),
    ("nuwi", "noun", None, "NA", "squid", "batch-300: squid perception/reference only; ink-throwing action/event prose closed."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-300: bare nominative subject support only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-300: bare nominative subject support only."),
    ("yurra", "pronoun", None, "NA", "second plural nominative", "batch-300: bare nominative subject support only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-300: bare nominative subject support only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-300: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-300: bare local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-300: bare local demonstrative support only."),
    ("nyajil", "verb", "l", "NA", "see", "batch-300: 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-300-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 258 rows. Morphology checked bare shellfish/crustacean nouns, bare nominative pronouns, bare yaluy/yinyay, and nyajil nonpast only. Lexicon checked selected shellfish/crustacean 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 171 or Rule 223 alternate target, no jirrum, no synonym expansion, no edible/food/eating row, no bait/use row, no cooking/frying row, no gathering/collecting/catching/fishing/spearing/netting row, no sea/reef/rock/night/habitat/water row, no shell/body-part row, no sting/burn row, no ink/action/event row, no secondary-label expansion, 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 258 lessons covering source checks, lexical target senses, hard exclusions, morphology, syntax, fidelity, register, process traps, and handoff.",
        artifact_path="batch_scripts/close_300.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 258 targets and support heads.",
        artifact_path="batch_scripts/close_300.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 300: 50 accepted Rule 258 complementary shellfish/crustacean perception rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_300.py",
        artifact_path="batch_scripts/close_300.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-300-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())
