#!/usr/bin/env python3
"""Close batch-159 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-159"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-159-narrative-sequence-support-lexicon-process.md"
LENSES = ("morphology", "lexicon", "syntax", "fidelity", "register")

NOTES = (
    "LEXICON: NARRATIVE SEQUENCE SUPPORT VOCABULARY (Rule 117). 50 rows. DESIGN: hand-authored lexical rows for "
    "movement/return/following, preparation/transfer/camp work, rest/sleep/wake, speech/perception/response, and "
    "weather/time event predicates. SOURCE CONTROLS: dictionary.yaml plus Patz grammar examples, with grammar used "
    "as controlling evidence for posture/rest roots and narrative frames. PROCESS STORAGE: source inventory, "
    "grammar-vs-dictionary decisions, existing-surface scan, row plan, static guards, review correction, lint, "
    "five-lens review, close, export, docs, and live verification are stored."
)

LESSONS = [
    ("process", "A lexical batch after a construction batch should strengthen content vocabulary without re-drilling the previous clitics.", "Rule 117: lexical after construction."),
    ("syntax", "Do not translate every English narrative 'then' with a Kuku temporal clitic; lexical event order can be plain when no Rule 116 construction is targeted.", "Rule 117: no clitic overuse."),
    ("lexicon", "`wukurri-l` is a transitive follow verb; include a followee where English requires one.", "Rule 117: follow frames."),
    ("lexicon", "`bawa-l` is transitive leave/quit and can take a place or thing as object.", "Rule 117: leave frames."),
    ("lexicon", "`nyunba-y` is the safe return/turn-back verb; use it instead of inventing a return compound.", "Rule 117: return lexicon."),
    ("lexicon", "`wundi-l` covers bring/take; direction is supplied by destination/source case rather than a separate English-like verb choice.", "Rule 117: bring/take."),
    ("lexicon", "`ngara-l` is the sourced verb for set up/build/spread, including `bayan ngara-ny` set up camp.", "Rule 117: camp setup."),
    ("lexicon", "`kida-l` covers sweep/remove/wipe and is safe for bubu/bayan cleaning rows.", "Rule 117: cleaning lexicon."),
    ("lexicon", "`nanda-l` is close/shut/bury; avoid a phantom close verb.", "Rule 117: close lexicon."),
    ("lexicon", "`yijarri-l` is the sourced put/place verb and should not be replaced with English-like set/place inventions.", "Rule 117: put/place."),
    ("lexicon", "For posture/rest, grammar is the controlling source: `bunda-y` sit down, `bundanda-y` stay/sit-state, `wuna-y` lie down, `wunana-y` rest/sleep-state.", "Rule 117: posture source priority."),
    ("lexicon", "`warngku wuna-y` is the transparent sleep compound; keep `warngku` visible in analysis when English says sleep.", "Rule 117: sleep compound."),
    ("lexicon", "`wandi-l` covers get up, wake up, come out, and emerge; context must do the disambiguating work.", "Rule 117: wake/emerge."),
    ("lexicon", "`nyaji-l` covers see/hear/perceive; match English tense to Kuku inflection exactly.", "Rule 117: perception tense."),
    ("lexicon", "`milka-janay` is listen/obey; Batch 159 uses only concrete listening, not abstract obedience.", "Rule 117: listen caution."),
    ("lexicon", "`yunga-l` can send a message; keep `kuku` visible for message/news rows.", "Rule 117: send-message frame."),
    ("lexicon", "`yajarri-l` laugh can take a dative/about target in sourced text frames.", "Rule 117: laugh target."),
    ("lexicon", "`warrmba-bunga-l` find is sourced for uncovered/find frames; use it instead of an invented find verb.", "Rule 117: find lexicon."),
    ("lexicon", "Weather narratives can stay lexical: rain falls with `dara-y`, wind/storm comes with `kada-y`, water rises with `yalbay-ma-l`, rain stops with `wula-y`.", "Rule 117: weather predicates."),
    ("fidelity", "A review-time correction changed row 33 English from past to present because `nyaji-l` was intentionally nonpast.", "Rule 117: review correction evidence."),
    ("process", "Store grammar-vs-dictionary decisions in process_events when dictionary entries are thin but the grammar has examples.", "Rule 117: process memory."),
    ("process", "Exact recent surfaces should be scanned even when rows are hand-authored; near-source variation is intentional, exact duplication is not.", "Rule 117: duplicate scan."),
]

LEXEMES = [
    ("dunga-y", "intransitive-verb", "y-conjugation", None, "go", "batch-159: movement support; source Patz examples with dunga-y/dunga-ny."),
    ("kada-y", "intransitive-verb", "y-conjugation", None, "come", "batch-159: movement/weather-event support."),
    ("nyunba-y", "intransitive-verb", "y-conjugation", None, "turn back; return", "batch-159: sourced return/turn-back verb."),
    ("wukurri-l", "transitive-verb", "l-conjugation", None, "follow", "batch-159: follow verb, normally with a followee."),
    ("bawa-l", "transitive-verb", "l-conjugation", None, "leave; quit", "batch-159: leave place/thing."),
    ("wundi-l", "transitive-verb", "l-conjugation", None, "bring; take", "batch-159: bring/take with destination/source case."),
    ("mani-l", "transitive-verb", "l-conjugation", None, "get", "batch-159: preparation/getting rows."),
    ("daji-l/daya", "transitive-verb", "l-conjugation", "imperative daya", "give", "batch-159: give command form."),
    ("waju-l", "transitive-verb", "l-conjugation", None, "cook; burn; light", "batch-159: food/fire preparation."),
    ("nuka-l", "transitive-verb", "l-conjugation", None, "eat; drink", "batch-159: food and water consumption."),
    ("warmba-l", "transitive-verb", "l-conjugation", None, "fill", "batch-159: fill billycan with water."),
    ("yijarri-l", "transitive-verb", "l-conjugation", None, "put; place", "batch-159: put/place support."),
    ("kida-l", "transitive-verb", "l-conjugation", None, "sweep; remove; wipe", "batch-159: camp cleaning support."),
    ("nanda-l", "transitive-verb", "l-conjugation", None, "close; shut; bury", "batch-159: close house support."),
    ("ngara-l", "transitive-verb", "l-conjugation", None, "build; spread; set up camp", "batch-159: bayan ngara-ny camp setup."),
    ("bunda-y", "intransitive-verb", "y-conjugation", None, "sit down", "batch-159: grammar-controlled posture source."),
    ("bundanda-y", "intransitive-verb", "y-conjugation", "reduplicated", "stay; keep sitting; live at", "batch-159: grammar-controlled stay/sit-state."),
    ("wuna-y", "intransitive-verb", "y-conjugation", None, "lie down", "batch-159: posture source."),
    ("wunana-y", "intransitive-verb", "y-conjugation", "reduplicated", "rest; keep lying; sleep", "batch-159: rest/sleep-state."),
    ("warngku wuna-y", "intransitive-verb", "y-conjugation", "compound", "sleep", "batch-159: transparent sleep compound."),
    ("wandi-l", "intransitive-verb", "l-conjugation", None, "get up; wake up; come out", "batch-159: wake/emerge support."),
    ("wula-y", "intransitive-verb", "y-conjugation", None, "die; stop", "batch-159: rain-stop extension with caution."),
    ("babaji", "transitive-verb", "y-conjugation", None, "ask", "batch-159: ask-about-food frame."),
    ("balka-l", "transitive-verb", "l-conjugation", None, "tell; make; speak", "batch-159: tell plus purposive complement."),
    ("nyaji-l", "transitive-verb", "l-conjugation", None, "see; hear; perceive", "batch-159: perception rows and tense correction."),
    ("milka-janay", "intransitive-verb", "y-conjugation", "compound", "listen; obey", "batch-159: concrete listen use only."),
    ("yunga-l", "transitive-verb", "l-conjugation", None, "send; allow to go", "batch-159: send-message frame."),
    ("yajarri-l", "transitive-verb", "l-conjugation", None, "laugh", "batch-159: laugh-at-children frame."),
    ("yirrka-y", "intransitive-verb", "y-conjugation", None, "call out; sing out", "batch-159: night call-out row."),
    ("warrmba-bunga-l", "transitive-verb", "l-conjugation", "causative compound", "find", "batch-159: find tracks row."),
    ("dara-y", "intransitive-verb", "y-conjugation", None, "fall", "batch-159: rain-fall weather predicate."),
    ("yalbay-ma-l", "intransitive-verb", "l-conjugation", "inchoative", "become big; rise", "batch-159: water-rise weather predicate."),
    ("jarramali", "noun", None, None, "thunderstorm", "batch-159: weather event noun."),
    ("muyar", "noun", None, None, "wind", "batch-159: weather event noun."),
    ("muduwajuny", "temporal", None, None, "at daybreak", "batch-159: time-event support."),
    ("wunkuwingku", "temporal", None, None, "in the morning", "batch-159: time-event support."),
    ("yilay-yilay", "temporal", None, None, "late afternoon", "batch-159: time-event support."),
    ("kunarangkal", "temporal", None, None, "middle of the night", "batch-159: time-event support."),
]


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-159-verify", note, NOW),
        )
    record_event(
        db,
        batch_label=LABEL,
        phase="lint",
        event_type="pre-close-lint-pass",
        actor="claude-main",
        detail=(
            "After the row 33 fidelity correction, full-corpus lint passed under review: 8047 rows scanned, "
            "0 issues flagged; accepted goal metric correctly remained 7997 until close."
        ),
        command="python3 lint_corpus.py",
        output_excerpt="lint: 8047 rows scanned, 0 issues flagged; GOAL METRIC: 7997 / 20000 verified sentences (91702 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 117 rows. Morphology checked y/l-conjugation surfaces, "
            "past -n, nonpast -y/-l, command daya, locative/dative/ablative/comitative cases, and no Rule 116 "
            "clitic reuse. Lexicon checked each content word against dictionary or grammar source. Syntax checked "
            "transitive A marking, intransitive posture/weather subjects, and purposive complement in row 32. "
            "Fidelity checked tense/aspect and corrected row 33. Register stayed practical narrative-style pending "
            "elder verification."
        ),
        artifact_path=PROCESS_LOG,
        created_at=NOW,
    )
    record_event(
        db,
        batch_label=LABEL,
        phase="review",
        event_type="review-detail",
        actor="claude-main",
        detail=(
            "Rejected-risk decisions retained: no invented discourse particles; no TEMP1/TEMP2/TEMP3 drill; no "
            "phantom return/close/find/listen verbs; no unsourced abstract narrative vocabulary; grammar used as "
            "controlling evidence for posture and narrative frames where dictionary entries were thin."
        ),
        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 117 lessons covering lexical frames, source priority, weather predicates, and process safeguards.",
        artifact_path="batch_scripts/close_159.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 Rule 117 narrative support vocabulary.",
        artifact_path="batch_scripts/close_159.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 159: 50 accepted Rule 117 lexical rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_159.py",
        artifact_path="batch_scripts/close_159.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-159-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())
