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

NOTES = (
    "NAMED-TREE PERCEPTION CONSOLIDATION AFTER RULE 230 (Rule 231). 50 rows. TARGETS: "
    "bingkajiri, durral, kalbariji, kalkuri, kuji-kuji, kuralbi, kuray-kuray, mingur, mukukana, and "
    "mungka-mungka. SUPPORT: bare pronoun A forms ngayu/yundu/nyulu/ngana/jana, local yaluy/yinyay, nonpast nyajil, "
    "and past nyajin. FRAMES: Ngayu TARGET yaluy nyajil, Yundu TARGET yinyay nyajil, Nyulu TARGET yinyay nyajil, "
    "Ngana TARGET yaluy nyajil, and Jana TARGET yinyay nyajin. REVIEW: all target nouns stayed bare named-tree labels. "
    "No new tree target, no earlier flora/tree exact-target repeat, no no-definition target, no fruit/food/seed row, "
    "no medicine/poison/blinding row, no bark/wood/spear/rope/material row, no thorn/branch row, no habitat/ecology/"
    "place/story/use row, no target case, no pronoun case, no perception compound, no productive reduplication, and "
    "no support inflection was opened."
)

LESSONS = [
    ("source", "Patz section 3.5 supports bare nominative pronouns ngayu, yundu, nyulu, ngana, and jana in A/S function.", "Rule 231: pronoun source."),
    ("source", "Patz section 3.7 supports yaluy and yinyay as local demonstratives; Rule 231 uses only the bare local forms.", "Rule 231: local demonstratives."),
    ("source", "Patz examples and prior corpus law support nyaji-l perception with nonpast nyajil and past nyajin.", "Rule 231: perception source."),
    ("source", "Rule 230 verified the ten named-tree heads as bare tree-reference labels; Rule 231 changes construction only.", "Rule 231: target source."),
    ("process", "Exact preflight over all 50 planned Rule 231 perception surfaces returned no collisions.", "Rule 231: duplicate preflight."),
    ("lexicon", "Bingkajiri stayed bingkajiri-tree object only; no long-seed, eating, or blinding story was opened.", "Rule 231: bingkajiri."),
    ("lexicon", "Durral stayed durral-tree object only; no edible-fruit, spear, or wood-source row was opened.", "Rule 231: durral."),
    ("lexicon", "Kalbariji stayed kalbariji-tree object only; finger-cherry source wording did not license fruit or food prose.", "Rule 231: kalbariji."),
    ("lexicon", "Kalkuri stayed kalkuri-tree object only; woollybutt/Melaleuca source wording did not license gum, timber, or material prose.", "Rule 231: kalkuri."),
    ("lexicon", "Kuji-kuji stayed kuji-kuji-tree object only; the hyphenated lexical reduplication stayed a whole dictionary headword.", "Rule 231: kuji-kuji."),
    ("lexicon", "Kuralbi stayed kuralbi-tree object only despite two older bark-source rows; bark, rope, and material-source readings stayed closed.", "Rule 231: kuralbi."),
    ("lexicon", "Kuray-kuray stayed kuray-kuray-tree object only; the hyphenated lexical reduplication stayed a whole dictionary headword.", "Rule 231: kuray-kuray."),
    ("lexicon", "Mingur stayed mingur-tree object only; oilnut, roasting, and cosmetic source prose stayed closed.", "Rule 231: mingur."),
    ("lexicon", "Mukukana stayed mukukana-tree object only; edible-fruit source prose stayed closed.", "Rule 231: mukukana."),
    ("lexicon", "Mungka-mungka stayed mungka-mungka-tree object only; thorn and branch source prose stayed closed.", "Rule 231: mungka-mungka."),
    ("morphology", "All target named-tree nouns stayed bare transitive objects: no target LOC, DAT, ABL, PERL, ERG, INST, COMIT, POSS, PRIV, EXCESS, plural, or derivation.", "Rule 231: bare tree objects."),
    ("morphology", "Hyphenated lexical reduplications kuji-kuji, kuray-kuray, and mungka-mungka stayed whole dictionary headwords, not productive reduplication.", "Rule 231: lexical reduplication."),
    ("morphology", "Pronoun A forms stayed bare nominatives; Rule 231 did not open pronoun case paradigms beyond nominative forms.", "Rule 231: pronoun morphology."),
    ("morphology", "Yaluy, yinyay, nyajil, and nyajin stayed uninflected support/predicate forms.", "Rule 231: support morphology."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yaluy nyajil.", "Rule 231: 1sg nonpast here frame."),
    ("syntax", "Rows 11-20 used Yundu TARGET yinyay nyajil.", "Rule 231: 2sg nonpast there frame."),
    ("syntax", "Rows 21-30 used Nyulu TARGET yinyay nyajil.", "Rule 231: 3sg nonpast there frame."),
    ("syntax", "Rows 31-40 used Ngana TARGET yaluy nyajil.", "Rule 231: 1pl inclusive nonpast here frame."),
    ("syntax", "Rows 41-50 used Jana TARGET yinyay nyajin.", "Rule 231: 3pl past there frame."),
    ("fidelity", "English stayed literal perception prose: pronoun subject, see/saw, selected named-tree label, and here/there.", "Rule 231: literal English."),
    ("fidelity", "The batch did not turn dictionary tree prose into fruit, food, medicine, poison, bark, wood, spear, rope, material, thorn, branch, habitat, place, story, or use claims.", "Rule 231: source-prose restraint."),
    ("register", "Rows remained plain elicitation-style perception statements, not ecological description, resource-use instruction, medicine talk, story prose, or material-culture narrative.", "Rule 231: register."),
    ("process", "Duplicate preflight, static guards, whole-corpus lint, five-lens review, lessons, lexeme logs, export, and live docs are required before treating Rule 231 as complete.", "Rule 231: evidence standard."),
    ("handoff", "Next batch may continue from 13,747 if this closes; do not infer named-tree fruit, food, medicine, material, habitat, story, place, use, or perception-compound grammar from Rule 231.", "Rule 231: next cadence."),
]

LEXEMES = [
    ("bingkajiri", "noun", None, "NA", "bingkajiri tree", "batch-273: bingkajiri-tree object in perception frames only."),
    ("durral", "noun", None, "NA", "durral tree", "batch-273: durral-tree object only; no fruit/spear/wood row."),
    ("kalbariji", "noun", None, "NA", "kalbariji tree", "batch-273: kalbariji-tree object only; no finger-cherry food row."),
    ("kalkuri", "noun", None, "NA", "kalkuri tree", "batch-273: kalkuri-tree object only; no gum/timber/material row."),
    ("kuji-kuji", "noun", None, "NA", "kuji-kuji tree", "batch-273: whole hyphenated lexical tree head."),
    ("kuralbi", "noun", None, "NA", "kuralbi tree", "batch-273: kuralbi-tree object only; no bark/rope/material row."),
    ("kuray-kuray", "noun", None, "NA", "kuray-kuray tree", "batch-273: whole hyphenated lexical tree head."),
    ("mingur", "noun", None, "NA", "mingur tree", "batch-273: mingur-tree object only; no oilnut/roasting/cosmetic row."),
    ("mukukana", "noun", None, "NA", "mukukana tree", "batch-273: mukukana-tree object only; no edible-fruit row."),
    ("mungka-mungka", "noun", None, "NA", "mungka-mungka tree", "batch-273: whole hyphenated lexical tree head; no thorn/branch row."),
    ("ngayu", "personal-pronoun", None, "NA", "I", "batch-273: bare 1sg nominative A."),
    ("yundu", "personal-pronoun", None, "NA", "you", "batch-273: bare 2sg nominative A."),
    ("nyulu", "personal-pronoun", None, "NA", "he; she; it", "batch-273: bare 3sg nominative A."),
    ("ngana", "personal-pronoun", None, "NA", "we plural inclusive", "batch-273: bare 1pl inclusive nominative A."),
    ("jana", "personal-pronoun", None, "NA", "they", "batch-273: bare 3pl nominative A."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-273: local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-273: local demonstrative support only."),
    ("nyajil", "verb", "l", None, "perceive nonpast", "batch-273: nonpast nyaji-l perception predicate."),
    ("nyajin", "verb", "l", None, "perceive past", "batch-273: past nyaji-l perception predicate."),
]


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.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-273-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 231 rows. Morphology checked bare tree objects, bare nominative pronoun A forms, local demonstratives, lexicalized hyphenated reduplications, and uninflected nyajil/nyajin. Lexicon checked selected tree labels only. Syntax checked five perception frame bands. Fidelity checked literal perception English. Register stayed plain elicitation-style perception statement.",
        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 new tree target, no earlier flora/tree exact-target repeat, no no-definition target, no fruit/food/seed row, no medicine/poison/blinding row, no bark/wood/spear/rope/material row, no thorn/branch row, no habitat/ecology/place/story/use row, no target case, no pronoun case, no perception compound, no productive reduplication, 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 231 lessons covering source checks, construction scope, target senses, morphology, syntax, fidelity, register, and handoff.",
        artifact_path="batch_scripts/close_273.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 231 targets and support heads.",
        artifact_path="batch_scripts/close_273.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 273: 50 accepted Rule 231 named-tree perception consolidation rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_273.py",
        artifact_path="batch_scripts/close_273.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]
    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}, verified {verified_before}->{verified_after}, "
        f"kuku_words {words_before}->{words_after}"
    )
    return 0


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