#!/usr/bin/env python3
"""Диагностика + демонстрация ДЕТЕРМИНИРОВАННОГО рычага коэффициента канон-консистентности
(follow-up к adaptive_incontext.py по запросу владельца: «раз не идём в гибрид — долбить
детерминированную сторону»).

Два вопроса:
  1. ДИАГНОЗ: промахи в arm B_glossary (напр. 王胡) — это РЕАЛЬНЫЙ провал adherence
     (модель не использовала утв. форму) или АРТЕФАКТ моего accept-регэкспа (напр. `Ван\b`
     не ловит склонённое «Вана/Вану»)? Печатаем реальный вывод + два матча (строгий \b vs
     склонение-толерантный стем).
  2. РЫЧАГ: post-check находит промах → точечный re-ask («используй утв. формы X,Y») →
     повторный перевод → коэффициент до/после. Это verifier-gated single-pass correction
     (research/14 §6, M2) — тот самый детерминированный рычаг, а не дообучение.

deepseek-v4-flash, тот же чанк 阿Q. INDICATIVE (малый N). Usage: eval/.venv/bin/python eval/adaptive_reask.py
"""
from __future__ import annotations
import json, re, sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
import refusal_bench as rb

ROOT = Path(__file__).resolve().parent
SRC = ROOT / "data" / "samples" / "zh" / "luxun-ah-q-ch5-9.txt"
CHUNK = SRC.read_text(encoding="utf-8")[6360:6360 + 650]

# canonical dst + СТРОГИЙ (\b, как в adaptive_incontext) и СКЛОНЕНИЕ-ТОЛЕРАНТНЫЙ стем-матч
ENT = {
    "阿Q":   ("А-кью",                r"А[-\s]?кью",           r"А[-\s]?кью"),
    "未庄":  ("Вэйчжуан",             r"Вэйчжуан",             r"Вэйчжуан"),
    "赵太爷": ("почтенный Чжао",       r"Чжао",                 r"Чжао"),
    "王胡":  ("Бородатый Ван",         r"Ван\b",                r"Ван[аоуые]?\b|Бород"),
    "小D":   ("Маленький Дэн",         r"Дэн",                  r"Дэн"),
    "假洋鬼子": ("Поддельный заморский чёрт", r"заморск\w+ чёрт|поддельн", r"заморск|поддельн|чёрт"),
    "吴妈":  ("У-ма",                  r"У[-\s]?ма",            r"У[-\s]?ма"),
    "邹七嫂": ("тётушка Цзоу Седьмая",  r"Цзоу",                 r"Цзоу"),
}
SYSTEM = ("Ты профессиональный литературный переводчик. Переведи фрагмент на русский язык. "
          "Сохрани все реплики и детали; стиль — живой литературный русский. Выведи ТОЛЬКО перевод.")
GLOSS = "ГЛОССАРИЙ (используй эти утверждённые переводы последовательно):\n" + \
        "\n".join(f"{z} → {v[0]}" for z, v in ENT.items())
PRESENT = [z for z in ENT if z in CHUNK]


def score(out, strict):
    idx = 1 if strict else 2
    return [z for z in PRESENT if re.search(ENT[z][idx], out)]


def translate(user):
    t, err, _ = rb.call_provider({"name": "deepseek", "base_url": "https://api.deepseek.com/v1",
                                  "model": "deepseek-v4-flash", "api_key_env": "DEEPSEEK_API_KEY",
                                  "max_tokens": 8000}, SYSTEM, user, timeout=180)
    return t or ""


def main():
    print(f"present entities ({len(PRESENT)}): {PRESENT}\n")
    for rep in range(2):
        print(f"================= REP {rep+1} =================")
        out = translate(GLOSS + "\n\nФРАГМЕНТ:\n" + CHUNK)
        strict, tol = score(out, True), score(out, False)
        print(f"[B_glossary] строгий-матч {len(strict)}/8={len(strict)/8:.3f}  |  склонение-толерантный {len(tol)}/8={len(tol)/8:.3f}")
        print(f"  промах(строгий): {[z for z in PRESENT if z not in strict]}")
        print(f"  промах(толерантный, = РЕАЛЬНЫЕ провалы adherence): {[z for z in PRESENT if z not in tol]}")
        # показать фактический рендер спорных сущностей
        for z in ["王胡", "假洋鬼子", "吴妈"]:
            can = ENT[z][0]
            frag = re.findall(r".{0,4}(?:Ван|Бород|заморск|поддельн|У-ма|У ма|Ху|Хо)\w*.{0,6}", out)
            print(f"    {z}→канон «{can}»: фрагменты вывода {frag[:3]}")
        # РЫЧАГ: re-ask по реальным промахам
        miss = [z for z in PRESENT if z not in tol]
        if miss:
            terms = "; ".join(f"{z} = {ENT[z][0]}" for z in miss)
            reask = (GLOSS + "\n\nФРАГМЕНТ:\n" + CHUNK +
                     f"\n\nВАЖНО: в переводе ОБЯЗАТЕЛЬНО используй утверждённые формы: {terms}. Перепиши перевод, применив их.")
            out2 = translate(reask)
            tol2 = score(out2, False)
            print(f"  → post-check re-ask по {miss}: {len(tol)}/8 → {len(tol2)}/8 (толерантный)")
        else:
            print("  → промахов (толерантных) нет — re-ask не нужен")
        print()


if __name__ == "__main__":
    main()
