#!/usr/bin/env python3
"""Close Batch 385 after an explicit 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-385"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-385-complementary-sense-qualified-reptile-set-c-singular-third-past-perception-after-rule342-process.md"
LENSES = ("morphology", "lexicon", "syntax", "fidelity", "register")

NOTES = (
    "COMPLEMENTARY SENSE-QUALIFIED REPTILE LEXEME-SET-C SINGULAR/THIRD PAST PERCEPTION AFTER RULE 342 "
    "(Rule 343). 50 accepted distributional complements over kalkamuku, karrkurr, jinkalmu, barka, yalnga, "
    "biwul, yirku-yirku, jadi, walkarr and bajabaja. Fresh source hashes and exact record inventory unchanged; "
    "candidate cells 50/50 empty and opposites exactly Batch 384 seq 1-50. Generic labels preserve duplicate, "
    "flora, kinship, taxonomy/culture, food safety/taboo, myth/place, whole-head, property/habitat, case/source/event "
    "boundaries. Completion changes deictic gap 162->172."
)

LESSONS = [
    ("source", "Rule 343 re-hashed dictionary and Patz before authoring; both remained byte-identical to Rule 342 inputs.", "Rule 343: source hashes."),
    ("source", "Fresh YAML parsing retained exact target record counts 2/1/2/3/1/2/1/1/1/1 and the previously recorded source-line ranges.", "Rule 343: record inventory."),
    ("source", "Rule 343 adds distributional complements only; the ten conservative headword-plus-creature labels remain unchanged.", "Rule 343: no new sense."),
    ("source", "Barka snake remains separate from nut/flora and biwul snake from mother-in-law/avoidance; surface frequency is not sense frequency.", "Rule 343: polysemy preserved."),
    ("source", "Patz target hits delimit case, kinship, myth, bite and kill contexts; none licenses copying a source event into the complement.", "Rule 343: Patz boundaries."),
    ("process", "The full 100-cell singular/third x target x deictic matrix was accounted for: 50 Rule 342 cells plus 50 empty complements.", "Rule 343: complete grid."),
    ("process", "Every selected Rule 343 cell was empty and every opposite mapped exactly to Batch 384 sequence 1-50.", "Rule 343: one-to-one complement proof."),
    ("process", "Completion changes deictic gap 162->172; the apparent 152-gap inverse is inadmissible because it duplicates Batch 384.", "Rule 343: balance subordinate to nonduplication."),
    ("process", "Raw target coverage before banking was 10/15/16/18/18/19/19/23/25/26 in target order.", "Rule 343: target baseline."),
    ("process", "Support before banking was ngayu 1471, yundu 1067, nyulu 742, bula 538, jana 1243, yaluy 4462, yinyay 4624 and nyajin 2200.", "Rule 343: support baseline."),
    ("lexicon", "Kalkamuku remained generic snake; duplicate identity, colour/tree habitat, movement, diet, danger and events stayed closed.", "Rule 343: kalkamuku."),
    ("lexicon", "Karrkurr remained generic frog; colour, habitat, weather/season, sound, food, body, knowledge and events stayed closed.", "Rule 343: karrkurr."),
    ("lexicon", "Jinkalmu remained generic snake; brown-snake/taipan resolution, eyes, boys, eating, fierceness, fighting, biting and killing stayed closed.", "Rule 343: jinkalmu."),
    ("lexicon", "Barka selected snake only; nut/tree/fruit/season, record alignment, colour/water habitat, food and events stayed closed.", "Rule 343: barka."),
    ("lexicon", "Yalnga remained generic turtle; sea habitat, poison/danger, sacs, removal/butchery, food and events stayed closed.", "Rule 343: yalnga."),
    ("lexicon", "Biwul selected snake only; mother-in-law/kinship, avoidance language, colour/size, case, social events and danger stayed closed.", "Rule 343: biwul."),
    ("lexicon", "Yirku-yirku remained the exact whole frog head; free base, productive reduplication, sound imitation, habitat and events stayed closed.", "Rule 343: yirku-yirku."),
    ("lexicon", "Jadi remained generic goanna; sand habitat, age permission, taboo, eating/food, hunting and events stayed closed.", "Rule 343: jadi."),
    ("lexicon", "Walkarr remained bare generic goanna; colour/scrub habitat, ergative case, size, hunting/food and events stayed closed.", "Rule 343: walkarr."),
    ("lexicon", "Bajabaja remained the exact whole lizard head; free base, place/story, property/body, eggs/river, biting/fighting and events stayed closed.", "Rule 343: bajabaja."),
    ("morphology", "All ten targets remained bare absolutive O; no case, derivation, property or event morphology entered.", "Rule 343: bare O."),
    ("morphology", "Yirku-yirku and bajabaja remained exact lexicalized whole heads; no free component or productive pattern entered.", "Rule 343: whole heads."),
    ("morphology", "Ngayu, yundu, nyulu, bula and jana remained bare nominative A with number/person distinctions intact.", "Rule 343: pronoun A."),
    ("morphology", "Yaluy, yinyay and nyajin remained fixed; no dialect, case, nonpast, purposive, reduplicated perception or compound entered.", "Rule 343: support."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yinyay nyajin.", "Rule 343: 1sg there."),
    ("syntax", "Rows 11-20 used Yundu TARGET yaluy nyajin.", "Rule 343: 2sg here."),
    ("syntax", "Rows 21-30 used Nyulu TARGET yinyay nyajin.", "Rule 343: 3sg there."),
    ("syntax", "Rows 31-40 used Bula TARGET yaluy nyajin.", "Rule 343: 3du here."),
    ("syntax", "Rows 41-50 used Jana TARGET yinyay nyajin.", "Rule 343: 3pl there."),
    ("fidelity", "English preserved participant value, generic sense-qualified creature label, location and past seeing only.", "Rule 343: fidelity."),
    ("fidelity", "No alternate record, taxonomy, flora/kinship, culture/food, property/habitat, source context, case or event entered English.", "Rule 343: exclusion fidelity."),
    ("register", "All rows remained neutral elicitation clauses; cultural and food-safety prose stayed exclusion metadata.", "Rule 343: register."),
    ("process", "All 50 sentences were explicit sequence-specific row calls; no runtime generator authored sentence content.", "Rule 343: authorship."),
    ("process", "Rules 149-342 traps remained closed, including every Rule 342 sense boundary and exact-cell nonduplication requirement.", "Rule 343: cumulative traps."),
    ("handoff", "Next batch may continue from 19,347 only after a fresh source/gap audit; Rule 343 licenses no new target sense or event.", "Rule 343: handoff."),
]

LEXEMES = [
    ("kalkamuku", "noun", None, "NA", "snake", "batch-385: complementary generic snake only; Rule 342 duplicate/property/event boundaries preserved."),
    ("karrkurr", "noun", None, "NA", "frog", "batch-385: complementary generic frog only; property/knowledge/event boundaries preserved."),
    ("jinkalmu", "noun", None, "NA", "snake", "batch-385: complementary generic snake only; taxonomy/cultural/bite/kill boundaries preserved."),
    ("barka", "noun", None, "NA", "snake", "batch-385: complementary snake sense only; nut/flora and property/event boundaries preserved."),
    ("yalnga", "noun", None, "NA", "turtle", "batch-385: complementary generic turtle only; food-safety/body/event boundaries preserved."),
    ("biwul", "noun", None, "NA", "snake", "batch-385: complementary snake sense only; kinship/avoidance/case/event boundaries preserved."),
    ("yirku-yirku", "noun", None, "NA", "frog", "batch-385: complementary exact whole frog head; base/process/event boundaries preserved."),
    ("jadi", "noun", None, "NA", "goanna", "batch-385: complementary generic goanna only; taboo/food/hunting/event boundaries preserved."),
    ("walkarr", "noun", None, "NA", "goanna", "batch-385: complementary bare generic goanna; property/case/use/event boundaries preserved."),
    ("bajabaja", "noun", None, "NA", "lizard", "batch-385: complementary exact whole lizard head; myth/place/base/property/event boundaries preserved."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-385: bare nominative A only."),
    ("yundu", "pronoun", None, "NA", "second singular nominative", "batch-385: bare nominative A only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-385: bare nominative A only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-385: bare nominative A only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-385: bare nominative A only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-385: Yalanji local support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-385: Yalanji local support only."),
    ("nyajin", "verb-tr", "l", "NA", "see; see.PST", "batch-385: l-conjugation root nyaji-l with past -ny; running surface."),
]


def main() -> int:
    if len(LESSONS) != 35:
        raise SystemExit(f"lessons {len(LESSONS)}")
    if len(LEXEMES) != 18:
        raise SystemExit(f"lexemes {len(LEXEMES)}")

    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("not 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, under_review, accepted) != (50, 50, 0):
        raise SystemExit(f"precheck {total}/{under_review}/{accepted}")
    if db.execute("SELECT COUNT(*) FROM reviews WHERE sentence_id IN(SELECT id FROM sentences WHERE batch_id=?)", (batch_id,)).fetchone()[0]:
        raise SystemExit("reviews already exist")
    if db.execute("SELECT COUNT(*) FROM lessons WHERE batch_id=?", (batch_id,)).fetchone()[0]:
        raise SystemExit("lessons already exist")
    if db.execute("SELECT COUNT(*) FROM lexeme_log WHERE action='batch-385-verify'").fetchone()[0]:
        raise SystemExit("lexeme logs already exist")

    total_rows = db.execute("SELECT COUNT(*) FROM sentences WHERE status!='rejected'").fetchone()[0]
    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(
        """INSERT INTO reviews(sentence_id,round,lens,verdict,issues,suggested_fix,reviewer,created_at)
           VALUES(?,?,?,?,?,?,?,?)""",
        [(sentence_id, 1, lens, "pass", None, None, "codex-main-five-lens", NOW) for sentence_id 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, conjugation, 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, conjugation, 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-385-verify", note, NOW),
        )

    events = [
        ("lint", "under-review-lint-green", f"Whole-corpus lint scanned {total_rows} rows with zero issues; verified remained {before}."),
        ("review", "five-lens-pass", "All 250 judgments passed; complementary singular/third syntax, exact sense labels, fidelity and neutral register retained."),
        ("review", "review-detail", "Duplicate/taxonomy, barka flora, biwul kinship, jinkalmu culture, food safety/taboo, myth/place, whole-head, property/habitat, source/case/event and support drift remained closed."),
        ("review", "lesson-inventory", f"Inserted {len(LESSONS)} Rule 343 lessons."),
        ("review", "lexeme-source-log", f"Inserted {len(LEXEMES)} Rule 343 lexeme/source logs."),
    ]
    for phase, event_type, detail in events:
        record_event(
            db, batch_label=LABEL, phase=phase, event_type=event_type, actor="codex",
            detail=detail, artifact_path=PROCESS_LOG, created_at=NOW,
        )

    db.execute("UPDATE sentences SET status='accepted',updated_at=? WHERE batch_id=?", (NOW, batch_id))
    db.execute(
        "UPDATE batches SET notes=?,cheatsheet_version=?,guide_version=? WHERE id=?",
        (NOTES, "Rule 343 accepted", "operator-guide-2026-07-10", batch_id),
    )
    after, words_after = db.execute(
        """SELECT COUNT(*),SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1)
           FROM sentences WHERE status IN('accepted','revised')"""
    ).fetchone()
    accepted_count = db.execute("SELECT COUNT(*) FROM sentences WHERE batch_id=? AND status='accepted'", (batch_id,)).fetchone()[0]
    review_count = db.execute("SELECT COUNT(*) FROM reviews WHERE sentence_id IN(SELECT id FROM sentences WHERE batch_id=?)", (batch_id,)).fetchone()[0]
    lesson_count = db.execute("SELECT COUNT(*) FROM lessons WHERE batch_id=?", (batch_id,)).fetchone()[0]
    log_count = db.execute("SELECT COUNT(*) FROM lexeme_log WHERE action='batch-385-verify'").fetchone()[0]
    record_event(
        db, batch_label=LABEL, phase="close", event_type="close-success", actor="codex",
        detail=(
            f"Closed Rule 343: accepted={accepted_count}, reviews={review_count}, lessons={lesson_count}, "
            f"logs={log_count}; verified {before}->{after}; words {words_before}->{words_after}."
        ),
        command="python3 batch_scripts/close_385.py", artifact_path=PROCESS_LOG, created_at=NOW,
    )
    db.commit()
    print(
        f"closed batch-385: accepted={accepted_count} reviews={review_count} lessons={lesson_count} "
        f"logs={log_count} verified {before}->{after} words {words_before}->{words_after}"
    )
    return 0


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