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

NOTES = (
    "NEGATED SURFACE-PROPERTY CONSTRUCTION CONSOLIDATION AFTER RULE 203 (Rule 204). 50 rows. TARGETS retained from "
    "Rule 203: mulun folded/closed, dangal baggy/sloppy, dulngki wide, dungkul huge/enormous, dunju-dunju coarse/"
    "knobbed, jala-jala loose, jalkar-jalkar steep, yuku thick, muja-muja rotten/decayed, and nguyal sticky. 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; no privative -kari was opened; all target adjectives stayed bare; "
    "lexicalized reduplicated targets stayed dictionary headwords only; support nouns stayed in selected readings; "
    "yinya/yaluy/yinyay stayed uninflected support only. No perception verb, degree/comparison, inchoative, causative, "
    "action/event, use/source, illness/body-state, food/eating/cooking, clothing wear/make/folding event, road travel, "
    "house repair, wood cutting/use, proximal yala/yanyu, target case, target compound, target plural, or productive "
    "reduplication row was opened."
)

LESSONS = [
    ("process", "Rule 204 consolidated the Rule 203 adjectives rather than adding new lexical targets.", "Rule 204: construction consolidation."),
    ("process", "The selected construction was independent-particle negation, not privative target morphology.", "Rule 204: kari scope."),
    ("process", "Exact duplicate preflight over all 50 planned negated property surfaces returned no cross-corpus accepted/revised/under_review collisions.", "Rule 204: duplicate preflight."),
    ("source", "Patz 3.1 supports adjectives as property nominals.", "Rule 204: adjective-class source."),
    ("source", "Patz example 2 supports bare NP ADJ predicates.", "Rule 204: property-predicate source."),
    ("source", "Patz example 295 supports Yinya NP ADJ predicates.", "Rule 204: yinya predicate source."),
    ("source", "Patz clause-stress discussion supports independent kari before the predicator in negative statements.", "Rule 204: kari negative source."),
    ("source", "Batch 237 supplied local precedent for NP kari ADJ and Yinya NP kari ADJ property frames.", "Rule 204: local negative-property precedent."),
    ("source", "Batches 238 and 245 supplied local precedent for yaluy/yinyay support in property-predicate rows.", "Rule 204: deictic property precedent."),
    ("lexicon", "Mulun remained folded/closed property only, with no folding/opening/closing event.", "Rule 204: mulun negated property only."),
    ("lexicon", "Dangal remained baggy/sloppy property only, with no clothing wear/make event.", "Rule 204: dangal negated property only."),
    ("lexicon", "Dulngki remained wide property only, with baral as road/path noun and no travel event.", "Rule 204: dulngki negated property only."),
    ("lexicon", "Dungkul remained huge/enormous property only, with bayan as house/camp and no repair or ownership row.", "Rule 204: dungkul negated property only."),
    ("lexicon", "Dunju-dunju remained the dictionary-listed coarse/knobbed adjective only.", "Rule 204: dunju-dunju lexicalized only."),
    ("lexicon", "Jala-jala remained the dictionary-listed loose adjective only.", "Rule 204: jala-jala lexicalized only."),
    ("lexicon", "Jalkar-jalkar remained the dictionary-listed steep adjective only, with no route/travel event.", "Rule 204: jalkar-jalkar lexicalized only."),
    ("lexicon", "Yuku remained thick property only, not a generic new big-field expansion.", "Rule 204: yuku thick only."),
    ("lexicon", "Muja-muja remained rotten/decayed property only, with no cutting/use/source row.", "Rule 204: muja-muja negated property only."),
    ("lexicon", "Nguyal remained sticky property only, with no honey/eating/cooking/gathering row.", "Rule 204: nguyal negated property only."),
    ("lexicon", "Support noun kambi stayed clothing only; flying-fox homograph stayed closed.", "Rule 204: kambi support reading."),
    ("lexicon", "Support noun baral stayed road/path only; feel/perception verb homograph stayed closed.", "Rule 204: baral support reading."),
    ("lexicon", "Support nouns bayan, juku, and mayi stayed subject nouns only; repair, cutting/use/source, eating, cooking, and gathering readings stayed closed.", "Rule 204: support noun restraint."),
    ("morphology", "All target adjectives stayed bare: no target case, privative, degree, comparison, inchoative, causative, plural, compound, or productive reduplication.", "Rule 204: bare target morphology."),
    ("morphology", "Independent kari was the only negative form; privative -kari was not used.", "Rule 204: independent kari only."),
    ("morphology", "Lexicalized hyphenated dictionary headwords dunju-dunju, jala-jala, jalkar-jalkar, and muja-muja were not treated as productive morphology.", "Rule 204: lexicalized reduplication."),
    ("morphology", "Yinya, yaluy, and yinyay stayed uninflected support heads.", "Rule 204: support morphology restraint."),
    ("syntax", "Rows 1-10 used NP kari ADJ.", "Rule 204: NP negative property frame."),
    ("syntax", "Rows 11-20 used Yinya NP kari ADJ.", "Rule 204: demonstrative negative property frame."),
    ("syntax", "Rows 21-30 used NP kari ADJ yaluy.", "Rule 204: here negative property frame."),
    ("syntax", "Rows 31-40 used NP kari ADJ yinyay.", "Rule 204: there negative property frame."),
    ("syntax", "Rows 41-50 used Yinya NP kari ADJ yinyay.", "Rule 204: demonstrative there-negative frame."),
    ("fidelity", "English stayed literal: subject noun plus 'not' plus selected adjective and optional here/there/that support.", "Rule 204: literal negated English."),
    ("fidelity", "No English action, cause, repair, wearing, making, folding event, travel, cooking, eating, illness, body-state, source, comparison, degree, or perception wording was imported.", "Rule 204: denied English fields."),
    ("register", "Rows remained plain negated property descriptions, not narratives, repairs, travel reports, food events, clothing events, or perception reports.", "Rule 204: negated property register."),
    ("handoff", "Next batch may return to lexical expansion or consolidate these adjectives in another sourced construction; do not infer -kari, degree, perception, event, or source semantics from Rule 204.", "Rule 204: next cadence."),
]

LEXEMES = [
    ("mulun", "adjective", None, "NA", "folded; closed", "batch-246: negated property adjective only; no folding/opening/closing event."),
    ("dangal", "adjective", None, "NA", "baggy; sloppy", "batch-246: negated property adjective only; no clothing wear/make event."),
    ("dulngki", "adjective", None, "NA", "wide", "batch-246: negated property adjective only; no road/travel event."),
    ("dungkul", "adjective", None, "NA", "huge; enormous", "batch-246: negated property adjective only; no house repair/ownership row."),
    ("dunju-dunju", "adjective", None, "NA", "coarse; knobbed; spiky", "batch-246: lexicalized dictionary adjective only; no productive reduplication."),
    ("jala-jala", "adjective", None, "NA", "loose; loosely put together", "batch-246: lexicalized dictionary adjective only; no productive reduplication or clothing event."),
    ("jalkar-jalkar", "adjective", None, "NA", "steep", "batch-246: lexicalized dictionary adjective only; no road/travel event."),
    ("yuku", "adjective", None, "NA", "big; thick", "batch-246: negated property adjective selected as thick only; no generic big-field expansion."),
    ("muja-muja", "adjective", None, "NA", "rotten; decayed; easily broken", "batch-246: lexicalized dictionary adjective only; no wood cutting/use/source row."),
    ("nguyal", "adjective", None, "NA", "sticky", "batch-246: negated property adjective only; no honey/eating/cooking row."),
    ("kari", "particle", None, "NA", "not; no; but", "batch-246: independent negative particle before adjective predicator only; no privative -kari."),
    ("kambi", "noun", None, "NA", "clothing; flying fox", "batch-246: support subject noun as clothing only; flying-fox homograph closed."),
    ("baral", "noun", None, "NA", "road; path; track", "batch-246: support subject noun as road/path only; feel/perception verb homograph closed."),
    ("bayan", "noun", None, "NA", "house; camp; shelter", "batch-246: support subject noun only; no repair or ownership row."),
    ("juku", "noun", None, "NA", "tree; wood; stick", "batch-246: support subject noun as wood only; no cutting/use/source row."),
    ("mayi", "noun", None, "NA", "food; plant food; fruit", "batch-246: support subject noun as food only; no eating/cooking/gathering row."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-246: local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-246: local demonstrative support only."),
    ("yinya", "demonstrative", None, "NA", "that; those; there", "batch-246: 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-246-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 204 rows. Morphology checked independent kari only, no -kari, target adjectives bare, lexicalized hyphenated targets treated only as dictionary headwords, and yinya/yaluy/yinyay uninflected. Lexicon checked retained Rule 203 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 -kari, perception verb, nyaji-l, baral feel/perception verb, degree/comparison, inchoative, causative, action/event, use/source claim, illness/body-state reading, food/eating/cooking row, clothing wear/make/folding event, road travel row, house repair row, wood cutting/use row, proximal yala/yanyu, target case, target compound, target plural, or productive reduplication row.",
        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 204 lessons covering source checks, target senses, independent kari, support noun readings, morphology, syntax, fidelity, register, and handoff.",
        artifact_path="batch_scripts/close_246.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 204 target adjectives, independent kari, support nouns, and demonstrative heads.",
        artifact_path="batch_scripts/close_246.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 246: 50 accepted Rule 204 negated surface-property construction-consolidation rows, five-lens reviews, lessons, lexeme/source logs, and process evidence stored.",
        command="python3 batch_scripts/close_246.py",
        artifact_path="batch_scripts/close_246.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-246%'").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())
