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

NOTES = (
    "DWELLING/HOUSEHOLD PERCEPTION PRONOUN EXPANSION AFTER RULE 242 (Rule 243). 50 rows. "
    "TARGETS retained: bakarr ridge pole, bayan house, bira windbreak, jiji roof, kilili windbreak, "
    "wurun humpy, jakway door, yulal board, kararr blanket, and bilangkurr blanket. SUPPORT: bare "
    "nominative yulu, ngali, ngaliny, yubal, and nganjin plus yaluy/yinyay and nyajil. FRAMES: "
    "Yulu TARGET yaluy nyajil, Ngali TARGET yinyay nyajil, Ngaliny TARGET yaluy nyajil, "
    "Yubal TARGET yinyay nyajil, and Nganjin TARGET yaluy nyajil. REVIEW: yulu is the Patz Table 3.6 "
    "less-common free variant of nyulu; no ngana/yundu collision bands, yamba/opium/particle/none homograph, "
    "jakal mouse/full/front homograph, warrbi axe/beehive-house homograph, building/setting/spreading/entering/"
    "nailing action, roofing/source-material prose, sleeping/covering/warming use, front/open/shut extension, "
    "plank/round-stick contrast, top-of-anything extension, target case, target compound, productive reduplication, "
    "pronoun case, perception compound, support inflection, or recent fish/bird/fire drift was opened."
)

LESSONS = [
    ("source", "Rule 243 retained the ten checked Rule 238 dwelling/household noun heads: bakarr, bayan, bira, jiji, kilili, wurun, jakway, yulal, kararr, and bilangkurr.", "Rule 243: retained target inventory."),
    ("source", "Patz section 3.5 Table 3.6 supplied yulu as a less common free variant of nyulu and supplied bare nominative ngali, ngaliny, yubal, and nganjin.", "Rule 243: pronoun source."),
    ("source", "Patz section 3.7 supplied Yalanji yaluy 'here' and yinyay 'there'; Rule 243 used only the bare local demonstratives and did not add case-marked local forms.", "Rule 243: demonstrative source."),
    ("source", "Patz section 3.8.3.2 supplied nyaji-l 'see'; Rule 243 used only nonpast nyajil and did not build perception compounds or purposive/infinitive rows.", "Rule 243: perception source."),
    ("process", "A simple complementary Rule 239 dwelling grid was rejected before banking because Nyulu TARGET yinyay nyajil and several Ngayu TARGET yaluy nyajil surfaces collided with older accepted rows.", "Rule 243: rejected complementary grid."),
    ("process", "Ngana and yundu full bands were rejected because both local-demonstrative values collided on jakway, yulal, and bilangkurr surfaces.", "Rule 243: rejected pronoun bands."),
    ("process", "Exact duplicate preflight over all 50 final Rule 243 Kuku surfaces returned no accepted, revised, or under-review collisions.", "Rule 243: duplicate preflight."),
    ("process", "Token-boundary target coverage before banking after Rule 242 was bakarr 10, jiji 10, kilili 10, bira 11, jakway 20, yulal 20, bilangkurr 27, kararr 27, wurun 33, and bayan 436.", "Rule 243: target coverage audit."),
    ("process", "Pronoun coverage before banking was ngaliny 13, yubal 24, nganjin 28, ngali 78, ngana 858, and yundu 1174; the batch gave low-count dual/exclusive forms more signal.", "Rule 243: pronoun coverage audit."),
    ("lexicon", "Bakarr remained ridge pole only; pole material, building, structural action, and source-material prose stayed closed.", "Rule 243: bakarr."),
    ("lexicon", "Bayan remained house only in the English rows; camp, shelter, camping, building, ownership, location, and yamba homograph material stayed closed.", "Rule 243: bayan."),
    ("lexicon", "Bira remained windbreak only; making, setting, weather shelter, cold/rain event, and material-source prose stayed closed.", "Rule 243: bira."),
    ("lexicon", "Jiji remained roof only; top-of-anything extension and roofing-material prose stayed closed.", "Rule 243: jiji."),
    ("lexicon", "Kilili remained windbreak only; no construction, weather, source-material, or use row was opened.", "Rule 243: kilili."),
    ("lexicon", "Wurun remained humpy only; halfway translation, locative humpy rows, building, sleeping, and rain-shelter prose stayed closed.", "Rule 243: wurun."),
    ("lexicon", "Jakway remained door only; front sense, open/close/shut predicates, and jakal homograph material stayed closed.", "Rule 243: jakway."),
    ("lexicon", "Yulal remained board only; plank wording, round-stick contrast, nailing, building, and source-material prose stayed closed.", "Rule 243: yulal."),
    ("lexicon", "Kararr remained blanket only; sheet, grass bedding, spreading, sleeping, covering, warming, and year-counting extensions stayed closed.", "Rule 243: kararr."),
    ("lexicon", "Bilangkurr remained blanket only; clothing, sleeping, covering, warming, and ownership rows stayed closed.", "Rule 243: bilangkurr."),
    ("morphology", "All Rule 243 target nouns stayed bare: no LOC, DAT, ABL, PERL, ERG, INST, COMIT, POSS, PRIV, EXCESS, plural, derivation, or target suffix was admitted.", "Rule 243: bare targets."),
    ("morphology", "The subject support forms stayed bare nominatives: no pronoun case forms, possessive readings, or person/number extensions were introduced.", "Rule 243: bare nominative 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 243: uninflected support."),
    ("morphology", "No target compound, lexicalized trap compound, or productive reduplication was built from the dwelling/household heads.", "Rule 243: no compounds or reduplication."),
    ("syntax", "Rows 1-10 used Yulu TARGET yaluy nyajil.", "Rule 243: 3sg variant here perception band."),
    ("syntax", "Rows 11-20 used Ngali TARGET yinyay nyajil.", "Rule 243: 1du exclusive there perception band."),
    ("syntax", "Rows 21-30 used Ngaliny TARGET yaluy nyajil.", "Rule 243: 1du inclusive here perception band."),
    ("syntax", "Rows 31-40 used Yubal TARGET yinyay nyajil.", "Rule 243: 2du there perception band."),
    ("syntax", "Rows 41-50 used Nganjin TARGET yaluy nyajil.", "Rule 243: 1pl exclusive here perception band."),
    ("fidelity", "English stayed literal perception/reference prose: selected subject pronoun value, target label, here/there, and see only.", "Rule 243: literal English."),
    ("fidelity", "The batch did not convert dictionary examples or source prose into building, setting up camp, spreading blankets, sleeping, covering, warming, entering, nailing, roofing, weather-shelter, or ownership claims.", "Rule 243: source-prose restraint."),
    ("register", "Rows remained plain elicitation-style perception clauses; no ceremonial, mortuary, property, household-use, instruction, storm-preparation, or narrative register was introduced.", "Rule 243: register."),
    ("process", "Rules 149-242 carry-forward traps stayed closed, especially recent fish and bird perception traps, dwelling action/use/source traps, fire action/use/homograph traps, and body-part possession/case/perception drift.", "Rule 243: carry-forward closure."),
    ("handoff", "Next batch may continue from 14,347 if this closes; do not infer shelter-building, camp setup, blanket use, door action, board nailing, source-material, ownership, target case, pronoun case, perception-compound, or support-inflection grammar from Rule 243.", "Rule 243: next cadence."),
]

LEXEMES = [
    ("bakarr", "noun", None, "NA", "ridge pole", "batch-285: ridge-pole perception/reference only; no building, material-source, or use row."),
    ("bayan", "noun", None, "NA", "house", "batch-285: house perception/reference only; no camping, building, possession, locative house, or yamba homograph row."),
    ("bira", "noun", None, "NA", "windbreak", "batch-285: windbreak perception/reference only; no making, setting, weather, or material-source row."),
    ("jiji", "noun", None, "NA", "roof", "batch-285: roof perception/reference only; top-of-anything and roofing-material extensions closed."),
    ("kilili", "noun", None, "NA", "windbreak", "batch-285: windbreak perception/reference only; no construction/weather/source row."),
    ("wurun", "noun", None, "NA", "humpy", "batch-285: humpy perception/reference only; no halfway, building, sleeping, rain-shelter, or locative row."),
    ("jakway", "noun", None, "NA", "door", "batch-285: door perception/reference only; front/open/close/shut and jakal homograph closed."),
    ("yulal", "noun", None, "NA", "board", "batch-285: board perception/reference only; plank, round-stick contrast, nailing, and building prose closed."),
    ("kararr", "noun", None, "NA", "blanket", "batch-285: blanket perception/reference only; sheet/grass bedding/spread/sleep/cover/warm/year-count extensions closed."),
    ("bilangkurr", "noun", None, "NA", "blanket", "batch-285: blanket perception/reference only; clothing/sleep/cover/warm/ownership rows closed."),
    ("yulu", "pronoun", None, "NA", "third singular nominative", "batch-285: less-common free variant of nyulu; bare nominative subject support only."),
    ("ngali", "pronoun", None, "NA", "first dual exclusive nominative", "batch-285: bare nominative subject support only."),
    ("ngaliny", "pronoun", None, "NA", "first dual inclusive nominative", "batch-285: bare nominative subject support only."),
    ("yubal", "pronoun", None, "NA", "second dual nominative", "batch-285: bare nominative subject support only."),
    ("nganjin", "pronoun", None, "NA", "first plural exclusive nominative", "batch-285: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-285: bare local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-285: bare local demonstrative support only."),
    ("nyajil", "verb", "l", "NA", "see", "batch-285: 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-285-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 243 rows. Morphology checked bare dwelling/household nouns, bare nominative yulu/ngali/ngaliny/yubal/nganjin, bare yaluy/yinyay, and nyajil nonpast only. Lexicon checked selected target senses only. Syntax checked five 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 yamba/opium/particle/none homograph, no jakal mouse/full/front homograph, no warrbi axe/beehive-house homograph, no building/setting/spreading/entering/nailing action, no roofing/source-material prose, no sleeping/covering/warming use, no front/open/shut extension, no plank/round-stick contrast, no top-of-anything extension, no target case, no productive compound, no productive reduplication, no pronoun case, no perception compound, no support inflection, and no recent fish/bird/fire drift.",
        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 243 lessons covering source checks, rejected collision grids, lexical target senses, morphology, syntax, fidelity, register, process traps, and handoff.",
        artifact_path="batch_scripts/close_285.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 243 targets and support heads.",
        artifact_path="batch_scripts/close_285.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 285: 50 accepted Rule 243 dwelling/household pronoun-expansion rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_285.py",
        artifact_path="batch_scripts/close_285.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-285-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())
