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

NOTES = (
    "LEXICAL: PHYSICAL PROPERTIES AND MATERIAL QUALITIES (Rule 103). 50 rows. DESIGN: follow the Rule 102 body-part "
    "construction batch with a dictionary-rich property lexicon batch covering size, dimension, water depth, flat/low/"
    "bent, hard/soft/heavy, wet/dry/slippery/smooth/rough, dirty/clean/clear, hot/cold, burnt/ripe/fat, colour, good/"
    "no-good/taste/beauty, skinny/strong, sharp/blunt, new, too-small, and inchoative/causative property changes. "
    "SOURCE CONTROLS: Patz adjective inventory; Patz nominal/adjectival predicates; Patz inchoative -ma-l table; Patz "
    "state-causative -bunga-l/-kanga-l examples 169-170; appendix dajali/yalkan water examples; dictionary entries "
    "for all property lexemes. PROCESS STORAGE: source-pass, risk controls, duplicate corrections, row inventory, lint "
    "outputs, review, close, export, and live-doc verification are stored in process_events and the batch process log. "
    "CORRECTIONS BEFORE CLOSE: initial exact duplicates were corrected before banking; close script records the post-bank "
    "review result and leaves the full source trail in the process log."
)

LESSONS = [
    ("syntax", "Concrete adjective predicates can be short nominal/adjectival clauses: NP plus adjective, as in mayi ngulkurr or kalka dudu.", "cheatsheet Rule 103: adjective predicates."),
    ("lexicon", "`buban` is small amount/short time, not a free generic adjective for every small noun.", "dictionary errata Batch-145: buban scope."),
    ("lexicon", "`dajali` and `yalkan` are deep/shallow water expressions; do not treat them as generic deep/shallow adjectives.", "cheatsheet Rule 103: water-depth nouns."),
    ("lexicon", "Colour remains minimal: `ngumbu`, `bingaji`, and `ngala-ngala`; no green, blue, brown, or purple coinages.", "dictionary errata Batch-145: colour scope."),
    ("lexicon", "`kulngkul` is heavy; `niji` is not heavy.", "dictionary errata Batch-145: heavy guard."),
    ("lexicon", "`kiway`/`kiway-kiway` are cold; `kija` remains moon/month only.", "dictionary errata Batch-145: cold guard."),
    ("lexicon", "`jalngkun` is sharp and `dudu` is blunt; `jinbal` is fast/quick, not a general sharp adjective.", "dictionary errata Batch-145: edge-quality guard."),
    ("lexicon", "`darra` covers narrow and too-small; `darra bajaku` is source-backed for too small.", "cheatsheet Rule 103: darra scope."),
    ("morphology", "Property inchoatives use productive `-ma-l`: dandi-ma-l, kima-ma-l, wumbul-ma-l, kiway-ma-l, marral-ma-l.", "cheatsheet Rule 103: property inchoatives."),
    ("morphology", "Unmarked property causatives use `-bunga-l`, but `mumbu-kanga-l` is required for dirtying water by disturbance.", "cheatsheet Rule 103: property causatives."),
    ("morphology", "`jirra-bunga-l` is the food overcooking/burning causative; `jirra-kanga-l` belongs to fire/temper stirring contexts.", "dictionary errata Batch-145: jirra causative split."),
    ("lexicon", "`nganjay` is no-good/wilted/bad-smell, while `nganja-burra` is bad taste/distasteful; keep smell/value and taste distinct.", "dictionary errata Batch-145: no-good versus bad taste."),
    ("lexicon", "`dayirr` is clean/clear/bright; avoid the conflicting `wungku dayirr` sun shortcut because `wungku` is turkey in the dictionary.", "dictionary errata Batch-145: dayirr source guard."),
    ("process", "Duplicate checks should be run before script writing when common old surfaces like `Kalka kalbay` or `Kulji dandi` are likely.", "operator guide process storage: duplicate preflight."),
]

LEXEMES = [
    ("yalbay", "adjective", None, "NA", "big", "batch-145: physical-property size adjective."),
    ("buban", "noun", None, "neutral", "small amount; short time", "batch-145: small-amount only; not generic small-person adjective."),
    ("kalbay", "adjective", None, "NA", "long", "batch-145: dimension-size adjective."),
    ("yalmbar", "adjective", None, "NA", "wide", "batch-145: dimension-size adjective."),
    ("darra", "adjective", None, "NA", "narrow; too small", "batch-145: narrow/too-small adjective with darra bajaku."),
    ("dubar", "adjective", None, "NA", "level; flat place", "batch-145: flat/level ground-place adjective."),
    ("kambal", "noun", None, "neutral", "low level; within reach", "batch-145: low/within-reach source-bounded noun."),
    ("dajali", "noun", None, "neutral", "deep water", "batch-145: water-depth noun, not generic adjective."),
    ("yalkan", "adjective", None, "NA", "shallow water", "batch-145: shallow-water expression, not generic adjective."),
    ("duku", "noun", None, "neutral", "bent", "batch-145: bent physical-property row; source example muku-duku."),
    ("dandi", "adjective", None, "NA", "hard; tough; strong/healthy", "batch-145: hard property plus dandi-ma-l/dandi-bunga-l."),
    ("kima", "adjective", None, "NA", "soft; weak; sick", "batch-145: soft property plus kima-ma-l/kima-bunga-l."),
    ("kulngkul", "adjective", None, "NA", "heavy; pregnant", "batch-145: heavy guard against niji."),
    ("duna", "noun", None, "neutral", "wet", "batch-145: wet state; synonym yaru not needed."),
    ("marral", "adjective", None, "NA", "dry", "batch-145: dry state and marral-ma-l."),
    ("julbarr", "adjective", None, "NA", "slippery", "batch-145: slippery road/property row."),
    ("dirka-dirka", "adjective", None, "NA", "smooth", "batch-145: smooth stone/surface row."),
    ("murru-murru", "adjective", None, "NA", "lumpy; rough", "batch-145: rough-bark row from Patz dubal murru-murru."),
    ("mumbu", "adjective", None, "NA", "dirty; soiled; muddied", "batch-145: dirty base for mumbu-bunga-l and mumbu-kanga-l."),
    ("dayirr", "adjective", None, "NA", "clean; clear; bright", "batch-145: clear water and clean clothes; wungku-sun shortcut avoided."),
    ("wumbul", "adjective", None, "NA", "hot", "batch-145: hot property and wumbul-ma-l."),
    ("kiway", "noun", None, "neutral", "cold", "batch-145: cold noun/base; kija blocked."),
    ("kiway-kiway", "adjective", None, "NA", "cold", "batch-145: reduplicated cold adjective."),
    ("jirra", "adjective", None, "NA", "burnt; overdone food", "batch-145: burnt food and jirra-bunga-l."),
    ("kulbul", "adjective", None, "NA", "ripe", "batch-145: ripe food/fruit adjective."),
    ("wandul", "adjective", None, "NA", "fat", "batch-145: body/animal fat adjective."),
    ("ngumbu", "adjective", None, "NA", "black; dark; charcoal", "batch-145: dark/black colour term."),
    ("ngala-ngala", "adjective", None, "NA", "red; reddish", "batch-145: Yalanji red colour term."),
    ("bingaji", "adjective", None, "NA", "light coloured; white", "batch-145: light colour term; homonymous with white-haired person."),
    ("ngulkurr", "adjective", None, "NA", "good; well; morally good", "batch-145: good quality predicate."),
    ("nganjay", "adjective", None, "NA", "no good; wilted; bad smell", "batch-145: no-good quality distinct from bad taste."),
    ("nganja-burra", "noun", None, "NA", "bad taste; distasteful", "batch-145: bad-taste noun/quality."),
    ("ngulkurrijin", "adjective", None, "NA", "pretty; beautiful", "batch-145: beautiful flower quality."),
    ("bala", "adjective", None, "NA", "skinny; weak from sickness or lack of food", "batch-145: skinny adjective; homonymous sugar glider fenced by context."),
    ("yaykarr", "adjective", None, "NA", "strong; hard; swift", "batch-145: strong adjective, preferred over noun junkurr for adjective rows."),
    ("jalngkun", "adjective", None, "NA", "sharp", "batch-145: sharp edge adjective; not jinbal."),
    ("dudu", "noun", None, "neutral", "blunt", "batch-145: blunt edge/point property."),
    ("jirakal", "adjective", None, "NA", "new", "batch-145: new age/property adjective."),
    ("dubal", "noun", None, "neutral", "bark; coolamon/coffin context", "batch-145: retained Patz rough-bark spelling dubal murru-murru."),
]


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-145-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 103 rows: morphology, lexicon, syntax, fidelity, and register. "
            "Special attention went to bounded adjective senses, colour minimalism, water-depth nouns, edge-quality "
            "lexemes, inchoative/causative property morphology, and duplicate avoidance."
        ),
        artifact_path="process_logs/batch-145-physical-properties-process.md",
        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 145: 50 accepted physical-property/material-quality lexical rows, five-lens reviews, lessons, lexeme logs, and process evidence stored.",
        command="python3 batch_scripts/close_145.py",
        artifact_path="batch_scripts/close_145.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]
    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-145-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, verified corpus={verified}"
    )
    return 0


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