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

NOTES = (
    "ZERO-USE HUMAN-REFERENCE SINGULAR/THIRD-PERSON PAST PERCEPTION SWEEP AFTER RULE 322 (Rule 323). 50 rows. "
    "TARGETS: baliji people, kalbali tall man, kanjal companion, kaykay-kaykay children, kira baby girl, "
    "maral-maral young girls, marri-marri old people, walmbaji peacemaker, walmbi-walmbiji left-handed person, "
    "yarrkay-yarrka group of children. SUPPORT: bare nominative ngayu, yundu, nyulu, bula, jana; Yalanji "
    "yaluy/yinyay; dictionary-attested past nyajin. Exact human labels and attested plural/collective heads only. "
    "No open-country/location claim, adjective/degree expansion, social activity, parentage/possession, fight/"
    "restraint, body-part/hand action, class/gang sense, productive reduplication, target case, nonpast/purposive/"
    "reduplicated perception, support inflection, or carried trap was opened."
)

LESSONS = [
    ("source", "Rule 323 selected ten direct-dictionary, noun-typed, zero-use human-reference heads: baliji, kalbali, kanjal, kaykay-kaykay, kira, maral-maral, marri-marri, walmbaji, walmbi-walmbiji, and yarrkay-yarrka.", "Rule 323: zero-use human inventory."),
    ("source", "Dictionary lines reread: baliji 941-952, kalbali noun 12349-12359, kanjal 13298-13309, kaykay-kaykay 14071-14098, kira 14438-14449, maral-maral 18183-18196, marri-marri 18612-18625, walmbaji 25522-25533, walmbi-walmbiji 25543-25556, yarrkay-yarrka 29560-29577.", "Rule 323: dictionary source lines."),
    ("source", "Exact Patz searches found maral-maral at lines 1979, 4430, and 5447 and found none of the other nine target heads. Positive and negative results were recorded; dictionary entries remain the lexical source for all selected surfaces.", "Rule 323: Patz target occurrence audit."),
    ("source", "Patz line 1476 classifies humans as nouns; line 1376, line 5080, and line 5790 show woman, person, and man as bare absolutive perception objects. This directly licenses unmarked human O in Rule 323.", "Rule 323: human perception-object source."),
    ("source", "Patz lines 2577-2586 source singular/third 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 323: construction source."),
    ("source", "The zero-use human audit excluded colonial/racial caste labels, loans and post-contact ethnonyms/occupations, sickness, adultery, child-spirit/prematurity ambiguity, policing labels, and avoidable coercive or stigmatizing categories.", "Rule 323: ethical candidate exclusions."),
    ("process", "Rule 323 was scoped as bare human entity reference in singular/third-person past visual perception, not location, adjective predication, social activity, possession, conflict, handed action, class/gang, or event content.", "Rule 323: 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 323: authorship and preflight."),
    ("process", "Every selected target had zero accepted/revised token coverage before banking.", "Rule 323: target coverage audit."),
    ("process", "Support coverage before banking was ngayu 1381, yundu 977, nyulu 652, bula 448, jana 1153, yaluy 3922, yinyay 4164, nyajin 1350.", "Rule 323: support coverage audit."),
    ("lexicon", "Baliji was retained as people only; open-country location/association, belonging, origin, travel, residence, land identity, group activity, and event content stayed closed.", "Rule 323: baliji."),
    ("lexicon", "Kalbali selected the noun 'tall man' as one lexical human label; productive adjective predication, comparison, degree, measurement, stature event, and unrelated kalbal remedy stayed closed.", "Rule 323: kalbali."),
    ("lexicon", "Kanjal was retained as companion only; whose companion, possession, accompaniment, loneliness, helping, travel, relationship activity, and event content stayed closed.", "Rule 323: kanjal."),
    ("lexicon", "Kaykay-kaykay was retained as the exact dictionary children head; base kaykay, normalization to karrkay-karrkay, productive reduplication, parentage, school, play, possession, and event content stayed closed.", "Rule 323: kaykay-kaykay."),
    ("lexicon", "Kira was retained in its dictionary-restricted baby-girl sense; generic female/adult reference, age measurement, family relation, birth/care/possession, and kira-kira black-ant homophone stayed closed.", "Rule 323: kira."),
    ("lexicon", "Maral-maral was retained as the exact attested young-girls plural; productive reduplication, singular maral, age comparison, Patz bathing/food-gathering events, family relation, possession, and activity stayed closed.", "Rule 323: maral-maral."),
    ("lexicon", "Marri-marri was retained as the whole old-people head; productive reduplication, singular/base inference, age measurement, frailty, authority, knowledge, ceremony, family relation, possession, and event content stayed closed.", "Rule 323: marri-marri."),
    ("lexicon", "Walmbaji was retained as peacemaker only; fight, conflict, intervention, restraint, arms/body contact, relative identity, success, role performance, and event content stayed closed.", "Rule 323: walmbaji."),
    ("lexicon", "Walmbi-walmbiji was retained as one left-handed-person head; decomposition, productive reduplication, left locative, hand possession, handed action, skill, disability, separate property predication, and event content stayed closed.", "Rule 323: walmbi-walmbiji."),
    ("lexicon", "Yarrkay-yarrka was retained as the exact group-of-children head; class/gang senses, base yarrkay, karrkay equivalence, productive reduplication, school/play/parentage/possession, group activity, and event content stayed closed.", "Rule 323: yarrkay-yarrka."),
    ("morphology", "All Rule 323 human heads stayed bare absolutive objects. Human referents require potent marking as transitive agents, but as O in these clauses they are correctly unmarked; no target case or possession was added.", "Rule 323: bare human O."),
    ("morphology", "Kaykay-kaykay, maral-maral, marri-marri, walmbi-walmbiji, and yarrkay-yarrka were copied as exact dictionary plural/collective human heads. No new reduplicative form, base, equivalence, or derivation was generated.", "Rule 323: attested plural/collective restraint."),
    ("morphology", "All subject forms stayed bare nominatives; no accusative, dative, locative, ablative, comitative, possessive, alternative, expanded, or non-selected pronoun was admitted.", "Rule 323: 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 323: fixed support morphology."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yinyay nyajin for first-singular there past visual perception.", "Rule 323: 1sg there band."),
    ("syntax", "Rows 11-20 used Yundu TARGET yaluy nyajin for second-singular here past visual perception.", "Rule 323: 2sg here band."),
    ("syntax", "Rows 21-30 used Nyulu TARGET yinyay nyajin for third-singular there past visual perception.", "Rule 323: 3sg there band."),
    ("syntax", "Rows 31-40 used Bula TARGET yaluy nyajin for third-dual here past visual perception.", "Rule 323: 3du here band."),
    ("syntax", "Rows 41-50 used Jana TARGET yinyay nyajin for third-plural there past visual perception.", "Rule 323: 3pl there band."),
    ("fidelity", "English stayed literal past visual-perception/reference prose: selected observer, exact conservative human label, here/there, and saw only. Lexical labels do not assert the source commentary's location, activity, relation, or event.", "Rule 323: literal English."),
    ("fidelity", "No dictionary commentary, Patz clause, homophone, derivational analysis, or older corpus row was converted into open-country, comparison, loneliness, parentage, bathing, authority, conflict, handed action, school, or group-activity claims.", "Rule 323: source and prior-row restraint."),
    ("register", "Rows remained neutral elicitation-style human-reference clauses. Colonial/racial, stigmatizing, coercive, illness, adultery, policing, and loan categories were excluded during selection.", "Rule 323: register and candidate ethics."),
    ("process", "Every Rule 323 sentence is an explicit sequence-specific row call with exact Kuku, English, analysis, evidence, and confidence contracts; no runtime generator authored content.", "Rule 323: explicit-row authorship evidence."),
    ("process", "Rules 149-322 carry-forward traps stayed closed, including human/kin social-event, body-part, bird, anatomy, source-prose, homograph, case, compound, productive-reduplication, and support-inflection traps.", "Rule 323: cumulative trap closure."),
    ("handoff", "Next batch may continue from 18,347 if this closes; Rule 324 requires a fresh source and coverage audit and must not infer closed human location, property, activity, relation, conflict, morphology, case, perception, or support fields.", "Rule 323: next cadence."),
]

LEXEMES = [
    ("baliji", "noun", None, "NA", "people", "batch-365: baliji-people past-perception reference only; open-country/location/association, belonging/origin/travel/residence/land identity/activity/event closed."),
    ("kalbali", "noun", None, "NA", "tall man", "batch-365: noun tall-man label in bare reference only; adjective predication/comparison/degree/measurement/stature event and kalbal remedy closed."),
    ("kanjal", "noun", None, "NA", "companion", "batch-365: companion reference only; relation/possession, accompaniment/loneliness/help/travel/activity/event closed."),
    ("kaykay-kaykay", "noun", None, "NA", "children", "batch-365: exact dictionary children head only; base/normalization to karrkay-karrkay, productive reduplication, parentage/school/play/possession/event closed."),
    ("kira", "noun", None, "NA", "baby girl", "batch-365: baby-girl sense only; generic female/adult, age/family/birth/care/possession and kira-kira ant closed."),
    ("maral-maral", "noun", None, "NA", "young girls", "batch-365: exact Patz/dictionary young-girls plural in bare reference only; productive reduplication/base, age comparison, source events/relation/possession/activity closed."),
    ("marri-marri", "noun", None, "NA", "old people", "batch-365: exact old-people head only; productive reduplication/base, age/frailty/authority/knowledge/ceremony/relation/possession/event closed."),
    ("walmbaji", "noun", None, "NA", "peacemaker", "batch-365: peacemaker label only; fight/conflict/intervention/restraint/body contact/relative/success/role performance/event closed."),
    ("walmbi-walmbiji", "noun", None, "NA", "left-handed person", "batch-365: indivisible left-handed-person head only; decomposition/reduplication/left locative/hand possession/action/skill/disability/property/event closed."),
    ("yarrkay-yarrka", "noun", None, "NA", "group of children", "batch-365: exact child-group head only; class/gang/base/equivalence/reduplication/school/play/parentage/possession/activity/event closed."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-365: bare nominative subject support only."),
    ("yundu", "pronoun", None, "NA", "second singular nominative", "batch-365: bare nominative subject support only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-365: bare nominative subject support only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-365: bare nominative subject support only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-365: bare nominative subject support only; Patz table OCR iana reconciled to dictionary/corpus jana."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-365: bare Yalanji local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-365: bare Yalanji local demonstrative support only."),
    ("nyajin", "verb-tr", "l", "NA", "saw; see.PAST", "batch-365: 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-365-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-365-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 323 rows: bare human O morphology, nominative singular/third pronoun A, fixed Yalanji local/past support, exact dictionary human heads and conservative labels, literal English fidelity, and neutral elicitation register; all location, property, social activity, possession, conflict, body-action, class/gang, 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 open-country belonging/location, adjective comparison/degree, companionship activity, parentage/school/play, generic female or ant homophone, Patz bathing/gathering, age authority/frailty, fight/restraint/body contact, left-side/handed action, class/gang, productive reduplication, 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 323 lessons covering source, target occurrence/absence, human O syntax, ethical 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 323 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-365-verify'").fetchone()[0]
    record_event(db, batch_label=LABEL, phase="close", event_type="close-success", actor="codex", detail=f"Closed Batch 365 / Rule 323: {accepted_count} accepted, {reviews} reviews, {lessons} lessons, {logs} lexeme logs; verified {before}->{after}; Kuku words {words_before}->{words_after}.", command="python3 batch_scripts/close_365.py", output_excerpt=f"closed batch-365 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-365: 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())
