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

NOTES = (
    "ZERO-USE ANATOMY/BODY-SURFACE NON-SINGULAR NONPAST PERCEPTION SWEEP AFTER RULE 321 (Rule 322). 50 rows. "
    "TARGETS: dalkari bladder, diburr-miyil eyeball, jadalangka animal leg, mijan wart, mungka-dirka fur, "
    "murrka scar, nyirribulu appendix, waral stomach, wubun hump, yinkan ribs. SUPPORT: bare nominative ngali, "
    "ngaliny, yubal, yurra, ngana; Yalanji yaluy/yinyay; dictionary-attested nonpast nyajil. Bare targets assert no "
    "possessor. No compound decomposition, possession, person/animal attribution beyond lexical labels, pain/illness/"
    "medicine/surgery, injury/ritual/initiation, butchery/food/hunting, material use, property, target case, past/"
    "purposive/reduplicated perception, support inflection, or carried trap was opened."
)

LESSONS = [
    ("source", "Rule 322 selected ten direct-dictionary, noun-typed, zero-use anatomy/body-surface heads: dalkari, diburr-miyil, jadalangka, mijan, mungka-dirka, murrka, nyirribulu, waral, wubun, and yinkan.", "Rule 322: zero-use anatomy inventory."),
    ("source", "Dictionary lines reread: dalkari 4857-4865, diburr-miyil 5502-5512, jadalangka 6975-6985, mijan 18891-18899, mungka-dirka 20646-20656, murrka 21045-21057, nyirribulu 24623-24631, waral 26326-26335, wubun 27509-27517, yinkan 30271-30280.", "Rule 322: dictionary source lines."),
    ("source", "Exact Patz searches found waral once at line 2173 in derived possessed waral-ji-mu and found none of the other nine target heads. The positive and negative results were both recorded; dictionary entries remain the lexical source for all target surfaces.", "Rule 322: Patz target occurrence audit."),
    ("source", "Patz line 1476 classifies internal/external body parts and excretions as nouns; examples at lines 4761-4771 and 5431 show bare body-part nouns with contextual possessors; section 4.5.2 lines 5898-5917 distinguishes possessive/appositional structures when possession is asserted. Rule 322 asserts no possessor.", "Rule 322: body-part noun and possession boundary."),
    ("source", "Patz lines 2577-2582 and 2674-2684 source non-singular nominatives; lines 2834-2847 Yalanji yaluy/yinyay; 3043-3049 nonpast nyaji-l; 3149-3151 present/future function; 4256-4265 perception A/O syntax; dictionary 24282-24296 running-form nyajil.", "Rule 322: construction source."),
    ("source", "The 31-head zero-use body-part audit excluded type-mislabeled ngarran and wulbar, dialect-only and homograph-heavy heads, unresolved kurrburrbun/kuburrubun near-variants, and witchcraft/place-heavy candidates. Selected prior deferrals are reopened only for narrow reference.", "Rule 322: candidate exclusions."),
    ("process", "Rule 322 was scoped as bare zero-use anatomy/body-surface reference in non-singular nonpast visual perception, not possession, medicine, ritual, butchery, food, hunting, material use, body property, or event content.", "Rule 322: bounded lexical-debt scope."),
    ("process", "All 50 rows were explicit authored calls; static contracts, row-level linter probes, internal uniqueness, and corpus exact-collision preflight all passed before banking.", "Rule 322: authorship and preflight."),
    ("process", "Every selected target had zero accepted/revised token coverage before banking.", "Rule 322: target coverage audit."),
    ("process", "Support coverage before banking was ngali 533, ngaliny 475, yubal 485, yurra 470, ngana 1055, yaluy 3892, yinyay 4144, nyajil 3997.", "Rule 322: support coverage audit."),
    ("lexicon", "Dalkari was retained as bladder only; possession, person/animal attribution, urine/excretion, pain, illness, medicine, surgery, butchery, use, and event content stayed closed.", "Rule 322: dalkari."),
    ("lexicon", "Diburr-miyil was retained as one eyeball head; decomposition, productive compounding, seed/egg and eye-part claims, possession, injury, vision state, medicine, use, and event content stayed closed.", "Rule 322: diburr-miyil."),
    ("lexicon", "Jadalangka was retained as animal leg only; species, possession, movement, injury, butchery, food, hunting, cutting, carrying, use, and event content stayed closed.", "Rule 322: jadalangka."),
    ("lexicon", "Mijan was retained as wart only; possession, body location, pain, illness, contagion, medicine, removal, treatment, size, number, property, and event content stayed closed.", "Rule 322: mijan."),
    ("lexicon", "Mungka-dirka was retained as one fur head; decomposition, productive compounding, animal/species source, possession, colour, texture, clothing/material use, removal, hunting, and event content stayed closed.", "Rule 322: mungka-dirka."),
    ("lexicon", "Murrka was retained as scar only; scab, initiation/scarification, ritual, possession, injury cause, open wound, pain, medicine, healing, cultural practice, and event content stayed closed.", "Rule 322: murrka."),
    ("lexicon", "Nyirribulu was retained as appendix only; possession, person/animal attribution, pain, inflammation, illness, diagnosis, surgery, medicine, butchery, function, and event content stayed closed.", "Rule 322: nyirribulu."),
    ("lexicon", "Waral was retained as stomach only; belly alternation, possession, pregnancy, hunger, eating, digestion, pain, illness, greed compounds, medicine, butchery, and event content stayed closed.", "Rule 322: waral."),
    ("lexicon", "Wubun was retained as hump only; Brahman/bull attribution, possession, size, shape, back location, movement, burden, property, use, and event content stayed closed.", "Rule 322: wubun."),
    ("lexicon", "Yinkan was retained as ribs only; side alternation, possession, number morphology, body location, pain, injury, breathing, butchery, food, movement, lying-sideways expression, and event content stayed closed.", "Rule 322: yinkan."),
    ("morphology", "All Rule 322 anatomy heads stayed bare absolutive objects. Bare reference does not assert a possessor; no possessive pronoun, whole-part apposition, case, number suffix, derivation, or target morphology was added.", "Rule 322: bare target and possession boundary."),
    ("morphology", "Diburr-miyil and mungka-dirka were copied as indivisible dictionary compounds. No component was emitted separately and no productive compound, decomposition, or semantic inheritance was licensed.", "Rule 322: lexicalized compound restraint."),
    ("morphology", "All subject forms stayed bare nominatives; no accusative, dative, locative, ablative, comitative, possessive, alternative, expanded, or non-selected pronoun was admitted.", "Rule 322: bare pronoun A forms."),
    ("morphology", "Yaluy, yinyay, and nyajil stayed fixed support; no demonstrative case, past nyajin, purposive nyaji-nka, reduplicated watching, hearing compound, or perception compound was admitted.", "Rule 322: fixed support morphology."),
    ("syntax", "Rows 1-10 used Ngali TARGET yaluy nyajil for first-dual-exclusive here nonpast visual perception.", "Rule 322: 1du exclusive here band."),
    ("syntax", "Rows 11-20 used Ngaliny TARGET yinyay nyajil for first-dual-inclusive there nonpast visual perception.", "Rule 322: 1du inclusive there band."),
    ("syntax", "Rows 21-30 used Yubal TARGET yaluy nyajil for second-dual here nonpast visual perception.", "Rule 322: 2du here band."),
    ("syntax", "Rows 31-40 used Yurra TARGET yinyay nyajil for second-plural there nonpast visual perception.", "Rule 322: 2pl there band."),
    ("syntax", "Rows 41-50 used Ngana TARGET yaluy nyajil for first-plural-inclusive here nonpast visual perception.", "Rule 322: 1pl inclusive here band."),
    ("fidelity", "English stayed literal nonpast visual-perception/reference prose: selected subject value, conservative source-backed anatomy label, here/there, and see only. Definite reference supplies discourse identifiability, not possession.", "Rule 322: literal English."),
    ("fidelity", "No dictionary commentary, Patz possession example, compound analysis, or earlier corpus row was converted into possession, medical, ritual, animal-source, butchery, food, use, property, or event claims.", "Rule 322: source and prior-row restraint."),
    ("register", "Rows remained plain elicitation-style visual-reference clauses. Internal anatomy is referentially available without introducing clinical, surgical, ritual, butchery, hunting, food, or narrative register.", "Rule 322: register."),
    ("process", "Every Rule 322 sentence is an explicit sequence-specific row call with exact Kuku, English, analysis, evidence, and confidence contracts; no runtime generator authored content.", "Rule 322: explicit-row authorship evidence."),
    ("process", "Rules 149-321 carry-forward traps stayed closed, including earlier body-part possession/medical/ritual/animal-source deferrals plus source-prose, homograph, case, compound, productive-reduplication, and support-inflection traps.", "Rule 322: cumulative trap closure."),
    ("handoff", "Next batch may continue from 18,297 if this closes; Rule 323 requires a fresh source and coverage audit and must not infer closed anatomy possession, medical, ritual, animal-source, compound, case, perception, or support fields.", "Rule 322: next cadence."),
]

LEXEMES = [
    ("dalkari", "noun", None, "NA", "bladder", "batch-364: bare bladder nonpast-perception reference only; possession, attribution, excretion, pain/illness/medicine/surgery, butchery/use/event closed."),
    ("diburr-miyil", "noun", None, "NA", "eyeball", "batch-364: indivisible eyeball head in bare reference only; decomposition, seed/egg, eye-part, possession, injury/vision/medicine/use/event closed."),
    ("jadalangka", "noun", None, "NA", "animal leg", "batch-364: animal-leg reference only; species, possession, movement/injury, butchery/food/hunting, cutting/carrying/use/event closed."),
    ("mijan", "noun", None, "NA", "wart", "batch-364: wart reference only; possession/location, pain/illness/contagion, medicine/removal/treatment, property/number/event closed."),
    ("mungka-dirka", "noun", None, "NA", "fur", "batch-364: indivisible fur head in bare reference only; decomposition, source/species, possession, colour/texture, clothing/material/removal/hunting/event closed."),
    ("murrka", "noun", None, "NA", "scar", "batch-364: scar reference only; scab/initiation/scarification/ritual, possession/injury/open wound, pain/medicine/healing/cultural-event closed."),
    ("nyirribulu", "noun", None, "NA", "appendix", "batch-364: appendix reference only; possession/attribution, pain/inflammation/illness/diagnosis/surgery/medicine, butchery/function/event closed."),
    ("waral", "noun", None, "NA", "stomach", "batch-364: bare stomach reference only; belly alternation, possession/pregnancy, hunger/eating/digestion, pain/illness/greed/medicine/butchery/event closed."),
    ("wubun", "noun", None, "NA", "hump", "batch-364: hump reference only; Brahman/bull attribution, possession, size/shape/back, movement/burden/property/use/event closed."),
    ("yinkan", "noun", None, "NA", "ribs", "batch-364: ribs reference only; side alternation, possession/number/location, pain/injury/breathing, butchery/food/movement/sideways/event closed."),
    ("ngali", "pronoun", None, "NA", "first dual exclusive nominative", "batch-364: bare nominative subject support only."),
    ("ngaliny", "pronoun", None, "NA", "first dual inclusive nominative", "batch-364: bare nominative subject support only."),
    ("yubal", "pronoun", None, "NA", "second dual nominative", "batch-364: bare nominative subject support only."),
    ("yurra", "pronoun", None, "NA", "second plural nominative", "batch-364: bare nominative subject support only."),
    ("ngana", "pronoun", None, "NA", "first plural inclusive nominative", "batch-364: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-364: bare Yalanji local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-364: bare Yalanji local demonstrative support only."),
    ("nyajil", "verb-tr", "l", "NA", "see; see.NPST", "batch-364: dictionary-attested nonpast visual-perception surface corresponding to Patz nyaji-l."),
]


def main() -> int:
    if len(LESSONS) != 35:
        raise SystemExit(f"lesson inventory changed: {len(LESSONS)} != 35")
    if len(LEXEMES) != 18:
        raise SystemExit(f"lexeme inventory changed: {len(LEXEMES)} != 18")
    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")
    bid = 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=?",
        (bid,),
    ).fetchone()
    if total != 50 or under_review != 50 or accepted:
        raise SystemExit(f"close precheck failed total={total} under_review={under_review} accepted={accepted}")
    existing_reviews = db.execute(
        "SELECT COUNT(*) FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)", (bid,)
    ).fetchone()[0]
    existing_lessons = db.execute("SELECT COUNT(*) FROM lessons WHERE batch_id=?", (bid,)).fetchone()[0]
    existing_logs = db.execute("SELECT COUNT(*) FROM lexeme_log WHERE action='batch-364-verify'").fetchone()[0]
    if existing_reviews or existing_lessons or existing_logs:
        raise SystemExit(
            f"non-destructive close precheck failed reviews={existing_reviews} lessons={existing_lessons} logs={existing_logs}"
        )
    total_rows = db.execute("SELECT COUNT(*) FROM sentences WHERE status!='rejected'").fetchone()[0]
    before, words_before = db.execute(
        "SELECT COUNT(*),SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1) FROM sentences WHERE status IN ('accepted','revised')"
    ).fetchone()
    ids = [r[0] for r in db.execute("SELECT id FROM sentences WHERE batch_id=? ORDER BY seq", (bid,))]
    db.executemany(
        "INSERT INTO reviews(sentence_id,round,lens,verdict,issues,suggested_fix,reviewer,created_at) VALUES(?,?,?,?,?,?,?,?)",
        [(sid, 1, lens, "pass", None, None, "codex-main-five-lens", NOW) for sid in ids for lens in LENSES],
    )
    db.executemany(
        "INSERT INTO lessons(batch_id,category,lesson,guide_change,created_at) VALUES(?,?,?,?,?)",
        [(bid, category, lesson, guide_change, NOW) for category, lesson, guide_change in LESSONS],
    )
    for head, pos, conj, 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""",
            (head, None, pos, conj, 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(?,?,?,?)",
            (head, "batch-364-verify", note, NOW),
        )
    record_event(db, batch_label=LABEL, phase="lint", event_type="under-review-lint-green", actor="codex", detail=f"After banking, whole-corpus lint scanned {total_rows} rows and found 0 issues; verified remained {before} before close.", command="python3 lint_corpus.py", output_excerpt=f"lint: {total_rows} rows scanned, 0 issues; GOAL {before}/20000 ({words_before} words)", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="review", event_type="five-lens-pass", actor="codex", detail="Manual five-lens review passed all 50 Rule 322 rows: bare anatomy O morphology without possessor assertion, nominative non-singular pronoun A, fixed Yalanji local/nonpast support, exact dictionary heads and conservative labels, literal English fidelity, and elicitation register; all medical, ritual, animal-source, compound-analysis, use, property, and event semantics remained closed.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="review", event_type="review-detail", actor="codex", detail="No possession/whole-part apposition, compound decomposition, person/animal attribution beyond lexical labels, pain/illness/medicine/surgery, injury/scab/initiation/ritual, butchery/food/hunting, clothing/material use, colour/texture/property, prior-row event, target case, past/purposive/reduplicated perception, or support-inflection drift remained.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="review", event_type="lesson-inventory", actor="codex", detail=f"Inserted {len(LESSONS)} Rule 322 lessons covering source, target occurrence/absence, possession boundary, candidate exclusions, coverage, lexical boundaries, morphology, syntax, fidelity, register, explicit authorship, traps, and handoff.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="review", event_type="lexeme-source-log", actor="codex", detail=f"Inserted {len(LEXEMES)} lexeme/source-log rows: ten targets and eight support heads.", artifact_path=PROCESS_LOG, created_at=NOW)
    db.execute("UPDATE sentences SET status='accepted',updated_at=? WHERE batch_id=?", (NOW, bid))
    db.execute(
        "UPDATE batches SET notes=?,cheatsheet_version=?,guide_version=? WHERE id=?",
        (NOTES, "Rule 322 accepted", "operator-guide-2026-07-10", bid),
    )
    after, words_after = db.execute(
        "SELECT COUNT(*),SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1) FROM sentences WHERE status IN ('accepted','revised')"
    ).fetchone()
    accepted_count = db.execute("SELECT COUNT(*) FROM sentences WHERE batch_id=? AND status='accepted'", (bid,)).fetchone()[0]
    reviews = db.execute(
        "SELECT COUNT(*) FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)", (bid,)
    ).fetchone()[0]
    lessons = db.execute("SELECT COUNT(*) FROM lessons WHERE batch_id=?", (bid,)).fetchone()[0]
    logs = db.execute("SELECT COUNT(*) FROM lexeme_log WHERE action='batch-364-verify'").fetchone()[0]
    record_event(db, batch_label=LABEL, phase="close", event_type="close-success", actor="codex", detail=f"Closed Batch 364 / Rule 322: {accepted_count} accepted, {reviews} reviews, {lessons} lessons, {logs} lexeme logs; verified {before}->{after}; Kuku words {words_before}->{words_after}.", command="python3 batch_scripts/close_364.py", output_excerpt=f"closed batch-364 accepted={accepted_count} reviews={reviews} lessons={lessons} lexeme_logs={logs} verified {before}->{after} words {words_before}->{words_after}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit()
    print(
        f"closed batch-364: accepted={accepted_count}, reviews={reviews}, lessons={lessons}, "
        f"lexeme_logs={logs}, verified {before}->{after}, kuku_words {words_before}->{words_after}"
    )
    return 0


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