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

NOTES = (
    "SENSE-QUALIFIED REPTILE LEXEME-SET-C NON-SINGULAR PAST PERCEPTION AFTER RULE 343 (Rule 344). "
    "50 accepted rows over the ten Rule 342-343 heads with ngali 1du.excl, ngaliny 1du.incl, yubal 2du, "
    "yurra 2pl and nganjin 1pl.excl. All 100 cells were empty; selected three-here/two-there changed gap "
    "172->162. Patz Table 3.6 overrides the dictionary's ngali inclusive misgloss and exact-ngaliny omission; "
    "deferred ngana remains grammatical. All target record, sense, culture, property, source and event boundaries closed."
)

LESSONS = [
    ("source", "Rule 344 re-hashed dictionary and Patz before authoring; both remained byte-identical to Rules 342-343 inputs.", "Rule 344: source hashes."),
    ("source", "Fresh YAML parsing retained exact target record counts 2/1/2/3/1/2/1/1/1/1 and source ranges.", "Rule 344: target records."),
    ("source", "Support dictionary inventory was ngali 1, ngaliny 0, yubal 1, yurra 1, nganjin 1, ngana 1.", "Rule 344: support-card inventory."),
    ("source", "Patz Table 3.6 overrides the generated dictionary conflict: ngali is 1du exclusive and ngaliny 1du inclusive; dictionary misgloss/omission recorded.", "Rule 344: clusivity ruling."),
    ("source", "Ngana remains grammatical 1pl inclusive but was deferred at 1,115 uses; deferral is not unavailability or a lexical ban.", "Rule 344: ngana restraint."),
    ("source", "The ten generic creature labels remain unchanged; non-singular expansion supplies no new zoological sense.", "Rule 344: no new target sense."),
    ("source", "Patz target hits attest forms or delimit case, kinship, myth, bite and kill contexts; none licenses copying source events.", "Rule 344: Patz target boundaries."),
    ("process", "All 100 non-singular-pronoun x target x deictic past-perception cells were absent; both orientations unique and collision-free.", "Rule 344: complete grid."),
    ("process", "Three-here/two-there changes deictic gap 172->162; inverse would yield 182.", "Rule 344: balance."),
    ("process", "Raw target coverage before banking was 15/20/21/23/23/24/24/28/30/31 in target order.", "Rule 344: target baseline."),
    ("process", "Support before banking was ngali 653, ngaliny 595, yubal 605, yurra 590, nganjin 318, ngana 1115, yaluy 4482, yinyay 4654 and nyajin 2250.", "Rule 344: support baseline."),
    ("lexicon", "Kalkamuku remained generic snake; duplicate identity, colour/tree habitat, movement, diet, danger and events stayed closed.", "Rule 344: kalkamuku."),
    ("lexicon", "Karrkurr remained generic frog; colour, habitat, weather/season, sound, food, body, knowledge and events stayed closed.", "Rule 344: karrkurr."),
    ("lexicon", "Jinkalmu remained generic snake; taxonomy, eyes, boys, eating, fierceness, fighting, biting and killing stayed closed.", "Rule 344: jinkalmu."),
    ("lexicon", "Barka selected snake only; nut/tree/fruit/season, record alignment, property/habitat, food and events stayed closed.", "Rule 344: barka."),
    ("lexicon", "Yalnga remained generic turtle; sea habitat, poison/danger, sacs, removal/butchery, food and events stayed closed.", "Rule 344: yalnga."),
    ("lexicon", "Biwul selected snake only; kinship, avoidance language, colour/size, case, social events and danger stayed closed.", "Rule 344: biwul."),
    ("lexicon", "Yirku-yirku remained the exact whole frog head; free base, productive reduplication, sound, habitat and events stayed closed.", "Rule 344: yirku-yirku."),
    ("lexicon", "Jadi remained generic goanna; habitat, age permission, taboo, eating/food, hunting and events stayed closed.", "Rule 344: jadi."),
    ("lexicon", "Walkarr remained bare generic goanna; property/habitat, case, size, hunting/food and events stayed closed.", "Rule 344: walkarr."),
    ("lexicon", "Bajabaja remained the exact whole lizard head; free base, place/story, property/body, eggs/river, fighting and events stayed closed.", "Rule 344: bajabaja."),
    ("morphology", "All targets remained bare absolutive O; no case, derivation, property or event morphology entered.", "Rule 344: bare O."),
    ("morphology", "Yirku-yirku and bajabaja remained exact lexicalized whole heads; no free component or productive pattern entered.", "Rule 344: whole heads."),
    ("morphology", "Ngali, ngaliny, yubal, yurra and nganjin remained bare nominative A with number and clusivity explicit.", "Rule 344: pronoun A."),
    ("morphology", "Yaluy, yinyay and nyajin remained fixed; no dialect, case, nonpast, purposive, reduplicated perception or compound entered.", "Rule 344: support."),
    ("syntax", "Rows 1-10 used Ngali TARGET yaluy nyajin and explicit 1du exclusive English.", "Rule 344: 1du exclusive here."),
    ("syntax", "Rows 11-20 used Ngaliny TARGET yinyay nyajin and explicit 1du inclusive English.", "Rule 344: 1du inclusive there."),
    ("syntax", "Rows 21-30 used Yubal TARGET yaluy nyajin and explicit second-dual English.", "Rule 344: 2du here."),
    ("syntax", "Rows 31-40 used Yurra TARGET yinyay nyajin and explicit second-plural English.", "Rule 344: 2pl there."),
    ("syntax", "Rows 41-50 used Nganjin TARGET yaluy nyajin and explicit 1pl exclusive English.", "Rule 344: 1pl exclusive here."),
    ("fidelity", "English preserved participant number/clusivity, generic creature label, location and past seeing only.", "Rule 344: fidelity."),
    ("fidelity", "No alternate record, taxonomy, flora/kinship, culture/food, property/habitat, source context, case or event entered English.", "Rule 344: exclusion fidelity."),
    ("register", "All rows remained neutral elicitation clauses; dictionary defects and cultural prose stayed metadata.", "Rule 344: register."),
    ("process", "All 50 sentences were explicit row calls; no runtime generator authored content, and Rules 149-343 traps remained closed.", "Rule 344: authorship and cumulative traps."),
    ("handoff", "Next batch may continue from 19,397 only after a fresh source/gap audit; likely complements must be proved, not assumed.", "Rule 344: handoff."),
]

LEXEMES = [
    ("kalkamuku", "noun", None, "NA", "snake", "batch-386: non-singular generic snake only; duplicate/property/event boundaries preserved."),
    ("karrkurr", "noun", None, "NA", "frog", "batch-386: non-singular generic frog only; property/knowledge/event boundaries preserved."),
    ("jinkalmu", "noun", None, "NA", "snake", "batch-386: non-singular generic snake only; taxonomy/cultural/bite/kill boundaries preserved."),
    ("barka", "noun", None, "NA", "snake", "batch-386: non-singular snake sense only; nut/flora and property/event boundaries preserved."),
    ("yalnga", "noun", None, "NA", "turtle", "batch-386: non-singular generic turtle only; food-safety/body/event boundaries preserved."),
    ("biwul", "noun", None, "NA", "snake", "batch-386: non-singular snake sense only; kinship/avoidance/case/event boundaries preserved."),
    ("yirku-yirku", "noun", None, "NA", "frog", "batch-386: non-singular exact whole frog head; base/process/event boundaries preserved."),
    ("jadi", "noun", None, "NA", "goanna", "batch-386: non-singular generic goanna only; taboo/food/hunting/event boundaries preserved."),
    ("walkarr", "noun", None, "NA", "goanna", "batch-386: non-singular bare generic goanna; property/case/use/event boundaries preserved."),
    ("bajabaja", "noun", None, "NA", "lizard", "batch-386: non-singular exact whole lizard head; myth/place/base/property/event boundaries preserved."),
    ("ngali", "pronoun", None, "NA", "first dual exclusive nominative", "batch-386: Patz Table 3.6 controls; dictionary inclusive misgloss recorded; bare A only."),
    ("ngaliny", "pronoun", None, "NA", "first dual inclusive nominative", "batch-386: Patz Table 3.6 controls; exact dictionary card absent; bare A only."),
    ("yubal", "pronoun", None, "NA", "second dual nominative", "batch-386: bare A only."),
    ("yurra", "pronoun", None, "NA", "second plural nominative", "batch-386: bare A only."),
    ("nganjin", "pronoun", None, "NA", "first plural exclusive nominative", "batch-386: bare A only; distinct from deferred inclusive ngana."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-386: Yalanji local support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-386: Yalanji local support only."),
    ("nyajin", "verb-tr", "l", "NA", "see; see.PST", "batch-386: 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-386-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-386-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; non-singular number/clusivity, target senses, syntax, fidelity and neutral register retained."),
        ("review", "review-detail", "Dictionary pronoun conflict, ngana distinction, target duplicate/polysemy/taxonomy/culture/food/whole-head/property/habitat/source/case/event and support drift remained controlled."),
        ("review", "lesson-inventory", f"Inserted {len(LESSONS)} Rule 344 lessons."),
        ("review", "lexeme-source-log", f"Inserted {len(LEXEMES)} Rule 344 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 344 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-386-verify'").fetchone()[0]
    record_event(
        db, batch_label=LABEL, phase="close", event_type="close-success", actor="codex",
        detail=(f"Closed Rule 344: 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_386.py", artifact_path=PROCESS_LOG, created_at=NOW,
    )
    db.commit()
    print(
        f"closed batch-386: 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())
