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

NOTES = (
    "ZERO/LOW-USE BIRD SINGULAR/THIRD-PERSON PAST PERCEPTION SWEEP AFTER RULE 320 (Rule 321). 50 rows. "
    "TARGETS: zero-use binjurr-binjurr honeyeater, bujarr-bujarr bird, dakwul-dakwul scrub bird, dibirr-dibirr "
    "rainbow bird, julurr-julurr moomoo bird, muya bird; low-use juril-juril seashore plover, dawa-dawa magpie, "
    "bulnja frogmouth, jinabiju goshawk. SUPPORT: bare nominative ngayu, yundu, nyulu, bula, jana; Yalanji "
    "yaluy/yinyay; dictionary-attested past nyajin. Exact dictionary head orthography is preserved. No solid-variant "
    "equation, productive reduplication, species overresolution, color/anatomy, song/call/display, omen/totem/story/"
    "place, habitat/ecology, food/hunting, target case, nonpast/purposive/reduplicated perception, support inflection, "
    "or carried trap was opened."
)

LESSONS = [
    ("source", "Rule 321 selected six zero-use direct-dictionary bird heads (binjurr-binjurr, bujarr-bujarr, dakwul-dakwul, dibirr-dibirr, julurr-julurr, muya) and four two-to-four-use controls (juril-juril, dawa-dawa, bulnja, jinabiju).", "Rule 321: zero/low-use bird inventory."),
    ("source", "Dictionary lines reread: binjurr-binjurr 3049-3062, bujarr-bujarr 3606-3628, dakwul-dakwul 4703-4732, dibirr-dibirr 5452-5466, julurr-julurr 10719-10750, muya 21330-21351, juril-juril 11199-11227, dawa-dawa 5340-5354, bulnja 3893-3909, jinabiju 9327-9347.", "Rule 321: dictionary source lines."),
    ("source", "Exact Patz searches found none of the ten target heads. This absence was recorded: target lexical identity comes from the dictionary, while Patz supplies pronoun, case, tense, and perception-clause evidence.", "Rule 321: Patz lexical non-attestation."),
    ("source", "Patz lines 2577-2582 supplied bare nominatives ngayu, yundu, nyulu, bula, and jana/iana; lines 2834-2847 supplied Yalanji yaluy and yinyay.", "Rule 321: pronoun and demonstrative source."),
    ("source", "Patz example 67b at lines 2021-2024 supplied Ngayu ... nyaji-ny 'I saw ...'; lines 3160-3162 supplied past -ny; lines 4256-4265 supplied perception A/O syntax; dictionary lines 23876-23883 and 23968-23976 supplied running-form nyajin.", "Rule 321: past perception source."),
    ("source", "Solid reduplication variants bidubidu, binjurrbinjurr, dibirrdibirr, and jukujuku were excluded rather than added to the linter; dakwurr-dakwun and walu-dalbaji were excluded because totem/moiety and place/story pressure was avoidable in this pass.", "Rule 321: variant and candidate exclusions."),
    ("process", "Rule 321 was scoped as bare visible bird reference in singular/third-person past visual perception, not taxonomy resolution, color, anatomy, sound, display, omen, totem, story, place, ecology, food, hunting, or event content.", "Rule 321: 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 321: authorship and preflight."),
    ("process", "Target coverage before banking was binjurr-binjurr 0, bujarr-bujarr 0, dakwul-dakwul 0, dibirr-dibirr 0, julurr-julurr 0, muya 0, juril-juril 2, dawa-dawa 3, bulnja 4, jinabiju 4.", "Rule 321: target coverage audit."),
    ("process", "Support coverage before banking was ngayu 1371, yundu 967, nyulu 642, bula 438, jana 1143, yaluy 3872, yinyay 4114, nyajin 1300.", "Rule 321: support coverage audit."),
    ("lexicon", "Binjurr-binjurr was retained as the exact hyphenated honeyeater head only; no equivalence with solid binjurrbinjurr, robin identity, feeding, honey, call, habitat, color, or behavior was inferred.", "Rule 321: binjurr-binjurr."),
    ("lexicon", "Bujarr-bujarr used the populated bird entry and conservative English label 'bujarr-bujarr bird'; the empty duplicate and dictionary black-bird gloss did not license a productive color predicate, call, habitat, behavior, or event.", "Rule 321: bujarr-bujarr."),
    ("lexicon", "Dakwul-dakwul was retained as scrub bird only; brown/white color, sex, head/eye anatomy, clearing, circle, singing, dancing, display, habitat, and event prose stayed closed.", "Rule 321: dakwul-dakwul."),
    ("lexicon", "Dibirr-dibirr was retained as the exact hyphenated rainbow-bird common name only; solid dibirrdibirr, honeyeater identity, color, appearance, call, iconicity, onomatopoeia, and behavior stayed closed.", "Rule 321: dibirr-dibirr."),
    ("lexicon", "Julurr-julurr retained the source-local moomoo-bird label; owl/night-owl/night-hawk equivalence, nocturnality, call, omen, habitat, behavior, and event content stayed unresolved and closed.", "Rule 321: julurr-julurr."),
    ("lexicon", "Muya was retained only as a bird whose English species name is unknown; no taxon, appearance, sound, habitat, behavior, use, or event was invented.", "Rule 321: muya."),
    ("lexicon", "Juril-juril was retained as seashore plover only; the homophonous eject verb and earlier beach, water, running, feeding, crab, tide, flock, nest, call, and event propositions stayed closed.", "Rule 321: juril-juril."),
    ("lexicon", "Dawa-dawa was retained as the exact hyphenated magpie head only; solid dawadawa, song, call, dawn/time, weather, message, country, flock, habitat, and earlier events stayed closed.", "Rule 321: dawa-dawa."),
    ("lexicon", "Bulnja used the populated frogmouth entry only; the empty duplicate, mopoke synonym, nocturnality, branch posture, camouflage, mouth/anatomy, feeding, insects, warning, call, habitat, and earlier events stayed closed.", "Rule 321: bulnja."),
    ("lexicon", "Jinabiju used the direct goshawk identification only; chicken/chick, hunting, snatching, flight, wind, diving, prey, silence, warning, habitat, body-part, behavior, and earlier events stayed closed.", "Rule 321: jinabiju."),
    ("morphology", "All Rule 321 bird heads stayed bare absolutive objects with no case, number suffix, derivation, possession, or target morphology.", "Rule 321: bare target nouns."),
    ("morphology", "Hyphenated binjurr-binjurr, bujarr-bujarr, dakwul-dakwul, dibirr-dibirr, julurr-julurr, juril-juril, and dawa-dawa were copied as indivisible dictionary heads; no reduplicative form was generated productively and no solid variant was normalized into them.", "Rule 321: lexicalized head orthography."),
    ("morphology", "All subject forms stayed bare nominatives; no accusative, dative, locative, ablative, comitative, possessive, alternative, expanded, or non-selected pronoun was admitted.", "Rule 321: bare pronoun A forms."),
    ("morphology", "Yaluy, yinyay, and nyajin stayed fixed support; no demonstrative case, nonpast nyajil, purposive nyaji-nka, reduplicated watching, hearing compound, or perception compound was admitted.", "Rule 321: fixed support morphology."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yinyay nyajin for first-singular there past visual perception.", "Rule 321: 1sg there band."),
    ("syntax", "Rows 11-20 used Yundu TARGET yaluy nyajin for second-singular here past visual perception.", "Rule 321: 2sg here band."),
    ("syntax", "Rows 21-30 used Nyulu TARGET yinyay nyajin for third-singular there past visual perception.", "Rule 321: 3sg there band."),
    ("syntax", "Rows 31-40 used Bula TARGET yaluy nyajin for third-dual here past visual perception.", "Rule 321: 3du here band."),
    ("syntax", "Rows 41-50 used Jana TARGET yinyay nyajin for third-plural there past visual perception.", "Rule 321: 3pl there band."),
    ("fidelity", "English stayed literal past visual-perception/reference prose: selected subject value, conservative source-backed lexical bird label, here/there, and saw only.", "Rule 321: literal English."),
    ("fidelity", "No dictionary commentary, duplicate record, solid variant, Patz absence, or older corpus row was converted into taxonomy, color, anatomy, sound, display, omen, totem, story, place, habitat, food, hunting, or behavior claims.", "Rule 321: source and prior-row restraint."),
    ("register", "Rows remained plain elicitation-style past-perception clauses; no ornithological taxonomy, narrative, ceremonial, omen, ecological, hunting, food, warning, or story register was introduced.", "Rule 321: register."),
    ("process", "Every Rule 321 sentence is an explicit sequence-specific row call with exact Kuku, English, analysis, evidence, and confidence contracts; no runtime generator authored content.", "Rule 321: explicit-row authorship evidence."),
    ("process", "Rules 149-320 carry-forward traps stayed closed, including Rule 316-321 bird culture/behavior traps and older source-prose, homograph, case, compound, productive-reduplication, and support-inflection traps.", "Rule 321: cumulative trap closure."),
    ("handoff", "Next batch may continue from 18,247 if this closes; Rule 322 requires a fresh source and coverage audit and must not infer closed bird variants, taxonomy, source prose, prior-row events, case, compound, perception, or support fields.", "Rule 321: next cadence."),
]

LEXEMES = [
    ("binjurr-binjurr", "noun", None, "NA", "honeyeater", "batch-363: exact hyphenated honeyeater head in bare past-perception reference only; solid variant, robin, feeding/honey, call, habitat, color, behavior closed."),
    ("bujarr-bujarr", "noun", None, "NA", "bird (dictionary gloss: black bird)", "batch-363: populated bird entry in bare past-perception reference only; empty duplicate, productive color, call, habitat, behavior, event closed."),
    ("dakwul-dakwul", "noun", None, "NA", "scrub bird", "batch-363: scrub-bird reference only; color, sex, anatomy, clearing/circle, song/dance/display, habitat, event closed."),
    ("dibirr-dibirr", "noun", None, "NA", "rainbow bird", "batch-363: exact hyphenated rainbow-bird head in bare reference only; solid variant, honeyeater identity, color/appearance, call/iconicity, behavior closed."),
    ("julurr-julurr", "noun", None, "NA", "moomoo bird", "batch-363: source-local moomoo-bird label only; owl/night-hawk resolution, nocturnality, call, omen, habitat, behavior, event closed."),
    ("muya", "noun", None, "NA", "bird; English species name unknown", "batch-363: muya bird reference only; taxonomy, appearance, sound, habitat, behavior, use, event not inferred."),
    ("juril-juril", "noun", None, "NA", "seashore plover", "batch-363: plover reference only; eject homograph, beach/water, running/feeding/crab/tide, flock/nest/call, prior events closed."),
    ("dawa-dawa", "noun", None, "NA", "magpie", "batch-363: exact hyphenated magpie head in bare reference only; solid variant, song/call, dawn/time/weather, message/country, flock/habitat, prior events closed."),
    ("bulnja", "noun", None, "NA", "frogmouth", "batch-363: populated frogmouth entry in bare reference only; empty duplicate, mopoke, nocturnality, posture/camouflage/anatomy, feeding/insects, warning/call/habitat, prior events closed."),
    ("jinabiju", "noun", None, "NA", "goshawk", "batch-363: goshawk reference only; chicken/chick, hunting/snatching, flight/wind/dive/prey, silence/warning, habitat/body-part/behavior, prior events closed."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-363: bare nominative subject support only."),
    ("yundu", "pronoun", None, "NA", "second singular nominative", "batch-363: bare nominative subject support only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-363: bare nominative subject support only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-363: bare nominative subject support only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-363: bare nominative subject support only; Patz table OCR iana reconciled to corpus/dictionary jana."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-363: bare Yalanji local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-363: bare Yalanji local demonstrative support only."),
    ("nyajin", "verb-tr", "l", "NA", "saw; see.PAST", "batch-363: 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-363-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-363-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 321 rows: bare bird O morphology, nominative pronoun A, fixed Yalanji local/past support, exact dictionary heads and conservative labels, literal English fidelity, and elicitation register; all variants, source prose, and prior-row events 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 solid-variant equivalence, productive reduplication, species overresolution, color/anatomy, song/call/display, omen/totem/moiety, story/place, habitat/ecology, food/hunting, prior-row event, 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 321 lessons covering source, Patz absence, 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 321 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-363-verify'").fetchone()[0]
    record_event(db, batch_label=LABEL, phase="close", event_type="close-success", actor="codex", detail=f"Closed Batch 363 / Rule 321: {accepted_count} accepted, {reviews} reviews, {lessons} lessons, {logs} lexeme logs; verified {before}->{after}; Kuku words {words_before}->{words_after}.", command="python3 batch_scripts/close_363.py", output_excerpt=f"closed batch-363 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-363: 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())
