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

NOTES = (
    "NEGATED LOW-FREQUENCY PROPERTY CONSTRUCTION CONSOLIDATION AFTER RULE 205 (Rule 206). 50 rows. TARGETS retained "
    "from Rule 205: barrangkul flat, jalngka smooth/level, kurru-kurru crooked, darra narrow/too small, yalmbar wide, "
    "kiray quiet/slow, murru round, murru-murru lumpy, muru-muru close together, and manun-manun kind/merciful. "
    "FRAMES: NP kari ADJ, Yinya NP kari ADJ, NP kari ADJ yaluy, NP kari ADJ yinyay, and Yinya NP kari ADJ yinyay. "
    "REVIEW: kari stayed an independent negative particle before the adjective predicator; no privative ADJ-kari was "
    "opened; all target adjectives stayed bare; lexicalized hyphenated targets stayed dictionary headwords only; "
    "support nouns stayed in selected readings; yinya/yaluy/yinyay stayed uninflected support only. No degree/"
    "comparison, target case, target compound, target plural, derivation, productive reduplication, perception verb, "
    "event/action, source/use, food/eating/cooking, repair, travel, ownership, illness/body-state, money/coin, abstract "
    "wrongness, social-event, or homograph-drift row was opened."
)

LESSONS = [
    ("process", "Rule 206 consolidated the Rule 205 adjectives rather than adding new targets.", "Rule 206: construction consolidation."),
    ("source", "Patz supports independent kari before a negated adjective.", "Rule 206: kari source."),
    ("source", "Patz treats post-adjective ADJ-kari as probably privative; this stayed closed.", "Rule 206: privative boundary."),
    ("source", "Rule 204 supplied local precedent for NP kari ADJ property frames.", "Rule 206: local negation precedent."),
    ("lexicon", "Barrangkul remained flat property only.", "Rule 206: barrangkul."),
    ("lexicon", "Jalngka remained smooth/level adjective only; itchy-feeling noun homonym stayed closed.", "Rule 206: jalngka."),
    ("lexicon", "Kurru-kurru remained physical crooked property only; abstract wrongness stayed closed.", "Rule 206: kurru-kurru."),
    ("lexicon", "Darra remained narrow/too-small property only, with no degree bajaku.", "Rule 206: darra."),
    ("lexicon", "Yalmbar remained wide property only.", "Rule 206: yalmbar."),
    ("lexicon", "Kiray remained quiet person property only; motion and secrecy adverb readings stayed closed.", "Rule 206: kiray."),
    ("lexicon", "Murru remained round property only.", "Rule 206: murru."),
    ("lexicon", "Murru-murru remained lexicalized lumpy adjective only.", "Rule 206: murru-murru."),
    ("lexicon", "Muru-muru remained lexicalized close-together adjective only.", "Rule 206: muru-muru."),
    ("lexicon", "Manun-manun remained kind/merciful character property only; no social-event row was opened.", "Rule 206: manun-manun."),
    ("lexicon", "Bubu stayed ground only; country/ownership stayed closed.", "Rule 206: bubu support."),
    ("lexicon", "Juku stayed wood only; use/source/action stayed closed.", "Rule 206: juku support."),
    ("lexicon", "Baral stayed road/path noun only; feel/perception verb stayed closed.", "Rule 206: baral support."),
    ("lexicon", "Kambi stayed clothing only; flying-fox homograph stayed closed.", "Rule 206: kambi support."),
    ("lexicon", "Kulji stayed pebble/stone only; money/coin stayed closed.", "Rule 206: kulji support."),
    ("lexicon", "Bama stayed person/people only; social-event readings stayed closed.", "Rule 206: bama support."),
    ("morphology", "All target adjectives stayed bare: no case, privative, degree, comparison, inchoative, causative, plural, compound, or derivation.", "Rule 206: bare targets."),
    ("morphology", "Independent kari was the only negative form; post-adjective privative ADJ-kari was not used.", "Rule 206: independent kari only."),
    ("morphology", "Lexicalized hyphenated headwords kurru-kurru, murru-murru, muru-muru, and manun-manun were not treated as productive reduplication.", "Rule 206: lexicalized reduplication."),
    ("morphology", "Yinya, yaluy, and yinyay stayed uninflected support heads.", "Rule 206: support morphology."),
    ("syntax", "Rows 1-10 used NP kari ADJ.", "Rule 206: NP negative property frame."),
    ("syntax", "Rows 11-20 used Yinya NP kari ADJ.", "Rule 206: demonstrative negative property frame."),
    ("syntax", "Rows 21-30 used NP kari ADJ yaluy.", "Rule 206: here negative property frame."),
    ("syntax", "Rows 31-40 used NP kari ADJ yinyay.", "Rule 206: there negative property frame."),
    ("syntax", "Rows 41-50 used Yinya NP kari ADJ yinyay.", "Rule 206: demonstrative there-negative frame."),
    ("fidelity", "English stayed literal: subject noun plus 'not' plus selected adjective and optional here/there/that support.", "Rule 206: literal English."),
    ("fidelity", "No English degree, comparison, motion, secrecy, eating, cooking, repair, travel, ownership, source/use, illness, body-state, or perception wording was imported.", "Rule 206: denied English fields."),
    ("register", "Rows remained plain negated property descriptions, not narratives, social events, repairs, travel reports, food events, or perception reports.", "Rule 206: register."),
    ("handoff", "Next batch may return to lexical expansion or run a debt sweep; do not infer privative, degree, event, source/use, homograph, or productive reduplication semantics from Rule 206.", "Rule 206: next cadence."),
]

LEXEMES = [
    ("barrangkul", "adjective", None, "NA", "flat", "batch-248: negated flat property adjective only."),
    ("jalngka", "adjective", None, "NA", "smooth; level", "batch-248: negated smooth/level adjective only; itchy-feeling noun homonym closed."),
    ("kurru-kurru", "adjective", None, "NA", "crooked; wrong", "batch-248: negated physical crooked property only; abstract wrongness closed."),
    ("darra", "adjective", None, "NA", "narrow; too small", "batch-248: negated narrow/too-small property only; no degree bajaku."),
    ("yalmbar", "adjective", None, "NA", "wide", "batch-248: negated wide property only."),
    ("kiray", "adjective", None, "NA", "slow; quiet", "batch-248: negated quiet property only; no motion or secrecy adverb."),
    ("murru", "adjective", None, "NA", "round", "batch-248: negated round property only."),
    ("murru-murru", "adjective", None, "NA", "lumpy", "batch-248: negated lexicalized lumpy adjective only."),
    ("muru-muru", "adjective", None, "NA", "close together", "batch-248: negated lexicalized close-together adjective only."),
    ("manun-manun", "adjective", None, "NA", "kind; merciful", "batch-248: negated character property only; no social-event row."),
    ("kari", "particle", None, "NA", "not; no; but", "batch-248: independent negative particle before adjective predicator only; no privative ADJ-kari."),
    ("bubu", "noun", None, "NA", "ground; earth", "batch-248: support subject as ground only; country/ownership closed."),
    ("juku", "noun", None, "NA", "tree; wood; stick", "batch-248: support subject as wood only; use/source/action closed."),
    ("baral", "noun", None, "NA", "road; path; track", "batch-248: support subject as road/path only; feel/perception verb closed."),
    ("kambi", "noun", None, "NA", "clothing; flying fox", "batch-248: support subject as clothing only; flying-fox homograph closed."),
    ("kulji", "noun", None, "NA", "pebble; small stone", "batch-248: support subject as pebble/stone only; money/coin reading closed."),
    ("bama", "noun", None, "NA", "person; people", "batch-248: support subject as person/people only; no social-event row."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-248: local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-248: local demonstrative support only."),
    ("yinya", "demonstrative", None, "NA", "that; those; there", "batch-248: distal demonstrative support only; no new inflection."),
]


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-248-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 206 rows. Morphology checked independent kari only, no ADJ-kari, target adjectives bare, lexicalized hyphenated targets treated only as dictionary headwords, and yinya/yaluy/yinyay uninflected. Lexicon checked retained Rule 205 adjective senses and support noun readings. Syntax checked five negated property frames. Fidelity checked literal 'not' English. Register stayed plain negated property description.",
        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 privative ADJ-kari, perception verb, baral feel/perception verb, degree/comparison, target case/compound/plural/derivation, productive reduplication, motion/travel, secrecy adverb, food/eating/cooking, repair, ownership, source/use, illness/body-state, money/coin, itchy-feeling homonym, abstract wrongness, social-event, yala/yanyu, or support inflection.",
        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 206 lessons covering source checks, target senses, independent kari, support noun readings, morphology, syntax, fidelity, register, and handoff.",
        artifact_path="batch_scripts/close_248.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 206 targets, independent kari, support nouns, and demonstrative heads.",
        artifact_path="batch_scripts/close_248.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 248: 50 accepted Rule 206 negated low-frequency property construction-consolidation rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_248.py",
        artifact_path="batch_scripts/close_248.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]
    lessons = 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-248-verify'").fetchone()[0]
    process_events = db.execute("SELECT COUNT(*) FROM process_events WHERE batch_label=?", (LABEL,)).fetchone()[0]
    under_after = db.execute("SELECT COUNT(*) FROM sentences WHERE status='under_review'").fetchone()[0]
    verified_after = db.execute("SELECT COUNT(*) FROM sentences WHERE status IN ('accepted','revised')").fetchone()[0]
    print(
        f"closed {LABEL}: 50 accepted rows, {reviews} review passes, {lessons} lessons, "
        f"{lexeme_logs} lexeme/source-log rows, {process_events} process events, "
        f"under_review={under_after}, verified corpus={verified_after}"
    )
    return 0


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