#!/usr/bin/env python3
"""Close batch-155 after main-loop five-lens review."""

from __future__ import annotations

import datetime as dt
import json
import sqlite3
import sys

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-155"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-155-practical-contingency-lexicon-process.md"
LENSES = ("morphology", "lexicon", "syntax", "fidelity", "register")

NOTES = (
    "LEXICAL: PRACTICAL CONTINGENCY LEXICON FOR CONDITION/REASON CLAUSES (Rule 113). 50 rows. DESIGN: "
    "hand-authored practical vocabulary for weather, cold, fire, health, hunger, animal risk, road/water/camp "
    "situations, containers/tools, and support verbs, using already-reviewed Rule 112 clause frames. SOURCE "
    "CONTROLS: every content lexeme checked against the dictionary or Patz grammar; dakuy/dakwuy and "
    "bajaburray/baja-burray source-surface choices logged; no phantom lexemes; no yala coordination; no "
    "past-tense kaki; kunka/nganganjirrka restricted to in-case readings; nguba restricted to preposed "
    "possibility. PROCESS STORAGE: source pass, lexeme checks, static-guard correction, duplicate-gate "
    "correction, under-review lint, five-lens review, close, post-close lint, export, and live-doc verification "
    "are stored in process_events and the process log."
)

LESSONS = [
    ("process", "A lexical batch can legitimately reuse the previous construction rule, but the review target must remain lexical coverage rather than new syntax.", "Rule 113: lexical scope."),
    ("syntax", "Rule 113 rows reuse Rule 112 frames: nonpast kaki conditionals, kunka/nganganjirrka in-case clauses, and preposed nguba possibility clauses.", "Rule 113: construction reuse."),
    ("syntax", "Kaki rows remain nonpast/stative; a static preflight guard must distinguish real PAST from the substring inside NONPAST.", "Rule 113: kaki lint guard."),
    ("fidelity", "Kunka and nganganjirrka must not be used as generic 'maybe'; they mark in-case or hypothetical-reason relations.", "Rule 113: in-case guard."),
    ("fidelity", "Nguba is safest as a preposed independent possibility clause when the reason is conjectural rather than known.", "Rule 113: nguba reason strategy."),
    ("fidelity", "Balu was deliberately excluded from this lexical batch to avoid flattening wrong-assumption discourse into ordinary negation.", "Rule 113: balu exclusion."),
    ("lexicon", "Dakuy is the Patz/source surface used for dictionary dakwuy 'hungry'; both forms must stay cross-referenced.", "Rule 113: dakuy/dakwuy."),
    ("lexicon", "Bajaburray is the Patz/source surface used for dictionary baja-burray 'tired'; both forms must stay cross-referenced.", "Rule 113: bajaburray/baja-burray."),
    ("lexicon", "Kiway is cold as a noun/state source; kiway-kiway is the safe adjective-like surface for 'cold' in child-cold rows.", "Rule 113: kiway contrast."),
    ("lexicon", "Baya covers fire/firewood, and waju-l covers light/cook/burn; the English gloss must follow the local context.", "Rule 113: fire lexicon."),
    ("lexicon", "Weather contingency rows added checked vocabulary for kaba rain, muyar wind, junkurrji/junkuji strong, wumbul hot, and wungar sun/day.", "Rule 113: weather inventory."),
    ("lexicon", "Health contingency rows added checked vocabulary for bambay sick, ngiki cold/bronchitis, bangkan medicinal root, bangkarr body, and yangka green ant.", "Rule 113: health inventory."),
    ("lexicon", "Animal-risk rows added checked vocabulary for kaya dog, jarba snake, bikibiki pig, kuyu fish, kalka spear, juku stick/wood, and badur fishing line.", "Rule 113: animal-risk inventory."),
    ("lexicon", "Road/camp rows added checked vocabulary for baral road/path, baral-darr along the road, bana water, bayan camp/house, bubu ground, madja scrub, and ngundu close by.", "Rule 113: road/camp inventory."),
    ("morphology", "Source-shaped dependent forms such as dakuy-ma-nya-mun-ku, bambay-ma-nya-mun-ku, kada-nya-mun-ku, and bayka-nya-mun-ku remain higher confidence than improvised subordination.", "Rule 113: dependent-form provenance."),
    ("morphology", "Case-marked practical nouns were reviewed as lexical entries plus case: baral-ba, baral-ka, baral-darr, bana-ka, bana-nga, bana-ji, bayan-ba, madja-nga, and karrkay-anda.", "Rule 113: case review."),
    ("syntax", "Imperative response clauses are useful for practical contingencies, but the condition/premise still needs ordinary Kuku clause order and source-checked verbs.", "Rule 113: imperative responses."),
    ("syntax", "Exact Patz sentences already present in the corpus should become source models, not duplicates; row 22 was revised after the duplicate gate caught an existing Batch 126 surface.", "Rule 113: duplicate-source handling."),
    ("register", "Rows should read like fieldwork-appropriate practical instructions, not bureaucratic emergency prose or English idioms translated word-for-word.", "Rule 113: register control."),
    ("process", "Failed preflights, duplicate collisions, row revisions, lint output, and docs verification are process data and must be stored, not hidden behind a clean final count.", "Rule 113: process storage."),
]

LEXEMES = [
    ("kaba", "noun", None, "ABS subject", "rain", "batch-155: weather contingency rows."),
    ("muyar", "noun", None, "ABS subject", "wind", "batch-155: strong-wind contingency row."),
    ("junkurrji", "adjective-form", None, "junkurr plus comitative -ji", "strong", "batch-155: dictionary/source strong-wind vocabulary."),
    ("junkuji", "adjective-form", None, "source-shaped strong predicate", "strong", "batch-155: Patz source cross-reference for strong wind."),
    ("wumbul", "adjective", None, "state predicate", "hot", "batch-155: sun/fire heat rows."),
    ("kiway", "noun", None, "state noun", "cold", "batch-155: cold comes in-case rows."),
    ("kiway-kiway", "adjective-form", None, "reduplicated cold form", "cold", "batch-155: child-cold row."),
    ("baya", "noun", None, "ABS object", "fire; firewood", "batch-155: firewood-taking and fire-lighting rows."),
    ("wungar", "noun", None, "ABS subject/time noun", "sun; day", "batch-155: hot sun/day condition rows."),
    ("bambay", "adjective", None, "state predicate; inchoative bambay-ma-", "sick", "batch-155: sickness and in-case remedy rows."),
    ("dakwuy", "adjective", None, "dictionary headword", "hungry", "batch-155: cross-reference for Patz/source surface dakuy."),
    ("dakuy", "adjective-form", None, "Patz/source surface", "hungry", "batch-155: hunger contingency rows."),
    ("dakuy-ma-nya-mun-ku", "verb-form", None, "hungry-INCHO-SUB-mun-DAT", "in case I get hungry", "batch-155: Patz-source dependent hunger form."),
    ("ngiki", "noun", None, "COMIT ngiki-ji; PRIV ngiki-kari", "cold; bronchitis", "batch-155: cold/remedy rows."),
    ("ngiki-kari", "adjective-form", None, "cold-PRIV", "without a cold", "batch-155: recovery/wellness row."),
    ("baja-burray", "adjective", None, "dictionary headword", "tired", "batch-155: cross-reference for Patz/source surface bajaburray."),
    ("bajaburray", "adjective-form", None, "Patz/source surface", "tired", "batch-155: tiredness reason rows."),
    ("bangkan", "noun", None, "ABS object", "medicinal root", "batch-155: remedy/road rows."),
    ("bangkarr", "noun", None, "body noun", "body", "batch-155: tired-body row."),
    ("yangka", "noun", None, "ABS object", "green ant", "batch-155: green-ant remedy row."),
    ("kaya", "noun", None, "ERG kaya-ngka; COMIT kaya-nji", "dog", "batch-155: dog-bite and hunting rows."),
    ("jarba", "noun", None, "ERG jarba-bu", "snake", "batch-155: snake-road and snake-bite rows."),
    ("bikibiki", "noun", None, "LOC bikibiki-nga", "pig", "batch-155: pig-risk and hunting rows."),
    ("kuyu", "noun", None, "ERG kuyu-ngku", "fish", "batch-155: fish-bite and cooking rows."),
    ("baral", "noun", None, "LOC baral-ba; DAT baral-ka; PERL baral-darr", "road; path", "batch-155: road/water/travel rows."),
    ("baral-darr", "case-form", None, "road-PERL", "along the road", "batch-155: no-water-along-road rows."),
    ("bana", "noun", None, "LOC bana-nga; DAT bana-ka; COMIT bana-ji", "water", "batch-155: water-taking and water-location rows."),
    ("bayan", "noun", None, "LOC bayan-ba", "house; camp; shelter", "batch-155: camp/house rows."),
    ("bubu", "noun", None, "ABS object", "ground; country", "batch-155: house-cleaning row."),
    ("madja", "noun", None, "LOC madja-nga", "scrub", "batch-155: child-in-scrub row."),
    ("ngundu", "adverb", None, "preverbal locational", "close by; near", "batch-155: snake-nearby row."),
    ("janay", "verb", "y", "NONPAST jana-y", "stand; be", "batch-155: snake close-by predicate."),
    ("jungkalu", "noun", None, "ABS object", "billycan", "batch-155: water/container rows."),
    ("balji", "noun", None, "ABS object", "bag; dillybag", "batch-155: container-choice rows."),
    ("kalka", "noun", None, "ABS object", "spear", "batch-155: pig-risk rows."),
    ("juku", "noun", None, "ABS object", "tree; wood; stick", "batch-155: dog-bite in-case row."),
    ("badur", "noun", None, "ABS object", "hook and line; fishing line", "batch-155: fish-bite possibility row."),
    ("wundil", "verb", "l", "NONPAST wundi-l; IMP wundi", "bring; take", "batch-155: practical preparation rows."),
    ("bawal", "verb", "l", "NONPAST bawa-l; IMP bawa", "leave; quit", "batch-155: road/fishing-line rows."),
    ("bundanday", "verb", "y", "NONPAST bundanda-y", "stay; sit; live", "batch-155: camp-stay rows."),
    ("nandal", "verb", "l", "NONPAST nanda-l", "close; shut; bury", "batch-155: house-closing rows."),
    ("dajil", "verb", "l", "NONPAST daji-l", "give", "batch-155: food/remedy giving rows."),
    ("wajul", "verb", "l", "NONPAST waju-l; IMP waju", "cook; burn; light a fire", "batch-155: food/fire rows."),
    ("kidal", "verb", "l", "NONPAST kida-l", "sweep; remove; wipe", "batch-155: house-sweeping rows."),
    ("dayirr-bungal", "verb-form", None, "clean-CAUS-NONPAST", "clean it", "batch-155: house-cleaning row."),
    ("nyajil", "verb", "l", "NONPAST nyaji-l", "see; hear; perceive", "batch-155: snake-road and mother-sees-child rows."),
    ("baykal", "verb", "l", "NONPAST bayka-l; PRECAUT bayka-nyji", "bite; ache", "batch-155: dog/snake/fish bite rows."),
    ("karrba", "verb", None, "imperative/source form", "touch", "batch-155: vicious-dog precautionary row."),
    ("balkal", "verb", "l", "imperative balka", "tell; make", "batch-155: dog-bite tell-me row."),
    ("ngakiji", "verb", None, "REF hide; NONPAST ngaki-ji-y", "hide", "batch-155: child-in-scrub row."),
    ("maraji", "verb", None, "nonpast/imperative-like lexical surface", "swim", "batch-155: deep-water row."),
]


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:
        raise SystemExit(f"{LABEL} must have 50 rows before close; found {total}")
    if accepted:
        raise SystemExit(f"{LABEL} already has {accepted} accepted/revised rows; refusing to overwrite")
    if under_review != 50:
        raise SystemExit(f"{LABEL} must have 50 under_review rows before close; found {under_review}")

    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.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-155-verify", note, 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 113 rows. Morphology lens checked nonpast l/y endings, "
            "imperative response forms, comitative/locative/dative/perlative/instrumental/ergative case, and "
            "source-shaped -nya-mun-ku dependent forms. Lexicon lens checked every content word against dictionary "
            "or grammar evidence, including dakuy/dakwuy and bajaburray/baja-burray source variants. Syntax lens "
            "enforced Rule 112 frame reuse, nonpast kaki, preposed nguba, and in-case kunka/nganganjirrka. Fidelity "
            "lens guarded against English maybe/but flattening and exact-source copying. Register lens kept the rows "
            "as practical fieldwork-style instructions pending elder verification."
        ),
        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 113 lessons covering lexical scope, construction reuse, source-surface variants, case review, register, duplicate handling, and process storage.",
        artifact_path="batch_scripts/close_155.py",
        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 the Rule 113 practical contingency inventory.",
        artifact_path="batch_scripts/close_155.py",
        created_at=NOW,
    )
    db.execute("UPDATE batches SET notes=? WHERE id=?", (NOTES, batch_id))
    db.execute("UPDATE sentences SET status='accepted', updated_at=? WHERE batch_id=?", (NOW, batch_id))
    record_event(
        db,
        batch_label=LABEL,
        phase="close",
        event_type="close-success",
        actor="claude-main",
        detail="Closed Batch 155: 50 accepted Rule 113 practical-contingency lexicon rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_155.py",
        artifact_path="batch_scripts/close_155.py",
        created_at=NOW,
    )
    db.commit()
    reviews = db.execute(
        "SELECT COUNT(*) FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)",
        (batch_id,),
    ).fetchone()[0]
    verified = db.execute("SELECT COUNT(*) FROM sentences WHERE status IN ('accepted','revised')").fetchone()[0]
    under_review_remaining = db.execute("SELECT COUNT(*) FROM sentences WHERE status='under_review'").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-155-verify'").fetchone()[0]
    process_events = db.execute("SELECT COUNT(*) FROM process_events WHERE batch_label=?", (LABEL,)).fetchone()[0]
    print(
        f"closed {LABEL}: 50 accepted rows, {reviews} review passes, "
        f"{lesson_count} lessons, {lexeme_logs} lexeme/source-log rows, "
        f"{process_events} process events, under_review={under_review_remaining}, "
        f"verified corpus={verified}"
    )
    return 0


if __name__ == "__main__":
    sys.exit(main())
