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

NOTES = (
    "LAND-ANIMAL LEXICAL EXPANSION AFTER RULE 146 (Rule 147). 50 rows. TARGETS: bikibiki pig, kadar wallaby, "
    "julmbanu grey kangaroo, kaya dog, walkarr black scrub goanna, jarba generic snake, bajabaja blue-tongue lizard. "
    "FRAMES: yalbay size-state, support-only locative nominal clauses, past perception, present perception. REVIEW: "
    "bikibiki loan recorded; biki and bulki excluded; bajabaja animal sense only; jarba generic snake only; no hunting, "
    "killing, spearing, shooting, chasing, catching, cutting, biting, licking, eating, meat, food, poison, sickness, "
    "fear, taboo, storm, story, myth, totem, track, egg, tail, teeth, dog possession, target case forms, instruments, "
    "comitatives, possessives, compounds, or animal-behaviour ecology."
)

LESSONS = [
    ("process", "A lexical pass can widen the animal-name field only when each target has dictionary, Patz grammar, and lexeme-table readback.", "Rule 147: triple-source lexical gate."),
    ("process", "`Bulki` was excluded despite grammar examples because the parsed dictionary lacks an exact usable headword entry.", "Rule 147: dictionary gate beats convenience."),
    ("process", "Exact duplicate preflight found 50 planned rows, 50 unique surfaces, and no cross-corpus duplicates before banking.", "Rule 147: duplicate preflight."),
    ("lexicon", "`bikibiki` was admitted only as the reduplicated pig loan/contact animal; `biki` was not used.", "Rule 147: bikibiki only."),
    ("lexicon", "`kadar` was selected as wallaby / plains wallaby only.", "Rule 147: kadar sense."),
    ("lexicon", "`julmbanu` was selected as grey kangaroo only; no boss/metaphor, hunt, spear, or meat row.", "Rule 147: julmbanu sense."),
    ("lexicon", "`kaya` was selected as dog only; no dog-bite, barking, dog-tail, dog-food, or possession row.", "Rule 147: kaya sense."),
    ("lexicon", "`walkarr` was selected as black scrub goanna only; no viciousness, teeth, germs, food, or contrast row.", "Rule 147: walkarr sense."),
    ("lexicon", "`jarba` was selected as generic snake only; no bite, fear, poison, dead-snake instrument, rainbow-snake, or myth row.", "Rule 147: jarba sense."),
    ("lexicon", "`bajabaja` was selected as blue-tongue lizard only; no place, story-site, myth, egg, tongue-display, or fear row.", "Rule 147: bajabaja sense."),
    ("morphology", "All land-animal target heads stayed bare; no target dative, locative, ablative, instrumental, comitative, possessive, or compound forms appeared.", "Rule 147: target case restraint."),
    ("morphology", "Support locatives were limited to `madja-nga`, `ngalkal-ba`, `bayan-ba`, and `bubu-ngu`.", "Rule 147: support locative limit."),
    ("morphology", "`Bikibiki` was treated as a whole reduplicated loan head, not a productive reduplication template.", "Rule 147: reduplicated loan handling."),
    ("morphology", "`Bajabaja` was treated as a whole reduplicated lexical head, not a productive reduplication template.", "Rule 147: reduplicated lizard head."),
    ("morphology", "Common-noun A in perception rows was ERG-marked; pronoun A rows stayed bare.", "Rule 147: A marking."),
    ("syntax", "Size-state rows used bare target plus `yalbay` only.", "Rule 147: size-state syntax."),
    ("syntax", "Locative nominal clauses used bare target plus one approved support locative.", "Rule 147: support-location syntax."),
    ("syntax", "Past perception rows used `nyajin` with bare land-animal objects and optional support locative.", "Rule 147: past perception syntax."),
    ("syntax", "Present perception rows used `nyajil` with bare land-animal objects and optional support locative.", "Rule 147: present perception syntax."),
    ("fidelity", "English labels explicitly selected the intended animal senses: pig, wallaby, grey kangaroo, dog, black scrub goanna, snake, and blue-tongue lizard.", "Rule 147: selected-sense fidelity."),
    ("fidelity", "No hunting, killing, spearing, shooting, chasing, catching, cutting, biting, licking, eating, meat, food, poison, sickness, fear, taboo, storm, story, myth, totem, track, egg, tail, teeth, or behaviour inference was imported.", "Rule 147: no ecology inference."),
    ("register", "Rows remained ordinary descriptions of animals being big, being at a place, or being seen.", "Rule 147: register scope."),
    ("handoff", "Next cadence should consolidate this land-animal field before any new animal-use or danger semantics are considered.", "Rule 147: next cadence."),
    ("handoff", "Carry forward the `biki` exclusion, `bulki` dictionary-gate exclusion, `bajabaja` story-site trap, and `jarba` bite/fear/poison trap.", "Rule 147: carry-forward traps."),
    ("handoff", "If a future batch opens animal ecology, source each action verb or cultural predicate independently rather than inferring it from the animal noun.", "Rule 147: future ecology gate."),
]

LEXEMES = [
    ("bikibiki", "noun", None, "NA", "pig", "batch-189: selected reduplicated pig loan/contact animal; biki excluded."),
    ("biki", "noun", None, "NA", "pig base form", "batch-189: excluded as a target surface; use source-backed bikibiki only in this batch."),
    ("bulki", "noun", None, "NA", "cattle; bullock", "batch-189: excluded because parsed dictionary lacks exact usable headword entry."),
    ("kadar", "noun", None, "NA", "wallaby; plains wallaby", "batch-189: selected wallaby only; no hunting/eating row."),
    ("julmbanu", "noun", None, "NA", "grey kangaroo", "batch-189: selected grey kangaroo only; no boss/metaphor, hunt, spear, or meat row."),
    ("kaya", "noun", None, "NA", "dog", "batch-189: selected dog only; no bite, bark, tail, food, or possession row."),
    ("walkarr", "noun", None, "NA", "black scrub goanna", "batch-189: selected black scrub goanna only; no viciousness, teeth, germs, food, or contrast row."),
    ("jarba", "noun", None, "NA", "snake", "batch-189: selected generic snake only; no bite/fear/poison/instrument/myth row."),
    ("bajabaja", "noun", None, "NA", "blue-tongue lizard", "batch-189: selected animal sense only; no place/story-site/myth/egg/tongue-display row."),
    ("yalbay", "adjective", None, "NA", "big", "batch-189: size-state predicate for land-animal rows."),
    ("madja", "noun", None, "NA", "scrub; rainforest", "batch-189: support-only locative madja-nga."),
    ("ngalkal", "noun", None, "NA", "outside; open ground", "batch-189: support-only locative ngalkal-ba."),
    ("bayan", "noun", None, "NA", "camp; house", "batch-189: support-only locative bayan-ba."),
    ("bubu", "noun", None, "NA", "ground; country; place", "batch-189: support-only locative bubu-ngu."),
    ("nyaji-l", "verb", "l", "NA", "see; hear; perceive", "batch-189: past and present perception rows with land-animal objects."),
    ("ngamu", "noun", None, "NA", "mother", "batch-189: common-noun A in perception rows, ERG-marked."),
    ("nganjan", "noun", None, "NA", "father", "batch-189: common-noun A in perception rows, ERG-marked."),
    ("babi", "noun", None, "NA", "grandmother", "batch-189: common-noun A in perception rows, ERG-marked."),
    ("karrkay", "noun", None, "NA", "child", "batch-189: common-noun A in perception rows, ERG-marked."),
    ("kami", "noun", None, "NA", "grandfather", "batch-189: common-noun A in perception rows, ERG-marked."),
    ("jalbu", "noun", None, "NA", "woman", "batch-189: common-noun A in perception rows, ERG-marked."),
    ("dingkar", "noun", None, "NA", "man", "batch-189: common-noun A in perception rows, ERG-marked."),
    ("ngayu", "pronoun", None, "NA", "I; 1sg nominative", "batch-189: bare pronoun A in perception rows."),
    ("ngana", "pronoun", None, "NA", "we; 1pl inclusive", "batch-189: bare pronoun A in perception rows."),
    ("jana", "pronoun", None, "NA", "they; 3pl nominative", "batch-189: bare pronoun A in perception rows."),
]


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}")

    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.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-189-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 147 rows. Morphology checked bare land-animal targets, no "
            "target case morphology, no instruments/comitatives/possessives, approved support locatives only, whole "
            "reduplicated heads, common-noun A ERG, and pronoun A bare. Lexicon checked selected animal senses and "
            "excluded biki/bulki drift. Syntax checked size-state, locative nominal, past perception, and present "
            "perception frames. Fidelity checked animal-use/danger/story exclusions. Register stayed ordinary."
        ),
        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 hunting/killing/spearing/shooting/chasing/catching/cutting row, no biting/"
            "licking/barking row, no eating/meat/food row, no poison/sickness/fear/taboo/storm row, no story/myth/"
            "totem row, no track/egg/tail/teeth row, no dog possession row, no target instrument row, no target case "
            "form, and no unresolved water-fauna or bird/tree/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 147 lessons covering process, lexical senses, morphology, syntax, fidelity, register, and handoff.",
        artifact_path="batch_scripts/close_189.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 147 targets, excluded forms, support heads, verb, participants, and pronouns.",
        artifact_path="batch_scripts/close_189.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 189: 50 accepted Rule 147 land-animal lexical-expansion rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_189.py",
        artifact_path="batch_scripts/close_189.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 detail LIKE '%batch-189:%'").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, {lesson_count} lessons, "
        f"{lexeme_logs} lexeme/source-log rows, {process_events} process events, "
        f"under_review={under_review_remaining}, verified corpus={verified}"
    )
    return 0


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