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

NOTES = (
    "VISIBLE SKY/CELESTIAL NON-SINGULAR COMPLEMENTARY PAST PRONOUN PERCEPTION SWEEP AFTER RULE 282 "
    "(Rule 283). 50 rows. TARGETS: balbay lightning, binyu shooting star, dawar star, jiri sky, kaba rain, "
    "wungar sun, kurrinkurrin mackerel sky, kurrubijal morning star, ngurrban cloud, and yiril rainbow. SUPPORT: "
    "bare nominative ngali, ngaliny, yubal, yurra, and jana plus yaluy/yinyay and nyajin. FRAMES: Ngali TARGET "
    "yinyay nyajin, Ngaliny TARGET yaluy nyajin, Yubal TARGET yinyay nyajin, Yurra TARGET yaluy nyajin, and "
    "Jana TARGET yinyay nyajin. REVIEW: opposite-band Jana TARGET yaluy candidates collided with older sky/weather "
    "rows; kija was rejected after duplicate Jana kija yinyay nyajin. from Batch 195, and sourced wungar replaced "
    "it. No moon/month/place-story, lightning strike, death-spirit/death-omen, heaven/sky-mob/fine-day compound, "
    "rain event, sun-time/hot-season compound, rainbow story/snake/water-hole extension, target case, pronoun case, "
    "demonstrative case, target compound, productive reduplication, perception compound, nonpast/purposive/"
    "reduplicated perception drift, support inflection, or recent water/landform/fauna/body/dwelling/fire drift "
    "was opened."
)

LESSONS = [
    ("source", "Rule 283 selected ten visible sky/celestial target heads: balbay, binyu, dawar, jiri, kaba, wungar, kurrinkurrin, kurrubijal, ngurrban, and yiril.", "Rule 283: visible target inventory."),
    ("source", "Direct dictionary line readback was explicit: balbay 900-911, binyu 3063-3074, dawar 5374-5382, jiri 9720-9730, kaba 11671-11679, wungar 28081-28089, kurrinkurrin 16406-16419, kurrubijal 16557-16567, ngurrban 23885-23893, and yiril 30419-30427.", "Rule 283: dictionary source lines."),
    ("source", "Patz grammar lines 2577-2586 and 2592-2603 supplied the personal pronoun table and base forms for bare nominative ngali, ngaliny, yubal, yurra, and jana.", "Rule 283: pronoun source."),
    ("source", "Patz grammar lines 2674-2686 supplied the non-singular person/number contrasts used here: ngali 1du exclusive, ngaliny 1du inclusive, yubal 2du, yurra 2pl, and jana 3pl.", "Rule 283: non-singular source."),
    ("source", "Patz Table 3.12 lines 2838-2845 supplied Yalanji yaluy 'here' and yinyay 'there'; Rule 283 used only bare local demonstratives.", "Rule 283: demonstrative source."),
    ("source", "Patz lines 2568-2571 supplied nyaji-ny 'see-PAST'; Rule 283 used corpus-conventional nyajin as the past visual-perception surface only.", "Rule 283: past perception source."),
    ("source", "Patz lines 3043-3049 supplied nyaji-l 'see' only as nonpast contrast; Rule 283 did not use nonpast nyajil.", "Rule 283: nonpast contrast."),
    ("process", "The first opposite-band sky/celestial candidate was rejected because the Jana TARGET yaluy band collided with older sky/weather rows for kaba, ngurrban, kija, yiril, kurrubijal, balbay, and kurrinkurrin.", "Rule 283: opposite-band duplicate avoidance."),
    ("process", "The complementary-band candidate retained kija but exact duplicate preflight found Jana kija yinyay nyajin. in Batch 195; kija was replaced with sourced wungar sun rather than special-casing one row.", "Rule 283: kija replacement."),
    ("process", "Final preflight over the wungar replacement set returned 50 unique surfaces and no accepted, revised, or under-review collisions.", "Rule 283: duplicate preflight."),
    ("process", "Token-aware target coverage before banking after Rule 282 was balbay 23, binyu 6, dawar 62, jiri 91, kaba 243, wungar 650, kurrinkurrin 10, kurrubijal 23, ngurrban 68, and yiril 25.", "Rule 283: target coverage audit."),
    ("process", "Support coverage before banking after Rule 282 was ngali 313, ngaliny 255, yubal 265, yurra 270, jana 933, yaluy 2902, yinyay 3184, and nyajin 350 by words_used JSON.", "Rule 283: support coverage audit."),
    ("lexicon", "Balbay remained visible lightning only; lightning-strike, danger, event, and causation rows stayed closed.", "Rule 283: balbay."),
    ("lexicon", "Binyu remained visible shooting star only; death-spirit, death-omen, mourning, and story rows stayed closed.", "Rule 283: binyu."),
    ("lexicon", "Dawar remained star only; straw-hat homograph dawarr and post-contact object rows stayed closed.", "Rule 283: dawar."),
    ("lexicon", "Jiri remained visible sky only; heaven, sky-mob, fine-day, cloudless-sky, place-name, and post-contact object rows stayed closed.", "Rule 283: jiri."),
    ("lexicon", "Kaba remained visible rain only; rain falling, rain coming, rainbird, no-rain, storm, weather-predication, and event rows stayed closed.", "Rule 283: kaba."),
    ("lexicon", "Wungar remained visible sun only; sunrise, sunset, midday, hot-season, sun-locative, sun-time, and motion-into-sun rows stayed closed.", "Rule 283: wungar."),
    ("lexicon", "Kurrinkurrin remained lexicalized mackerel sky only; its reduplicated source form was not generalized to productive reduplication.", "Rule 283: kurrinkurrin."),
    ("lexicon", "Kurrubijal remained morning star/Venus only; star story, time, place, and astronomy expansion rows stayed closed.", "Rule 283: kurrubijal."),
    ("lexicon", "Ngurrban remained visible cloud only; weather-event predicates, darkness predicates, cloud-source prose, and storm rows stayed closed.", "Rule 283: ngurrban."),
    ("lexicon", "Yiril remained visible rainbow only; rainbow-snake, story, water-hole, place-name, and yirri/yiri homograph drift stayed closed.", "Rule 283: yiril."),
    ("morphology", "All Rule 283 target nouns stayed bare: no LOC, DAT, ABL, PERL, ERG, INST, COMIT, POSS, PRIV, EXCESS, plural, derivation, or target suffix was admitted.", "Rule 283: bare targets."),
    ("morphology", "The subject support forms stayed bare nominatives: ngali, ngaliny, yubal, yurra, and jana were not inflected for accusative, dative, locative, ablative, comitative, or possessive.", "Rule 283: bare nominative non-singular pronouns."),
    ("morphology", "Yaluy, yinyay, and nyajin stayed uninflected support heads; no demonstrative case, local-derived form, nonpast nyajil, purposive nyaji-nka, reduplicated watching form, or support suffix was admitted.", "Rule 283: uninflected support."),
    ("morphology", "No target compound, place-name compound, weather-event construction, story construction, pronoun-case construction, or productive reduplication was built from the Rule 283 heads.", "Rule 283: no compounds or reduplication."),
    ("syntax", "Rows 1-10 used Ngali TARGET yinyay nyajin for first dual exclusive there past visual perception.", "Rule 283: 1du exclusive there band."),
    ("syntax", "Rows 11-20 used Ngaliny TARGET yaluy nyajin for first dual inclusive here past visual perception.", "Rule 283: 1du inclusive here band."),
    ("syntax", "Rows 21-30 used Yubal TARGET yinyay nyajin for second dual there past visual perception.", "Rule 283: 2du there band."),
    ("syntax", "Rows 31-40 used Yurra TARGET yaluy nyajin for second plural here past visual perception.", "Rule 283: 2pl here band."),
    ("syntax", "Rows 41-50 used Jana TARGET yinyay nyajin for third plural there past visual perception.", "Rule 283: 3pl there band."),
    ("fidelity", "English stayed literal visual past perception/reference prose: selected subject pronoun value, target label, here/there, and saw only.", "Rule 283: literal English."),
    ("fidelity", "The batch did not convert dictionary alternate glosses or source prose into moon/month/place-story, lightning-strike, death-spirit/death-omen, heaven, sky-mob, fine-day, rain-event, sun-time/hot-season, rainbow-story, snake, water-hole, weather-event, danger, ownership, source, or use claims.", "Rule 283: source-prose restraint."),
    ("register", "Rows remained plain elicitation-style visual past perception clauses; no mythic narrative, omen report, weather forecast, astronomical explanation, route instruction, warning, source-prose, or story register was introduced.", "Rule 283: register."),
    ("process", "Rules 149-282 carry-forward traps stayed closed, especially recent visible water/landform traps plus older sky, fire, fauna, body, dwelling, source-prose, homograph, target-case, pronoun-case, demonstrative-case, perception-compound, target-compound, productive-reduplication, and support-inflection traps.", "Rule 283: carry-forward closure."),
    ("handoff", "Next batch may continue from 16,347 if this closes; do not infer sky/celestial weather-event, story, death-omen, time-compound, target-case, pronoun-case, perception-compound, nonpast/purposive/reduplicated perception, productive-reduplication, or support-inflection grammar from Rule 283.", "Rule 283: next cadence."),
]

LEXEMES = [
    ("balbay", "noun", None, "NA", "lightning", "batch-325: visible lightning past perception/reference only; strike, danger, event, and causation rows closed."),
    ("binyu", "noun", None, "NA", "shooting star", "batch-325: visible shooting-star past perception/reference only; death-spirit, death-omen, mourning, and story rows closed."),
    ("dawar", "noun", None, "NA", "star", "batch-325: visible star past perception/reference only; dawarr straw-hat homograph closed."),
    ("jiri", "noun", None, "NA", "sky", "batch-325: visible sky past perception/reference only; heaven, sky-mob, fine-day, cloudless-sky, and place-name rows closed."),
    ("kaba", "noun", None, "NA", "rain", "batch-325: visible rain past perception/reference only; falling/coming/no-rain/rainbird/weather-event rows closed."),
    ("wungar", "noun", None, "NA", "sun", "batch-325: visible sun past perception/reference only; sunrise, sunset, midday, hot-season, sun-locative, and time rows closed."),
    ("kurrinkurrin", "noun", None, "NA", "mackerel sky", "batch-325: visible mackerel-sky past perception/reference only; lexicalized reduplication, not productive pattern."),
    ("kurrubijal", "noun", None, "NA", "morning star", "batch-325: visible morning-star past perception/reference only; time/story/place expansion closed."),
    ("ngurrban", "noun", None, "NA", "cloud", "batch-325: visible cloud past perception/reference only; weather-event/storm/darkness/source-prose rows closed."),
    ("yiril", "noun", None, "NA", "rainbow", "batch-325: visible rainbow past perception/reference only; rainbow-snake/story/water-hole/place-name rows closed."),
    ("ngali", "pronoun", None, "NA", "first dual exclusive nominative", "batch-325: bare nominative subject support only."),
    ("ngaliny", "pronoun", None, "NA", "first dual inclusive nominative", "batch-325: bare nominative subject support only."),
    ("yubal", "pronoun", None, "NA", "second dual nominative", "batch-325: bare nominative subject support only."),
    ("yurra", "pronoun", None, "NA", "second plural nominative", "batch-325: bare nominative subject support only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-325: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-325: bare local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-325: bare local demonstrative support only."),
    ("nyajin", "verb", "l", "NA", "saw", "batch-325: past visual perception support only, corpus-conventional surface from nyaji-ny see-PAST."),
]


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 or under_review != 50 or accepted:
        raise SystemExit(f"{LABEL} close precheck failed: total={total}, under_review={under_review}, accepted={accepted}")

    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-325-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 283 rows. Morphology checked bare sky/celestial nouns, bare nominative ngali/ngaliny/yubal/yurra/jana, bare yaluy/yinyay, and nyajin past only. Lexicon checked selected visible sky/celestial senses only, with binyu/jiri/kaba/wungar/yiril source-prose extensions closed. Syntax checked five complementary non-singular past pronoun-perception frame bands. Fidelity checked literal visual past 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 moon/month/place-story, lightning strike, death-spirit/death-omen, heaven/sky-mob/fine-day compound, rain falling/coming/no-rain/rainbird/weather-event, sun-time/hot-season/sun-locative, rainbow story/snake/water-hole, target case, productive compound, productive reduplication, demonstrative case, pronoun case, perception compound, nonpast/purposive/reduplicated perception drift, support inflection, or recent water/landform/fauna/body/dwelling/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 283 lessons covering source checks, duplicate avoidance, past perception support, sky/celestial scope, coverage, lexical target senses, morphology, syntax, fidelity, register, process traps, and handoff.", artifact_path=PROCESS_LOG, 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 283 targets and support heads.", artifact_path=PROCESS_LOG, created_at=NOW)
    db.execute("UPDATE sentences SET status='accepted', updated_at=? WHERE batch_id=?", (NOW, batch_id))
    db.execute("UPDATE batches SET notes=?, cheatsheet_version=?, guide_version=? WHERE id=?", (NOTES, "Rule 283 accepted", "operator-guide-2026-07-09", batch_id))
    verified_after, words_after = db.execute(
        """
        SELECT COUNT(*), SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1)
        FROM sentences
        WHERE status IN ('accepted','revised')
        """
    ).fetchone()
    accepted_after = db.execute("SELECT COUNT(*) FROM sentences WHERE batch_id=? AND status='accepted'", (batch_id,)).fetchone()[0]
    review_count = db.execute("SELECT COUNT(*) FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)", (batch_id,)).fetchone()[0]
    lesson_count = 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-325-verify'").fetchone()[0]
    record_event(db, batch_label=LABEL, phase="close", event_type="close-success", actor="claude-main", detail=f"Closed Batch 325 / Rule 283 with {accepted_after} accepted rows, {review_count} review passes, {lesson_count} lessons, and {lexeme_logs} lexeme/source-log rows. Verified sentences moved {verified_before}->{verified_after}; Kuku words moved {words_before}->{words_after}.", command="python3 batch_scripts/close_325.py", output_excerpt=f"closed batch-325: accepted={accepted_after}, reviews={review_count}, lessons={lesson_count}, lexeme_logs={lexeme_logs}, verified {verified_before}->{verified_after}, kuku_words {words_before}->{words_after}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit()
    print(
        f"closed batch-325: accepted={accepted_after}, reviews={review_count}, lessons={lesson_count}, "
        f"lexeme_logs={lexeme_logs}, verified {verified_before}->{verified_after}, kuku_words {words_before}->{words_after}"
    )
    return 0


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