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

from __future__ import annotations

import datetime as dt
import json
import sqlite3
import sys

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-131"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
LENSES = ("morphology", "lexicon", "syntax", "fidelity", "register")

NOTES = (
    "LEXICAL: WEATHER, SKY, AND TIME OF DAY (Patz §3.2.1 noun classes for natural forces, "
    "§3.4 time words, §4.1.2 inanimate S, §4.2 causatives, §4.3.2 coordinate kari clauses, "
    "§4.4.2 successive clauses, §4.4.3 precautionary clauses, §4.5.2 inalienable possession, "
    "text 3 rain journey; dictionary sky-weather entries). 50 rows. DESIGN: controlled lexical "
    "batch after Rule 88 construction, using exact Patz lines where possible and short source-safe "
    "weather predicates elsewhere. CORE WEATHER: `kaba` rain, `ngurrban` cloud, `ngurrbal`/`wurrbal` "
    "fog/mist, `muyar` wind, `jarramali` thunder/thunderstorm, `jabulbina` thunder from the west/start "
    "of storms, `balbay` lightning, `wadjal` cyclone, `yiril` rainbow. SKY/TIME: `jiri` sky, `dawar` "
    "star, `wungar` sun/day, `wungar dakal` sunrise, `wungar daray` sunset, `wungar jalamal` sun "
    "peeking from cloud, `wungar wandil-wandil` sun coming up, `wungar wangkar-wangkar` midday, "
    "`muduwaju` daybreak, `wunkuwingku` morning, `yilay-yilay` late afternoon, `wujurr` night/darkness. "
    "STATE TERMS: `kiway` cold, `wumbul` hot, `duna` wet, `marral` dry, `julbarr` slippery, `ngumbu` "
    "dark, `dayirr` bright. SOURCE TENSIONS: rejected the dictionary's unglossed `bunjurril` wind-blow "
    "example; rejected `balbay-nja` because the lint denylist records that segmented form as unsafe. "
    "PROCESS RECORD: external process log created; cross-corpus duplicate check run before banking; "
    "full corpus lint passed before close with 6647 rows scanned and 0 issues."
)

LESSONS = [
    ("lexicon", "`kaba` is rain and can be the inanimate S of `kada-y`: Patz's conversation opener is `Kaba kaday`.", "cheatsheet Rule 89: rain/weather S frame."),
    ("lexicon", "`jarramali` covers thunder/thunderstorm/thunderheads; `jabulbina` is thunder from the west/start of storms; `balbay` is lightning; `wadjal` is cyclone.", "cheatsheet Rule 89: storm inventory."),
    ("process", "Do not use `bunjurril` as a wind verb even though one dictionary usage string has it; the headword is unglossed and the grammar root points to curse/spit/throw, not ordinary blowing.", "errata Batch-131: bunjurril rejected pending source repair."),
    ("process", "Do not bank `balbay-nja` in new rows; it is in the mechanical denylist. Use bare `balbay` lightning or an explicitly safe Patz/dictionary frame.", "errata Batch-131: balbay-nja blocked."),
    ("morphology", "Time words form phrases directly: `muduwajuny`, `wunkuwingku`, `yilay-yilay`, and `wujurr-bu` set temporal frame without extra English prepositions.", "cheatsheet Rule 89: weather plus time words."),
    ("morphology", "`wungar-iji` and `bulur-iji` are comitative season terms: sun-COMIT hot season and chill/dew-COMIT cold season.", "cheatsheet Rule 89: season terms."),
    ("syntax", "Natural forces can be inanimate S or potent A: `Kaba kaday`, but `Muyar-abu nganya yararri-manil` and `Jarramali-ngka bulki dalbarrin` when wind/storm acts on an object.", "cheatsheet Rule 89: natural force case behavior."),
    ("syntax", "Weather is a good source for dependent clauses: `kada-nyjiku` successive, `kada-nyji` precautionary, and `kari` hindrance clauses all have exact weather examples.", "cheatsheet Rule 89: weather dependent-clause examples."),
    ("semantics", "`wujurr` is night/darkness; use `ngumbu` for dark as a property. Do not collapse night, black, darkness, and fear into one English 'dark' token.", "errata Batch-131: wujurr/ngumbu distinction."),
    ("semantics", "`ngurrban` cloud, `ngurrbal` fog, and `wurrbal` river mist/fog are distinct enough to log separately.", "cheatsheet Rule 89: cloud/fog distinction."),
    ("process", "Batch 131 keeps weather rows short because the target is lexical anchoring, not new narrative complexity; longer weather narratives can reuse these verified forms later.", "operator guide: controlled lexical batches can prioritize evidence density."),
    ("process", "Live books must be rendered and verified after each accepted batch; Batch 131 continues the process-log audit trail started in Batch 130.", "operator guide: live books and process log requirement."),
]

LEXEMES = [
    ("kaba", "noun", None, "neutral", "rain", "batch-131: rain weather S, rain-locative and no-rain frames"),
    ("ngurrban", "noun", None, "neutral", "cloud", "batch-131: cloud; not fog"),
    ("ngurrbal", "noun", None, "neutral", "fog", "batch-131: heavy fog"),
    ("wurrbal", "noun", None, "neutral", "fog; river mist", "batch-131: river fog/mist"),
    ("muyar", "noun", None, "potent/natural-force", "wind; air", "batch-131: wind as S and potent A"),
    ("jarramali", "noun", None, "potent/natural-force", "thunder; thunderstorm; thunderheads", "batch-131: thunderstorm and storm-strike frames"),
    ("jabulbina", "noun", None, "neutral", "thunder from the west; start of storms", "batch-131: thunder-west lexical contrast"),
    ("balbay", "noun", None, "neutral", "lightning", "batch-131: safe bare lightning form; avoid balbay-nja"),
    ("wadjal", "noun", None, "neutral", "cyclone", "batch-131: cyclone"),
    ("yiril", "noun", None, "neutral", "rainbow", "batch-131: rainbow"),
    ("jiri", "noun", None, "neutral", "sky; heaven", "batch-131: sky locative"),
    ("dawar", "noun", None, "neutral", "star", "batch-131: stars at night / in sky"),
    ("wungar", "noun", None, "neutral/potent natural force", "sun; day", "batch-131: sun/day weather-time base"),
    ("wungar dakal", "verb-itr", "l", "NA", "sunrise", "batch-131: sun climb compound"),
    ("wungar daray", "verb-itr", "y", "NA", "sunset", "batch-131: sun fall compound"),
    ("wungar jalamal", "verb-itr", "l", "NA", "sun comes out from behind cloud", "batch-131: sun-peek compound"),
    ("wungar wandil-wandil", "verb-itr", "l", "NA", "sun is coming up", "batch-131: sunrise reduplicated compound"),
    ("wungar wangkar-wangkar", "temporal/adjective", None, "NA", "midday", "batch-131: sun-above reduplicated midday term"),
    ("wungar-iji", "temporal", None, "NA", "hot season", "batch-131: sun-COMIT season term"),
    ("bulur-iji", "temporal", None, "NA", "cold season", "batch-131: chill/dew-COMIT season term"),
    ("muduwaju", "temporal", None, "NA", "dawn; daybreak", "batch-131: temporal setting muduwajuny"),
    ("wunkuwingku", "temporal", None, "NA", "morning", "batch-131: morning setting"),
    ("yilay-yilay", "temporal", None, "NA", "late afternoon", "batch-131: late-afternoon setting"),
    ("wujurr", "noun", None, "neutral", "darkness; night", "batch-131: wujurr-bu locative night frame"),
    ("kiway", "noun/adjective", None, "neutral", "cold", "batch-131: cold as weather condition"),
    ("wumbul", "adjective", None, "neutral", "hot", "batch-131: hot day/season"),
    ("duna", "adjective", None, "neutral", "wet", "batch-131: wet hair/wood"),
    ("marral", "adjective", None, "neutral", "dry", "batch-131: dry ground/wood"),
    ("julbarr", "adjective", None, "neutral", "slippery", "batch-131: slippery ground after rain"),
    ("ngumbu", "adjective", None, "neutral", "dark", "batch-131: night-dark property"),
    ("dayirr", "adjective", None, "neutral", "bright; clear; clean", "batch-131: bright sun"),
    ("bunjurril", "watchlist", None, "NA", "unresolved dictionary usage, not accepted as wind-blow verb", "batch-131: explicitly rejected pending source repair"),
]


def main() -> int:
    db = sqlite3.connect(DB)
    db.execute("PRAGMA foreign_keys = ON")
    db.execute("BEGIN")
    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)
        status = "watchlist" if pos == "watchlist" else "verified"
        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=CASE
                WHEN lexemes.status IN ('phantom-retired', 'watchlist') THEN lexemes.status
                ELSE excluded.status
              END,
              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, status, NOW,
                note, "batch-131",
            ),
        )
        db.execute(
            "INSERT INTO lexeme_log(headword, action, detail, created_at) VALUES(?,?,?,?)",
            (headword, "batch-131-verify", note, 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))
    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]
    print(f"closed {LABEL}: 50 accepted rows, {reviews} review passes, verified corpus={verified}")
    return 0


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