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

NOTES = (
    "PROPERTY-ADJECTIVE LEXICAL EXPANSION AFTER RULE 194 (Rule 195). 50 rows. TARGETS: yalbay big, karrkay small, "
    "kalbay long, kulka short, kulngkul heavy, wuban strong, yayji thin, wumbul hot, kiway-kiway cold, and marral dry. "
    "SUBJECTS: bayan house/camp, baral road, juku tree/wood, kulji stone, bama person, wungar sun, kaba rain, bana "
    "water, and bubu ground. FRAMES: bare NP+ADJ, bare NP + kari + ADJ, yinya NP+ADJ, yinya NP + kari + ADJ, and "
    "NP + ADJ-kari post-adjective privative/negative predicate. REVIEW: no case, degree, causative, inchoative, plural, "
    "productive reduplication, target compound, child-noun karrkay, pregnant kulngkul, diagnosis/medical/event reading, "
    "material-use, travel-event, ownership/country, or Rule 193-194 state-predicate trap was opened."
)

LESSONS = [
    ("process", "Rule 195 returned to lexical expansion after the Rule 193-194 state-predicate pair.", "Rule 195: cadence reset to lexical expansion."),
    ("process", "The source pass used structured dictionary readback for every selected adjective and noun subject.", "Rule 195: dictionary-backed target and subject inventory."),
    ("process", "Two duplicate candidate surfaces were rejected before banking: bare cold water and demonstrative big house.", "Rule 195: duplicate avoidance."),
    ("process", "Post-adjective `-kari` was opened only because Patz explicitly allows `kari` after adjectives as a privative-like predicator.", "Rule 195: sourced post-adjective negation."),
    ("process", "The post-adjective `-kari` rows did not open general privative possession or absence frames.", "Rule 195: narrow -kari scope."),
    ("lexicon", "`yalbay` was retained as big only; heavy-rain idiom was avoided in authored English.", "Rule 195: yalbay retained."),
    ("lexicon", "`karrkay` was retained as adjective small only; the child-noun homograph stayed closed.", "Rule 195: karrkay adjective only."),
    ("lexicon", "`kalbay` was retained as long only; no route/travel event was imported from the road subject.", "Rule 195: kalbay retained."),
    ("lexicon", "`kulka` was retained as short only; no cutting/breaking event was imported.", "Rule 195: kulka retained."),
    ("lexicon", "`kulngkul` was retained as heavy only; the pregnant reading stayed closed.", "Rule 195: kulngkul retained."),
    ("lexicon", "`wuban` was retained as strong only; hard-material readings were not extended into tool or use claims.", "Rule 195: wuban retained."),
    ("lexicon", "`yayji` was retained as thin only; diagnosis, sickness, and medical causes stayed closed.", "Rule 195: yayji retained."),
    ("lexicon", "`wumbul` was retained as hot only; hot-season and sun-event readings stayed closed.", "Rule 195: wumbul retained."),
    ("lexicon", "`kiway-kiway` was retained as cold only; no sickness, weather-event, or water-use row was opened.", "Rule 195: kiway-kiway retained."),
    ("lexicon", "`marral` was retained as dry only; no country/ownership or land-use claim was imported from `bubu`.", "Rule 195: marral retained."),
    ("morphology", "Rows 1-40 kept target adjectives bare, with no case, degree, causative, inchoative, plural, compound, or reduplication.", "Rule 195: bare target morphology."),
    ("morphology", "Rows 41-50 used only the sourced post-adjective `-kari` form and glossed it as PRIV.", "Rule 195: post-adjective -kari."),
    ("morphology", "Free `kari` in rows 11-20 and 31-40 was glossed as NEG before the adjective.", "Rule 195: pre-adjective kari."),
    ("syntax", "Rows 1-10 used bare noun plus property adjective as a nominal predicate.", "Rule 195: NP+ADJ predicates."),
    ("syntax", "Rows 11-20 used bare noun plus pre-adjective `kari` negation.", "Rule 195: NP kari ADJ predicates."),
    ("syntax", "Rows 21-30 used `yinya` plus noun plus property adjective.", "Rule 195: demonstrative NP+ADJ predicates."),
    ("syntax", "Rows 31-40 used `yinya` plus noun plus pre-adjective `kari` negation.", "Rule 195: demonstrative negated predicates."),
    ("syntax", "Rows 41-50 used bare noun plus post-adjective `-kari` as the negative/property predicate.", "Rule 195: NP ADJ-kari predicates."),
    ("fidelity", "English stayed close to selected dictionary senses and did not paraphrase into causes, uses, events, or diagnoses.", "Rule 195: source-fidelity guard."),
    ("handoff", "Next cadence should run construction consolidation after Rule 195, retaining the property-adjective field unless a debt sweep is chosen.", "Rule 195: next cadence."),
]

LEXEMES = [
    ("yalbay", "adjective", None, "NA", "big", "batch-237: retained as big property adjective only."),
    ("karrkay", "adjective", None, "NA", "small", "batch-237: retained as adjective small only; no child-noun reading."),
    ("kalbay", "adjective", None, "NA", "long", "batch-237: retained as long property adjective only."),
    ("kulka", "adjective", None, "NA", "short", "batch-237: retained as short property adjective only."),
    ("kulngkul", "adjective", None, "NA", "heavy", "batch-237: retained as heavy only; no pregnant reading."),
    ("wuban", "adjective", None, "NA", "strong", "batch-237: retained as strong only."),
    ("yayji", "adjective", None, "NA", "thin", "batch-237: retained as thin only; no diagnosis claim."),
    ("wumbul", "adjective", None, "NA", "hot", "batch-237: retained as hot only."),
    ("kiway-kiway", "adjective", None, "NA", "cold", "batch-237: retained as cold only."),
    ("marral", "adjective", None, "NA", "dry", "batch-237: retained as dry only."),
    ("bayan", "noun", None, "NA", "house; camp; shelter", "batch-237: subject noun for property predicates."),
    ("baral", "noun", None, "NA", "road; path; track; trail", "batch-237: subject noun only; no travel event."),
    ("juku", "noun", None, "NA", "tree; wood", "batch-237: subject noun only; no material-use claim."),
    ("kulji", "noun", None, "NA", "stone; pebbles", "batch-237: subject noun for heavy property predicate."),
    ("bama", "noun", None, "NA", "person; people", "batch-237: subject noun only; no social-event claim."),
    ("wungar", "noun", None, "NA", "sun", "batch-237: subject noun for hot property predicate."),
    ("kaba", "noun", None, "NA", "rain", "batch-237: subject noun for cold property predicate."),
    ("bana", "noun", None, "NA", "water", "batch-237: subject noun for demonstrative cold predicate."),
    ("bubu", "noun", None, "NA", "ground; earth; country", "batch-237: subject noun only; no ownership/country claim."),
    ("yinya", "demonstrative", None, "NA", "that", "batch-237: demonstrative in nominal adjective predicates."),
    ("kari", "particle", None, "NA", "not; NEG", "batch-237: pre-adjective negator."),
    ("-kari", "derivational-suffix", None, "NA", "PRIV; post-adjective negative/property predicate", "batch-237: sourced post-adjective negative predicate; narrow scope only."),
]


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-237-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 by SQL token estimate)",
                 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 195 rows. Morphology checked bare target adjectives in rows 1-40 and only sourced post-adjective -kari in rows 41-50, with no case/degree/causative/inchoative/plural/compound/reduplication. Lexicon checked selected senses and kept homographs, polysemy, events, uses, causes, and diagnoses closed. Syntax checked NP+ADJ, NP kari ADJ, yinya NP+ADJ, yinya NP kari ADJ, and NP ADJ-kari frames. Fidelity checked dictionary-sense English. Register stayed plain descriptive.",
                 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 target locative/dative/ablative/perlative/ergative/instrument/comitative/possessive/excess/degree/causative/inchoative/plural/productive-reduplication/compound form beyond the deliberately sourced post-adjective -kari, no loan token, no child-noun karrkay, no pregnant kulngkul, no material-use, no travel-event, no ownership/country claim, and no Rule 193-194 state-predicate 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 195 lessons covering source checks, lexical scope, duplicate preflight, post-adjective -kari, retained target senses, morphology, syntax, fidelity, register, and handoff.",
                 artifact_path="batch_scripts/close_237.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 195 property adjectives, subject nouns, yinya, kari, and -kari.",
                 artifact_path="batch_scripts/close_237.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 237: 50 accepted Rule 195 property-adjective lexical-expansion rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
                 command="python3 batch_scripts/close_237.py", artifact_path="batch_scripts/close_237.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 LIKE 'batch-237%'").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, {lexeme_logs} lexeme/source-log rows, {process_events} process events, under_review={under_review_remaining}, verified corpus={verified}")
    return 0


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