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

NOTES = (
    "VISIBLE WATER/LANDFORM COMPLEMENTARY NONPAST PRONOUN PERCEPTION SWEEP AFTER RULE 279 (Rule 280). 50 rows. "
    "TARGETS: dajali deep water, jalun sea, jirka spring, bubu ground/earth, manjal mountain, daburri swamp, "
    "dulngku reef, yilki creek, yiri waterfall, and yirri running water. SUPPORT: bare nominative ngayu, yundu, "
    "nyulu, bula, and ngana plus yaluy/yinyay and nyajil. FRAMES: Ngayu TARGET yinyay nyajil, Yundu TARGET yaluy "
    "nyajil, Nyulu TARGET yinyay nyajil, Bula TARGET yaluy nyajil, and Ngana TARGET yaluy nyajil. REVIEW: first "
    "candidate with bana and wawubaja was rejected after exact duplicate pressure; no pronoun case, water-use, "
    "drinking/getting/filling/washing/swimming, travel, route, road, crossing, flood, tide, salt-pan, whale-oil, "
    "spring-season, place-name, bubu country/place extension, daburri ecology/use, dulngku fishing/navigation, "
    "source-use, story, water-spirit, danger, ownership, target case, demonstrative case, target compound, "
    "productive reduplication, perception compound, past/purposive/reduplicated perception drift, support inflection, "
    "or recent sky/fire/fauna/body/dwelling drift was opened."
)

LESSONS = [
    ("source", "Rule 280 selected ten visible water/landform target heads: dajali, jalun, jirka, bubu, manjal, daburri, dulngku, yilki, yiri, and yirri.", "Rule 280: visible target inventory."),
    ("source", "Direct dictionary line readback was explicit: dajali 4510-4518, jalun 7612-7620, jirka 9803-9813, bubu 3452-3470, manjal 17832-17840, daburri 4428-4442, dulngku 6520-6530, yilki 30031-30039, yiri 30410-30418, and yirri 30507-30515.", "Rule 280: dictionary source lines."),
    ("source", "Patz grammar lines 2577-2586 and 2592-2603 supplied the personal pronoun table and base forms for bare nominative ngayu, yundu, nyulu, bula, and ngana.", "Rule 280: pronoun source."),
    ("source", "Patz grammar lines 2678-2686 supported bula as third dual and ngana as first plural inclusive.", "Rule 280: bula and ngana source."),
    ("source", "Patz Table 3.12 lines 2838-2845 supplied Yalanji yaluy 'here' and yinyay 'there'; Rule 280 used only bare local demonstratives.", "Rule 280: demonstrative source."),
    ("source", "Patz lines 3043-3049 supplied nyaji-l 'see' as the nonpast form; Rule 280 used corpus-conventional nyajil as the nonpast visual-perception surface only.", "Rule 280: nonpast perception source."),
    ("source", "Patz lines 2568-2571 supplied nyaji-ny 'see-PAST' only as contrast; Rule 280 did not use past nyajin.", "Rule 280: past contrast."),
    ("process", "The first Rule 280 candidate retained bana and wawubaja but exact duplicate preflight found Ngayu bana yinyay nyajil. and Ngayu wawubaja yinyay nyajil. in Batch 194; those targets were replaced with sourced daburri and dulngku rather than special-cased.", "Rule 280: duplicate avoidance."),
    ("process", "Exact duplicate preflight over the final 50 Rule 280 Kuku surfaces returned no accepted, revised, or under-review collisions.", "Rule 280: duplicate preflight."),
    ("process", "Token-aware target coverage before banking after Rule 279 was dajali 68, jalun 113, jirka 28, bubu 687, manjal 55, daburri 34, dulngku 25, yilki 27, yiri 25, and yirri 25.", "Rule 280: target coverage audit."),
    ("process", "Support coverage before banking after Rule 279 was ngayu 1381, yundu 1241, nyulu 1856, bula 284, ngana 1030, yaluy 2844, yinyay 3108, and nyajil 3573.", "Rule 280: support coverage audit."),
    ("lexicon", "Dajali remained deep water only; no danger, crossing, swimming, travel, route, or depth-event predicate was imported.", "Rule 280: dajali."),
    ("lexicon", "Jalun remained sea only; flood, seafarer, sea-fauna, salt-water, route, and tide rows stayed closed.", "Rule 280: jalun."),
    ("lexicon", "Jirka remained spring as a water source only; season and place-name readings stayed closed.", "Rule 280: jirka."),
    ("lexicon", "Bubu remained visible ground/earth only; country, belonging, place, Shipton's Flats example prose, and dirtiness rows stayed closed.", "Rule 280: bubu."),
    ("lexicon", "Manjal remained mountain only; mountain story, mountain-and-river place, dog legend, route, and place-name prose stayed closed.", "Rule 280: manjal."),
    ("lexicon", "Daburri remained swamp/brackish swamp water only; ecology, use, crossing, danger, and place rows stayed closed.", "Rule 280: daburri."),
    ("lexicon", "Dulngku remained reef only; fishing, travel, navigation, danger, ecology, and place rows stayed closed.", "Rule 280: dulngku."),
    ("lexicon", "Yilki remained creek only; creek-place, crossing, travel, ecology, and use prose stayed closed.", "Rule 280: yilki."),
    ("lexicon", "Yiri remained waterfall only; no rainbow yiril, escape yiril, place-name, water-use, or story row was imported.", "Rule 280: yiri."),
    ("lexicon", "Yirri remained running water only; yirri-damal leak, current/flow event, and water-use rows stayed closed.", "Rule 280: yirri."),
    ("morphology", "All Rule 280 target nouns stayed bare: no LOC, DAT, ABL, PERL, ERG, INST, COMIT, POSS, PRIV, EXCESS, plural, derivation, or target suffix was admitted.", "Rule 280: bare targets."),
    ("morphology", "The subject support forms stayed bare nominatives: ngayu, yundu, nyulu, bula, and ngana were not inflected for accusative, dative, locative, ablative, comitative, or possessive.", "Rule 280: bare nominative pronouns."),
    ("morphology", "Yaluy, yinyay, and nyajil stayed uninflected support heads; no demonstrative case, local-derived form, past nyajin, purposive nyaji-nka, reduplicated watching form, or support suffix was admitted.", "Rule 280: uninflected support."),
    ("morphology", "No target compound, place-name compound, water-use construction, route/travel construction, pronoun-case construction, or productive reduplication was built from the Rule 280 heads.", "Rule 280: no compounds or reduplication."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yinyay nyajil for first singular there nonpast visual perception.", "Rule 280: 1sg there band."),
    ("syntax", "Rows 11-20 used Yundu TARGET yaluy nyajil for second singular here nonpast visual perception.", "Rule 280: 2sg here band."),
    ("syntax", "Rows 21-30 used Nyulu TARGET yinyay nyajil for third singular there nonpast visual perception.", "Rule 280: 3sg there band."),
    ("syntax", "Rows 31-40 used Bula TARGET yaluy nyajil for third dual here nonpast visual perception.", "Rule 280: 3du here band."),
    ("syntax", "Rows 41-50 used Ngana TARGET yaluy nyajil for first plural inclusive here nonpast visual perception.", "Rule 280: 1pl inclusive here band."),
    ("fidelity", "English stayed literal visual nonpast perception/reference prose: selected subject pronoun value, target label, here/there, and see/sees only.", "Rule 280: literal English."),
    ("fidelity", "The batch did not convert dictionary alternate glosses or source prose into drinking, getting, filling, washing, swimming, crossing, travel, route, flood, tide, salt-pan, whale-oil, season, place-name, story, ecology, fauna/flora, water-spirit, danger, ownership, country/belonging, dirtiness, fishing/navigation, or use claims.", "Rule 280: source-prose restraint."),
    ("register", "Rows remained plain elicitation-style visual nonpast perception clauses; no route instruction, travel narrative, ecological note, water-use instruction, danger warning, country/place statement, fishing/navigation note, or story register was introduced.", "Rule 280: register."),
    ("process", "Rules 149-279 carry-forward traps stayed closed, especially recent visible water/landform traps plus older sky, fire, fauna, body, dwelling, and source-prose traps.", "Rule 280: carry-forward closure."),
    ("handoff", "Next batch may continue from 16,197 if this closes; do not infer water-use, travel, route, place-name, flood/tide, ecology, story, bubu country/place, daburri swamp-use, dulngku reef-use, target-case, pronoun-case, perception-compound, past/purposive/reduplicated perception, or support-inflection grammar from Rule 280.", "Rule 280: next cadence."),
]

LEXEMES = [
    ("dajali", "noun", None, "NA", "deep water", "batch-322: visible deep-water nonpast perception/reference only; danger, crossing, swimming, and route rows closed."),
    ("jalun", "noun", None, "NA", "sea", "batch-322: visible sea nonpast perception/reference only; flood, seafarer, sea-fauna, tide, and route rows closed."),
    ("jirka", "noun", None, "NA", "spring", "batch-322: visible spring/water-source nonpast perception/reference only; season and place-name rows closed."),
    ("bubu", "noun", None, "NA", "ground", "batch-322: visible ground/earth nonpast perception/reference only; country, belonging, place, and dirtiness rows closed."),
    ("manjal", "noun", None, "NA", "mountain", "batch-322: visible mountain nonpast perception/reference only; mountain story, dog legend, route, and place-name prose closed."),
    ("daburri", "noun", None, "NA", "swamp", "batch-322: visible swamp/brackish-swamp-water nonpast perception/reference only; ecology, use, crossing, danger, and place rows closed."),
    ("dulngku", "noun", None, "NA", "reef", "batch-322: visible reef nonpast perception/reference only; fishing, travel, navigation, danger, ecology, and place rows closed."),
    ("yilki", "noun", None, "NA", "creek", "batch-322: visible creek nonpast perception/reference only; creek-place, crossing, travel, ecology, and use prose closed."),
    ("yiri", "noun", None, "NA", "waterfall", "batch-322: visible waterfall nonpast perception/reference only; rainbow yiril, escape yiril, place-name, water-use, and story rows closed."),
    ("yirri", "noun", None, "NA", "running water", "batch-322: visible running-water nonpast perception/reference only; yirri-damal leak and water-use rows closed."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-322: bare nominative subject support only."),
    ("yundu", "pronoun", None, "NA", "second singular nominative", "batch-322: bare nominative subject support only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-322: bare nominative subject support only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-322: bare nominative subject support only."),
    ("ngana", "pronoun", None, "NA", "first plural inclusive nominative", "batch-322: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-322: bare local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-322: bare local demonstrative support only."),
    ("nyajil", "verb", "l", "NA", "see", "batch-322: nonpast visual perception support only, corpus-conventional surface from nyaji-l see.NPST."),
]


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-322-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 280 rows. Morphology checked bare water/landform nouns, bare nominative ngayu/yundu/nyulu/bula/ngana, bare yaluy/yinyay, and nyajil nonpast only. Lexicon checked selected visible water/landform senses only, with bubu/daburri/dulngku restricted to literal reference. Syntax checked five complementary nonpast pronoun-perception frame bands. Fidelity checked literal visual nonpast 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 pronoun case, drinking, getting, filling, washing, swimming, crossing, travel, route, road, flood, tide, salt-pan, whale-oil, spring-season, place-name, bubu country/place extension, daburri ecology/use, dulngku fishing/navigation, mountain story, water-source use, water spirit, fish/shellfish/reptile/plant/ecology, danger, ownership, target case, productive compound, productive reduplication, demonstrative case, perception compound, past/purposive/reduplicated perception drift, support inflection, or recent sky/fire/fauna/body/dwelling 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 280 lessons covering source checks, duplicate avoidance, nonpast perception support, water/landform 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 280 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 280 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-322-verify'").fetchone()[0]
    record_event(
        db,
        batch_label=LABEL,
        phase="close",
        event_type="close-success",
        actor="claude-main",
        detail=f"Closed Batch 322 / Rule 280 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_322.py",
        output_excerpt=f"closed batch-322: 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-322: 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())
