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

NOTES = (
    "LOW-COVERAGE FLORA NON-SINGULAR PAST PERCEPTION AFTER RULE 323 (Rule 324). 50 rows. TARGETS: bajarr "
    "fern leaves, bikarrakul ti tree, binainyji fig-like fruit, jakalkulu tree stump, jumul-jumul grass seeds, "
    "jika-birra tobacco leaf, kalbawurr cypress-pine pitch, makaji onion plant, mawu grass, wakumba tree canopy. "
    "SUPPORT: bare nominative ngali, ngaliny, yubal, yurra, ngana; Yalanji yaluy/yinyay; dictionary-attested past "
    "nyajin. Exact conservative flora labels only. No alternate sense, source-prose use/event, edibility/food, "
    "poison, shelter, clothing, material manufacture, productive compound/reduplication, target case, nonpast/"
    "purposive/reduplicated perception, support inflection, or carried trap was opened."
)

LESSONS = [
    ("source", "Rule 324 selected ten direct-dictionary, noun-typed, low-coverage flora heads: bajarr, bikarrakul, binainyji, jakalkulu, jumul-jumul, jika-birra, kalbawurr, makaji, mawu, and wakumba.", "Rule 324: low-coverage flora inventory."),
    ("source", "Dictionary lines reread: bajarr 456-481, bikarrakul 2381-2391, binainyji 2642-2655, jakalkulu 7197-7205, jumul-jumul 10812-10825, jika-birra 8986-8996, kalbawurr 12432-12440, makaji 17152-17161, mawu 18764-18774, wakumba 25245-25255.", "Rule 324: dictionary source lines."),
    ("source", "Exact Patz searches found binainyji at lines 1145-1151 and found none of the other nine target heads. Positive and negative results were recorded; dictionary entries remain the lexical source for nine selected surfaces.", "Rule 324: Patz target occurrence audit."),
    ("source", "Patz line 1476 explicitly includes flora among corporeal objects denoted by nouns, licensing the selected heads as noun objects rather than inferred properties or events.", "Rule 324: flora noun source."),
    ("source", "Patz lines 2577-2584 source non-singular nominatives; 2834-2847 Yalanji yaluy/yinyay; 2021-2024 and 2568-2571 nyaji-ny; 3160-3162 past -ny; 4256-4265 perception A/O; dictionary 23876-23883 and 23968-23976 running-form nyajin.", "Rule 324: construction source."),
    ("source", "The candidate audit rejected contradictory or undefined entries, Nyungkul-only forms, place names, hazardous/post-contact food and drink, stigmatizing or culturally sensitive human/spirit labels, weapon/euphemism ambiguity, coercive implements, and unresolved flora sense/dialect drift.", "Rule 324: candidate exclusions."),
    ("process", "Rule 324 was scoped as bare flora entity reference in non-singular past visual perception, not source-prose use, property, preparation, food, poison, shelter, material, possession, location, or event content.", "Rule 324: 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 324: authorship and preflight."),
    ("process", "Target coverage before banking was three heads at zero, two at one, and five at two accepted/revised token rows.", "Rule 324: target coverage audit."),
    ("process", "Support coverage before banking was ngali 543, ngaliny 485, yubal 495, yurra 480, ngana 1065, yaluy 3942, yinyay 4194, nyajin 1400.", "Rule 324: support coverage audit."),
    ("lexicon", "Bajarr was retained as fern leaves with double r; bajar white gum, vine/fern taxonomy, shelter/mia-mia, gathering, carrying, drying, manufacture, material use, and events stayed closed.", "Rule 324: bajarr."),
    ("lexicon", "Bikarrakul was retained as ti tree only; fruit, required cooking, edibility, food, bark, firewood, gathering, species comparison, material use, and events stayed closed.", "Rule 324: bikarrakul."),
    ("lexicon", "Binainyji was retained as the Patz-attested fig-like fruit; fig identity, edibility, taste, ripeness, gathering, preparation, source tree, and minimal-pair forms binanj-ji, jalbanj-ji, and jalbainy-ji stayed closed.", "Rule 324: binainyji."),
    ("lexicon", "Jakalkulu was retained as tree stump only; tree species, cutting/felling, age, decay, burning, firewood, sitting, location, material use, cause, and events stayed closed.", "Rule 324: jakalkulu."),
    ("lexicon", "Jumul-jumul was retained as the exact grass-seed head; base jumul, productive reduplication, clothing contact, sticking, wet-season timing, gathering, food, sowing, and events stayed closed.", "Rule 324: jumul-jumul."),
    ("lexicon", "Jika-birra was retained as one tobacco-leaf head; component senses, productive compounding, tobacco use, smoking, chewing, drying, preparation, trade, medicine, possession, and events stayed closed.", "Rule 324: jika-birra."),
    ("lexicon", "Kalbawurr was retained as cypress-pine pitch; poison/toxicity, touching, ingestion, medicine, processing, spear use, tree/source relation, material use, events, and near-form kulbawurr stayed closed.", "Rule 324: kalbawurr."),
    ("lexicon", "Makaji was retained as onion plant only; edibility, herb classification, food, harvesting, digging, cooking, taste, medicine, cultivation, possession, and events stayed closed.", "Rule 324: makaji."),
    ("lexicon", "Mawu was retained as grass only; coarseness predication, bag making, weaving, cutting, gathering, drying, material use, possession, events, and near-form mawar vine stayed closed.", "Rule 324: mawu."),
    ("lexicon", "Wakumba was retained as tree canopy only; branch decomposition, tree species, size, shape, shade, height, location, growth, climbing, cutting, material use, and events stayed closed.", "Rule 324: wakumba."),
    ("morphology", "All Rule 324 flora heads stayed bare absolutive objects, with no case, number, possession, derivation, or property morphology added.", "Rule 324: bare flora O."),
    ("morphology", "Jumul-jumul and jika-birra were copied as exact whole dictionary heads. No base jumul, component jika/birra, new reduplicative form, compound decomposition, equivalence, or derivation was generated.", "Rule 324: lexicalized-form restraint."),
    ("morphology", "All subject forms stayed bare nominatives; no accusative, dative, locative, ablative, comitative, possessive, alternative, expanded, or non-selected pronoun was admitted.", "Rule 324: bare pronoun A forms."),
    ("morphology", "Yaluy, yinyay, and nyajin stayed fixed support; no demonstrative case, nonpast nyajil, purposive nyaji-nka, reduplicated watching, hearing/smell compound, or perception compound was admitted.", "Rule 324: fixed support morphology."),
    ("syntax", "Rows 1-10 used Ngali TARGET yaluy nyajin for first-dual-exclusive here past visual perception.", "Rule 324: 1du exclusive here band."),
    ("syntax", "Rows 11-20 used Ngaliny TARGET yinyay nyajin for first-dual-inclusive there past visual perception.", "Rule 324: 1du inclusive there band."),
    ("syntax", "Rows 21-30 used Yubal TARGET yaluy nyajin for second-dual here past visual perception.", "Rule 324: 2du here band."),
    ("syntax", "Rows 31-40 used Yurra TARGET yinyay nyajin for second-plural there past visual perception.", "Rule 324: 2pl there band."),
    ("syntax", "Rows 41-50 used Ngana TARGET yaluy nyajin for first-plural-inclusive here past visual perception.", "Rule 324: 1pl inclusive here band."),
    ("fidelity", "English stayed literal past visual-perception/reference prose: selected observer, exact conservative flora label, here/there, and saw only. Lexical labels do not assert source commentary's uses, properties, preparation, or events.", "Rule 324: literal English."),
    ("fidelity", "No dictionary commentary, Patz minimal-pair neighbor, or older corpus row was converted into shelter, cooking, food, clothing, season, poison, medicine, weapon, harvesting, weaving, location, growth, or material-use claims.", "Rule 324: source and prior-row restraint."),
    ("register", "Rows remained neutral elicitation-style flora-reference clauses. Culturally sensitive, stigmatizing, coercive, hazardous-consumption, weapon-euphemism, place-name, and unresolved dialect candidates were excluded during selection.", "Rule 324: register and candidate ethics."),
    ("process", "Every Rule 324 sentence is an explicit sequence-specific row call with exact Kuku, English, analysis, evidence, and confidence contracts; no runtime generator authored content.", "Rule 324: explicit-row authorship evidence."),
    ("process", "Rules 149-323 carry-forward traps stayed closed, including flora use, food, material, homograph, place, case, compound, productive-reduplication, human, anatomy, bird, and support-inflection traps.", "Rule 324: cumulative trap closure."),
    ("handoff", "Next batch may continue from 18,397 if this closes; Rule 325 requires a fresh source and coverage audit and must not infer closed flora use, property, preparation, food, poison, material, location, morphology, case, perception, or support fields.", "Rule 324: next cadence."),
]

LEXEMES = [
    ("bajarr", "noun", None, "NA", "fern leaves", "batch-366: double-r bajarr fern-leaf past-perception reference only; bajar white gum and shelter/gathering/material-use/event content closed."),
    ("bikarrakul", "noun", None, "NA", "ti tree", "batch-366: ti-tree reference only; fruit/cooking/food/bark/firewood/material-use/event content closed."),
    ("binainyji", "noun", None, "NA", "fig-like fruit", "batch-366: Patz-attested fig-like-fruit reference only; minimal-pair neighbors and edibility/taste/ripeness/gathering/source/event content closed."),
    ("jakalkulu", "noun", None, "NA", "tree stump", "batch-366: tree-stump reference only; species/felling/decay/burning/sitting/location/material-use/event content closed."),
    ("jumul-jumul", "noun", None, "NA", "grass seeds", "batch-366: exact grass-seed head only; base/productive reduplication/clothing/wet-season/gathering/food/sowing/event content closed."),
    ("jika-birra", "noun", None, "NA", "tobacco leaf", "batch-366: indivisible tobacco-leaf head only; components/smoking/chewing/preparation/trade/medicine/possession/event content closed."),
    ("kalbawurr", "noun", None, "NA", "cypress-pine pitch", "batch-366: cypress-pine-pitch reference only; toxicity/ingestion/medicine/processing/spear/source/material-use/event and kulbawurr closed."),
    ("makaji", "noun", None, "NA", "onion plant", "batch-366: onion-plant reference only; edibility/herb/food/harvesting/cooking/taste/medicine/cultivation/possession/event closed."),
    ("mawu", "noun", None, "NA", "grass", "batch-366: grass reference only; coarse-property/bag/weaving/cutting/gathering/drying/material-use/event and mawar closed."),
    ("wakumba", "noun", None, "NA", "tree canopy", "batch-366: tree-canopy reference only; branch decomposition/species/size/shade/height/location/growth/climbing/cutting/use/event closed."),
    ("ngali", "pronoun", None, "NA", "first dual exclusive nominative", "batch-366: bare nominative subject support only."),
    ("ngaliny", "pronoun", None, "NA", "first dual inclusive nominative", "batch-366: bare nominative subject support only."),
    ("yubal", "pronoun", None, "NA", "second dual nominative", "batch-366: bare nominative subject support only."),
    ("yurra", "pronoun", None, "NA", "second plural nominative", "batch-366: bare nominative subject support only."),
    ("ngana", "pronoun", None, "NA", "first plural inclusive nominative", "batch-366: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-366: bare Yalanji local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-366: bare Yalanji local demonstrative support only."),
    ("nyajin", "verb-tr", "l", "NA", "saw; see.PAST", "batch-366: dictionary-attested past visual-perception surface corresponding to Patz nyaji-ny."),
]


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-366-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-366-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 324 rows: bare flora O morphology, nominative non-singular pronoun A, fixed Yalanji local/past support, exact dictionary flora heads and conservative labels, literal English fidelity, and neutral elicitation register; all alternate-sense, source-use, property, food, poison, shelter, clothing, material, location, 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 bajar/bajarr drift, bikarrakul fruit/cooking, binainyji minimal-pair confusion, stump cause/use, jumul productive reduplication/season, jika-birra decomposition/tobacco use, kalbawurr poison/spear use or kulbawurr substitution, makaji food/medicine, mawu weaving or mawar substitution, wakumba branch/property, target case, nonpast/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 324 lessons covering source, target occurrence/absence, flora O syntax, 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 324 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-366-verify'").fetchone()[0]
    record_event(db, batch_label=LABEL, phase="close", event_type="close-success", actor="codex", detail=f"Closed Batch 366 / Rule 324: {accepted_count} accepted, {reviews} reviews, {lessons} lessons, {logs} lexeme logs; verified {before}->{after}; Kuku words {words_before}->{words_after}.", command="python3 batch_scripts/close_366.py", output_excerpt=f"closed batch-366 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-366: 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())
