#!/usr/bin/env python3
"""Close Batch 388 after 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-388"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-388-underrepresented-bird-set-d-singular-third-past-perception-after-rule345-process.md"
LENSES = ("morphology", "lexicon", "syntax", "fidelity", "register")

NOTES = (
    "UNDERREPRESENTED BIRD LEXEME-SET-D SINGULAR/THIRD PAST PERCEPTION AFTER RULE 345 (Rule 346). "
    "50 accepted rows over diwalngku, bujil-yiran, karrmbil, yiki, bajal, biru-biru, jangkan, kurranday, "
    "ngarkay and wakuka. Fresh two-record inventories and Patz exact-hit profile passed. Generic labels preserve "
    "unknown/conflicting taxonomy, empty cognition card, whole reduplication, cultural belief, property/habitat, "
    "source and event boundaries. All 100 cells empty; selected three-here/two-there changed gap 172->162."
)

LESSONS = [
    ("source", "Rule 346 re-hashed dictionary and Patz; both remained byte-identical to prior inputs.", "Rule 346: source hashes."),
    ("source", "Fresh YAML parsing returned exactly two records for each of the ten selected bird heads.", "Rule 346: record inventory."),
    ("source", "Exact Patz target scan found only wakuka: bird contexts at 713/4026 and Wakuka/Wakooka Station proper-name context at 6903; the three-hit profile was asserted before banking.", "Rule 346: Patz target hits."),
    ("source", "Zero Patz hits for nine targets were recorded as source coverage facts, not negative lexical claims; dictionary cards license those heads.", "Rule 346: absence discipline."),
    ("source", "Generic headword-plus-bird labels minimize taxonomic/property commitments while selecting the intended fauna cards.", "Rule 346: label policy."),
    ("process", "All 100 singular/third-pronoun x target x deictic past-perception cells were absent; both orientations unique.", "Rule 346: complete grid."),
    ("process", "Three-here/two-there changes deictic gap 172->162; inverse would yield 182.", "Rule 346: balance."),
    ("process", "Raw target coverage before banking was 5/5/5/5/6/6/6/6/6/7 in planned order.", "Rule 346: target baseline."),
    ("process", "Support before banking was ngayu 1481, yundu 1077, nyulu 752, bula 548, jana 1253, yaluy 4532, yinyay 4704 and nyajin 2350.", "Rule 346: support baseline."),
    ("lexicon", "Diwalngku remained generic bird; unknown English species, migration, season/route, habitat and events stayed closed.", "Rule 346: diwalngku."),
    ("lexicon", "Bujil-yiran selected ibis; empty cognition card, proposed fear-base decomposition, free components, fear meaning and events stayed closed.", "Rule 346: bujil-yiran."),
    ("lexicon", "Karrmbil remained generic parakeet; blue-mountain/rainbow-lorikeet alignment, colour/habitat and events stayed closed.", "Rule 346: karrmbil."),
    ("lexicon", "Yiki remained generic owl; owl/night-owl resolution, nocturnal behavior, sound, hunting and events stayed closed.", "Rule 346: yiki."),
    ("lexicon", "Bajal remained generic bower bird; duplicate collapse, habitat, building, collecting, stealing, objects and events stayed closed.", "Rule 346: bajal."),
    ("lexicon", "Biru-biru remained exact whole rainbow-bird head; bee-eater resolution, free base, productive reduplication, nesting, honey signs and events stayed closed.", "Rule 346: biru-biru."),
    ("lexicon", "Jangkan remained the swift bird noun; duplicate collapse, speed/property, flight, season and events stayed closed.", "Rule 346: jangkan."),
    ("lexicon", "Kurranday remained generic seagull; duplicate collapse, sea/shore habitat, warning, sound, feeding, flight and events stayed closed.", "Rule 346: kurranday."),
    ("lexicon", "Ngarkay remained generic waterhen; duplicate collapse, swamp/water habitat, walking, feeding, hunting and events stayed closed.", "Rule 346: ngarkay."),
    ("lexicon", "Wakuka remained generic bird; crow/kookaburra resolution, messenger/death belief, Wakuka/Wakooka Station place-name transfer, sound, source event and possession stayed closed.", "Rule 346: wakuka."),
    ("morphology", "All targets remained bare absolutive O; no case, derivation, property or event morphology entered.", "Rule 346: bare O."),
    ("morphology", "Bujil-yiran and biru-biru remained exact whole heads; no free component or productive process entered.", "Rule 346: whole heads."),
    ("morphology", "Ngayu, yundu, nyulu, bula and jana remained bare nominative A.", "Rule 346: pronoun A."),
    ("morphology", "Yaluy, yinyay and nyajin remained fixed; no dialect, case, nonpast, purposive or perception compound entered.", "Rule 346: support."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yaluy nyajin.", "Rule 346: 1sg here."),
    ("syntax", "Rows 11-20 used Yundu TARGET yinyay nyajin.", "Rule 346: 2sg there."),
    ("syntax", "Rows 21-30 used Nyulu TARGET yaluy nyajin.", "Rule 346: 3sg here."),
    ("syntax", "Rows 31-40 used Bula TARGET yinyay nyajin.", "Rule 346: 3du there."),
    ("syntax", "Rows 41-50 used Jana TARGET yaluy nyajin.", "Rule 346: 3pl here."),
    ("fidelity", "English preserved participant, conservative bird label, location and past seeing only.", "Rule 346: fidelity."),
    ("fidelity", "No alternate card, taxonomy, composition, property, behavior, culture, habitat, source context or event entered English.", "Rule 346: exclusion fidelity."),
    ("register", "Rows remained neutral elicitation clauses; cultural beliefs and prior ecological narratives stayed metadata.", "Rule 346: register."),
    ("process", "All 50 sentences were explicit row calls; no runtime generator authored content.", "Rule 346: authorship."),
    ("process", "Rules 149-345 traps stayed closed, including the completed set-C grid and all new bird-card boundaries.", "Rule 346: cumulative traps."),
    ("process", "Source cards, Patz hit profile, planned rows, scripts, readback, review, export and publication are retained in the mounted-drive log and process_events.", "Rule 346: process storage."),
    ("handoff", "Next batch may continue from 19,497 only after a fresh source/gap audit; Rule 346 licenses no bird property or event.", "Rule 346: handoff."),
]

LEXEMES = [
    ("diwalngku", "noun", None, "NA", "bird", "batch-388: generic bird only; unknown taxonomy/migration/property/event boundaries recorded."),
    ("bujil-yiran", "noun", None, "NA", "ibis", "batch-388: ibis card only; empty cognition card/free-component/fear/event boundaries recorded."),
    ("karrmbil", "noun", None, "NA", "parakeet", "batch-388: generic parakeet only; taxonomic/property/habitat/event boundaries recorded."),
    ("yiki", "noun", None, "NA", "owl", "batch-388: generic owl only; night/species/behavior/event boundaries recorded."),
    ("bajal", "noun", None, "NA", "bower bird", "batch-388: generic bower bird only; duplicate/habitat/build/collect/steal/event boundaries recorded."),
    ("biru-biru", "noun", None, "NA", "rainbow bird", "batch-388: exact whole head; taxonomy/base/reduplication/ecology/event boundaries recorded."),
    ("jangkan", "noun", None, "NA", "swift bird", "batch-388: bird noun only; speed/flight/season/event boundaries recorded."),
    ("kurranday", "noun", None, "NA", "seagull", "batch-388: generic seagull only; duplicate/habitat/warning/feeding/event boundaries recorded."),
    ("ngarkay", "noun", None, "NA", "waterhen", "batch-388: generic waterhen only; duplicate/habitat/motion/feeding/event boundaries recorded."),
    ("wakuka", "noun", None, "NA", "bird", "batch-388: generic bird only; crow/kookaburra/messenger/death/place-name/source-event boundaries recorded."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-388: bare A only."),
    ("yundu", "pronoun", None, "NA", "second singular nominative", "batch-388: bare A only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-388: bare A only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-388: bare A only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-388: bare A only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-388: Yalanji local support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-388: Yalanji local support only."),
    ("nyajin", "verb-tr", "l", "NA", "see; see.PST", "batch-388: 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]
    counts = 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 counts != (50, 50, 0):
        raise SystemExit(f"precheck {counts}")
    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-388-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-388-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; singular/third morphology, conservative bird labels, syntax, fidelity and register retained."),
        ("review", "review-detail", "Unknown/conflicting taxonomy, empty cognition card, whole-head, cultural belief, property/habitat/behavior/source/case/event and support drift remained closed."),
        ("review", "lesson-inventory", f"Inserted {len(LESSONS)} Rule 346 lessons."),
        ("review", "lexeme-source-log", f"Inserted {len(LEXEMES)} Rule 346 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 346 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-388-verify'").fetchone()[0]
    record_event(
        db, batch_label=LABEL, phase="close", event_type="close-success", actor="codex",
        detail=f"Closed Rule 346: accepted={accepted_count}, reviews={review_count}, lessons={lesson_count}, logs={log_count}; verified {before}->{after}; words {words_before}->{words_after}.",
        command="python3 batch_scripts/close_388.py", artifact_path=PROCESS_LOG, created_at=NOW,
    )
    db.commit()
    print(f"closed batch-388: accepted={accepted_count} reviews={review_count} lessons={lesson_count} logs={log_count} verified {before}->{after} words {words_before}->{words_after}")
    return 0


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