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

NOTES = (
    "CONSTRUCTION CONSOLIDATION AFTER RULE 147 (Rule 148). 50 rows. TARGETS RETAINED: bikibiki pig, kadar wallaby, "
    "julmbanu grey kangaroo, kaya dog, walkarr black scrub goanna, jarba generic snake, bajabaja blue-tongue lizard. "
    "FRAMES: support-only locative nominal clauses, bare past perception, support-locative past perception, present "
    "perception. REVIEW: no new target heads, 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, barking, 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 construction pass after land-animal lexical expansion can strengthen support-location and perception frames without opening animal ecology.", "Rule 148: construction before ecology."),
    ("process", "Rule 148 reused the exact Rule 147 target set and admitted no new target heads.", "Rule 148: no new targets."),
    ("process", "Exact duplicate preflight found 50 planned rows, 50 unique surfaces, and no cross-corpus duplicates before banking.", "Rule 148: duplicate preflight."),
    ("lexicon", "`bikibiki` remained the reduplicated pig loan/contact animal; `biki` remained excluded.", "Rule 148: bikibiki retained."),
    ("lexicon", "`bulki` remained excluded because the parsed dictionary lacks an exact usable headword entry.", "Rule 148: bulki still excluded."),
    ("lexicon", "`kadar` remained wallaby / plains wallaby only; no hunting/eating row.", "Rule 148: kadar retained."),
    ("lexicon", "`julmbanu` remained grey kangaroo only; no boss/metaphor, hunt, spear, or meat row.", "Rule 148: julmbanu retained."),
    ("lexicon", "`kaya` remained dog only; no bite, bark, tail, food, or possession row.", "Rule 148: kaya retained."),
    ("lexicon", "`walkarr` remained black scrub goanna only; no viciousness, teeth, germs, food, or contrast row.", "Rule 148: walkarr retained."),
    ("lexicon", "`jarba` remained generic snake only; no bite, fear, poison, instrument, rainbow-snake, or myth row.", "Rule 148: jarba retained."),
    ("lexicon", "`bajabaja` remained blue-tongue lizard only; no place, story-site, myth, egg, or tongue-display row.", "Rule 148: bajabaja retained."),
    ("morphology", "All land-animal target heads stayed bare; no target dative, locative, ablative, instrumental, comitative, possessive, or compound forms appeared.", "Rule 148: target case restraint."),
    ("morphology", "Support locatives stayed limited to `madja-nga`, `ngalkal-ba`, `bayan-ba`, and `bubu-ngu`.", "Rule 148: support locative limit."),
    ("morphology", "`Bikibiki` and `bajabaja` remained whole lexical heads, not productive reduplication templates.", "Rule 148: whole reduplicated heads."),
    ("morphology", "Common-noun A in perception rows was ERG-marked; pronoun A rows stayed bare.", "Rule 148: A marking."),
    ("syntax", "Locative nominal clauses used bare target plus one approved support locative.", "Rule 148: support-location syntax."),
    ("syntax", "Bare past perception rows used `nyajin` with bare land-animal objects.", "Rule 148: bare past perception syntax."),
    ("syntax", "Support-locative past perception rows used `nyajin` plus one approved support locative.", "Rule 148: located past perception syntax."),
    ("syntax", "Present perception rows used `nyajil` with bare land-animal objects.", "Rule 148: present perception syntax."),
    ("fidelity", "English labels explicitly selected retained animal senses and did not add animal behaviour or cultural inference.", "Rule 148: selected-sense fidelity."),
    ("fidelity", "No hunting, killing, spearing, shooting, chasing, catching, cutting, biting, licking, barking, eating, meat, food, poison, sickness, fear, taboo, storm, story, myth, totem, track, egg, tail, teeth, or behaviour inference was imported.", "Rule 148: no ecology inference."),
    ("register", "Rows remained ordinary descriptions of animals at places or being seen.", "Rule 148: register scope."),
    ("handoff", "Next cadence may return to lexical expansion, but animal ecology should stay closed unless separately sourced.", "Rule 148: next cadence."),
    ("handoff", "Carry forward `biki` exclusion, `bulki` dictionary-gate exclusion, `bajabaja` story-site trap, and `jarba` bite/fear/poison trap.", "Rule 148: carry-forward traps."),
    ("handoff", "If a future batch opens animal actions, source each verb and cultural predicate independently and guard it separately.", "Rule 148: future ecology gate."),
]

LEXEMES = [
    ("bikibiki", "noun", None, "NA", "pig", "batch-190: retained reduplicated pig loan/contact animal; biki excluded."),
    ("biki", "noun", None, "NA", "pig base form", "batch-190: still excluded as a target surface; use source-backed bikibiki only in this construction pass."),
    ("bulki", "noun", None, "NA", "cattle; bullock", "batch-190: still excluded because parsed dictionary lacks exact usable headword entry."),
    ("kadar", "noun", None, "NA", "wallaby; plains wallaby", "batch-190: retained wallaby only; no hunting/eating row."),
    ("julmbanu", "noun", None, "NA", "grey kangaroo", "batch-190: retained grey kangaroo only; no boss/metaphor, hunt, spear, or meat row."),
    ("kaya", "noun", None, "NA", "dog", "batch-190: retained dog only; no bite, bark, tail, food, or possession row."),
    ("walkarr", "noun", None, "NA", "black scrub goanna", "batch-190: retained black scrub goanna only; no viciousness, teeth, germs, food, or contrast row."),
    ("jarba", "noun", None, "NA", "snake", "batch-190: retained generic snake only; no bite/fear/poison/instrument/myth row."),
    ("bajabaja", "noun", None, "NA", "blue-tongue lizard", "batch-190: retained animal sense only; no place/story-site/myth/egg/tongue-display row."),
    ("madja", "noun", None, "NA", "scrub; rainforest", "batch-190: support-only locative madja-nga."),
    ("ngalkal", "noun", None, "NA", "outside; open ground", "batch-190: support-only locative ngalkal-ba."),
    ("bayan", "noun", None, "NA", "camp; house", "batch-190: support-only locative bayan-ba."),
    ("bubu", "noun", None, "NA", "ground; country; place", "batch-190: support-only locative bubu-ngu."),
    ("nyaji-l", "verb", "l", "NA", "see; hear; perceive", "batch-190: past and present perception rows with land-animal objects."),
    ("ngamu", "noun", None, "NA", "mother", "batch-190: common-noun A in perception rows, ERG-marked."),
    ("nganjan", "noun", None, "NA", "father", "batch-190: common-noun A in perception rows, ERG-marked."),
    ("babi", "noun", None, "NA", "grandmother", "batch-190: common-noun A in perception rows, ERG-marked."),
    ("karrkay", "noun", None, "NA", "child", "batch-190: common-noun A in perception rows, ERG-marked."),
    ("kami", "noun", None, "NA", "grandfather", "batch-190: common-noun A in perception rows, ERG-marked."),
    ("jalbu", "noun", None, "NA", "woman", "batch-190: common-noun A in perception rows, ERG-marked."),
    ("dingkar", "noun", None, "NA", "man", "batch-190: common-noun A in perception rows, ERG-marked."),
    ("ngayu", "pronoun", None, "NA", "I; 1sg nominative", "batch-190: bare pronoun A in perception rows."),
    ("ngana", "pronoun", None, "NA", "we; 1pl inclusive", "batch-190: bare pronoun A in perception rows."),
    ("jana", "pronoun", None, "NA", "they; 3pl nominative", "batch-190: 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-190-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 148 rows. Morphology checked bare retained 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 retained senses and excluded "
            "biki/bulki drift. Syntax checked locative nominal, bare past perception, located 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, bird, tree, or 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 148 lessons covering process, lexical senses, morphology, syntax, fidelity, register, and handoff.",
        artifact_path="batch_scripts/close_190.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 148 retained targets, excluded forms, support heads, verb, participants, and pronouns.",
        artifact_path="batch_scripts/close_190.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 190: 50 accepted Rule 148 land-animal construction-consolidation rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_190.py",
        artifact_path="batch_scripts/close_190.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-190:%'").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())
