#!/usr/bin/env python3
"""exp13 — слепой «монитор ПЕРЕВОДЧИКОВ»: оригинал zh + все армы-переводчики, СЛЕПО.

Для флагман-сверки владельца (пре-рег §1.4): оригинал+вариант на копирование во Fable 5/5.6,
+ место под любительский перевод. Имена моделей скрыты; армы под нейтральными метками,
перемешаны СВОЕЙ перестановкой в каждой главе (свап). Ключ — отдельный файл
`_МОНИТОР13_КЛЮЧ.json`, не открывать до вынесения оценки. Локальный HTML (текст книги ВНЕ git/хостинга).

Выход: diag/reading/monitor13.html + diag/reading/_МОНИТОР13_КЛЮЧ.json
"""
from __future__ import annotations
import html, json, random
from pathlib import Path

DIAG = Path("/home/ubuntu/books/gu-zhenren/diag")
ARMS = DIAG / "arms13"
chunks = json.loads((DIAG / "chunks.json").read_text(encoding="utf-8"))
CH = [(5, "смешанная (нарратив+диалог)"), (7, "диалого-плотная"), (14, "экспозиция/описание")]
CHUNKS = {5: [0, 1], 7: [0, 1], 14: [0, 1]}
SALT = "exp13-monitor-blind-v1"
LEGEND = {
    "T1": "deepseek-v4-flash (текущий базовый черновик)",
    "T2": "mistral-large-2512",
    "T3": "glm-5",
    "T4": "deepseek-v4-pro",
    "T5": "grok-4.3 reasoning-ON",
    "T6": "qwen-flash",
}


MD_PROMPT = """# Слепая оценка ЧЕРНОВИКОВ перевода (蛊真人, zh→ru) — задача для модели

Ты — эксперт по художественному переводу китайских вебновелл-культиваторок (сянься/уся) на русский. Ниже — 3 главы. В КАЖДОЙ: китайский ОРИГИНАЛ и 5 анонимных вариантов её русского ЧЕРНОВОГО перевода (метки V1…V5). Это черновики РАЗНЫХ моделей-переводчиков (редактура будет позже) — оценивай именно черновой перевод. Метки перемешаны В КАЖДОЙ ГЛАВЕ ПО-РАЗНОМУ: «V1» в главе 5 и в главе 7 — это РАЗНЫЕ модели, не связывай метки между главами. Не пытайся угадать, какая модель за какой меткой — суди только текст.

Для КАЖДОЙ главы сравни варианты по трём осям, СТРОГО сверяясь с оригиналом:
1. **ВЕРНОСТЬ смыслу (главное):** точность; отсутствие искажений, ИНВЕРСИЙ смысла, пропусков, отсебятины, перепутанных субъектов. Особо отмечай «smooth-wrong» — гладко по-русски, но смысл искажён.
2. **КАЧЕСТВО русской прозы:** живость, читаемость, отсутствие канцелярита и калек, естественный синтаксис/ритм.
3. **ЖАНР/ТЕРМИНОЛОГИЯ:** корректность реалий культивации (культивация, секты, ранги, гу-термины), уместность имён/титулов.

**Вывод по каждой главе:** (a) ранг V1…V5 от лучшего к худшему (приоритет — верность); (b) по каждому варианту 2–4 примера (цитата + что не так/хорошо относительно оригинала); (c) список smooth-wrong искажений (вариант → цитата → верный смысл).
**Сводно в конце:** какая метка в какой главе — лучший черновик; есть ли модель, стабильно лучшая во всех 3 главах; дотягивает ли хоть один черновик до чтения без спотыкания и какой ближе к публикабельному.

---
"""


def arms_present():
    return sorted([p.name for p in ARMS.iterdir() if p.is_dir() and p.name.startswith("T")])


def build_markdown(arms, key_map):
    out = [MD_PROMPT]
    for ch, reg in CH:
        out.append(f"\n# ГЛАВА {ch} — {reg}\n")
        out.append("## Оригинал (zh)\n")
        out.append(source_text(ch))
        for i in range(len(arms)):
            lab = f"V{i+1}"
            out.append(f"\n## Вариант {lab}\n")
            out.append(arm_text(key_map[str(ch)][lab], ch))
    return "\n".join(out)


def arm_text(arm, ch):
    parts = []
    for ci in CHUNKS[ch]:
        p = ARMS / arm / f"{ch}_{ci}.txt"
        parts.append(p.read_text(encoding="utf-8").strip() if p.exists() else "(нет)")
    return "\n\n".join(parts)


def source_text(ch):
    return "\n\n".join(chunks[f"{ch}/{ci}"]["source"] for ci in CHUNKS[ch])


CSS = """
:root{--bg:#faf9f7;--fg:#1c1a17;--card:#fff;--bd:#e3ddd3;--mut:#8a8177;--acc:#3e5c7a}
@media(prefers-color-scheme:dark){:root{--bg:#0f1317;--fg:#e8e3d8;--card:#171e25;--bd:#2a333b;--mut:#8494a0;--acc:#78a6c9}}
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.6 Georgia,"Noto Serif",serif}
.wrap{max-width:1180px;margin:0 auto;padding:24px}
h1{font-size:24px;margin:0 0 6px}.sub{color:var(--mut);font-size:14px;margin:0 0 20px;line-height:1.5}
.chap{margin:34px 0 8px;font-size:20px;border-bottom:2px solid var(--acc);padding-bottom:6px}
.src{background:var(--card);border:1px solid var(--bd);border-radius:10px;padding:14px 16px;margin:12px 0 20px}
.src .lbl{color:var(--acc);font-weight:700;font-size:13px;letter-spacing:.03em;text-transform:uppercase}
.grid{display:grid;grid-template-columns:1fr;gap:14px}
.card{background:var(--card);border:1px solid var(--bd);border-radius:10px;overflow:hidden}
.hd{display:flex;align-items:center;gap:10px;padding:11px 14px;border-bottom:1px solid var(--bd)}
.hd .t{font-weight:700;font-size:15px}
.body{padding:6px 16px 14px;white-space:pre-wrap;font-size:15.5px}
.body.zh{font-family:"Noto Sans CJK SC","Microsoft YaHei",sans-serif;font-size:15px}
button{font:inherit;font-size:12.5px;background:var(--acc);color:#fff;border:0;border-radius:6px;padding:5px 11px;cursor:pointer}
button.ghost{background:transparent;color:var(--acc);border:1px solid var(--acc)}
.slot{border:2px dashed var(--bd);border-radius:10px;padding:16px;color:var(--mut);font-size:14px;margin-top:14px}
.toolbar{display:flex;gap:8px;flex-wrap:wrap;margin:8px 0 0}
.note{background:var(--card);border:1px solid var(--bd);border-left:3px solid var(--acc);border-radius:8px;padding:10px 14px;font-size:13.5px;color:var(--mut);margin:16px 0}
"""
FLAGSHIP_PROMPT = (
    "Ты — эксперт по художественному переводу китайских вебновелл-культиваторок (сянься/уся) на русский. "
    "Ниже — КИТАЙСКИЙ ИСХОДНИК одной главы и несколько АНОНИМНЫХ вариантов её русского ЧЕРНОВОГО перевода "
    "(метки V1, V2, …). Это черновики РАЗНЫХ моделей; редактура будет позже — оценивай именно черновой перевод. "
    "Не пытайся угадать модель — суди только текст.\\n\\n"
    "Сравни варианты по трём осям, СТРОГО сверяясь с исходником:\\n"
    "1) ВЕРНОСТЬ смыслу (главное): точность; отсутствие искажений, ИНВЕРСИЙ смысла, пропусков, отсебятины, "
    "перепутанных субъектов. Особо отмечай «smooth-wrong» — гладко по-русски, но смысл искажён.\\n"
    "2) КАЧЕСТВО русской прозы: живость, читаемость, отсутствие канцелярита и калек, естественный синтаксис/ритм.\\n"
    "3) ЖАНР/ТЕРМИНОЛОГИЯ: корректность реалий культивации, уместность имён/титулов.\\n\\n"
    "Ответ: (a) РАНГ вариантов от лучшего к худшему (приоритет — верность); (b) по каждому 2–4 конкретных "
    "примера (цитата + что не так/хорошо относительно zh); (c) отдельный список smooth-wrong (вариант → цитата → "
    "верный смысл); (d) вердикт: дотягивает ли ХОТЬ ОДИН до чтения без спотыкания и какой ближе к публикабельному черновику."
)

JS = """
var PROMPT=%r;
function esc(id){var e=document.getElementById(id);return e?e.textContent:''}
function copyOne(vid){navigator.clipboard.writeText(esc(vid));flash(event.target)}
function copyPair(sid,vid){navigator.clipboard.writeText('=== ОРИГИНАЛ (zh) ===\\n'+esc(sid)+'\\n\\n=== ПЕРЕВОД ===\\n'+esc(vid));flash(event.target)}
function copyPrompt(){navigator.clipboard.writeText(PROMPT);flash(event.target)}
function copyChapter(sid,vids){
  var parts=[PROMPT,'\\n\\n===== ИСХОДНИК (zh) =====\\n'+esc(sid)];
  for(var i=0;i<vids.length;i++){parts.push('\\n\\n===== V'+(i+1)+' =====\\n'+esc(vids[i]))}
  navigator.clipboard.writeText(parts.join(''));flash(event.target)
}
function flash(b){var o=b.textContent;b.textContent='✓ скопировано';setTimeout(function(){b.textContent=o},1400)}
""" % FLAGSHIP_PROMPT


def main():
    arms = arms_present()
    key_map = {}
    out = ['<div class="wrap">']
    out.append('<h1>蛊真人 — слепой монитор ПЕРЕВОДЧИКОВ (exp13)</h1>')
    out.append('<p class="sub">Оригинал + варианты ЧЕРНОВОГО перевода (разные модели-переводчики) по 3 главам, '
               'СЛЕПО: имена моделей скрыты, метки перемешаны по-своему в каждой главе («V3» в гл.5 и гл.7 — РАЗНЫЕ модели). '
               'Это ЧЕРНОВИКИ (без редактуры) — сравнивай ВЕРНОСТЬ смыслу и качество русской прозы. '
               'Кнопка «копировать оригинал+перевод» кладёт пару в буфер для флагмана (Fable 5/5.6) слепо. '
               'Ключ — <code>_МОНИТОР13_КЛЮЧ.json</code> рядом, НЕ открывай до вынесения оценки.</p>')
    out.append('<div class="note">🎯 <b>Как гонять флагмана (GPT/Claude), слепо:</b> у каждой главы жми '
               '«📋 копировать ГЛАВУ целиком» — в буфер лягут ГОТОВЫЙ ПРОМТ + оригинал + все версии V1…V5. '
               'Вставь одним куском в GPT/Claude и отправь. Флагман не увидит имён моделей. '
               '<button onclick="copyPrompt()">копировать только промт</button></div>')

    for ch, reg in CH:
        order = arms[:]
        random.Random(f"{SALT}-{ch}").shuffle(order)
        labels = {f"V{i+1}": arm for i, arm in enumerate(order)}
        key_map[str(ch)] = labels
        out.append(f'<h2 class="chap">Глава {ch} — {html.escape(reg)}</h2>')
        sid = f"src{ch}"
        vids_js = "[" + ",".join(f"'v{ch}_{i+1}'" for i in range(len(arms))) + "]"
        out.append(f'<div class="src"><div class="lbl">Оригинал (zh)</div>'
                   f'<div class="toolbar">'
                   f'<button onclick="copyChapter(\'{sid}\',{vids_js})">📋 копировать ГЛАВУ целиком (промт + оригинал + все версии) — для флагмана</button>'
                   f'<button class="ghost" onclick="copyOne(\'{sid}\')">только оригинал</button></div>'
                   f'<div class="body zh" id="{sid}">{html.escape(source_text(ch))}</div></div>')
        out.append('<div class="grid">')
        for i, (lab, arm) in enumerate(labels.items(), 1):
            vid = f"v{ch}_{i}"
            out.append('<div class="card">')
            out.append(f'<div class="hd"><span class="t">{lab}</span></div>')
            out.append(f'<div class="toolbar" style="padding:8px 16px 0">'
                       f'<button onclick="copyPair(\'{sid}\',\'{vid}\')">копировать оригинал+перевод</button>'
                       f'<button class="ghost" onclick="copyOne(\'{vid}\')">только перевод</button></div>')
            out.append(f'<div class="body" id="{vid}">{html.escape(arm_text(arm, ch))}</div>')
            out.append('</div>')
        out.append('</div>')
        out.append('<div class="slot">➕ Любительский перевод этой главы: добавляй сам при загрузке во флагман.</div>')

    out.append('<div class="note">Это ЧЕРНОВИКИ переводчиков (стадия draft), НЕ финал: downstream их чинит '
               'билингвальный редактор (D30.1). Задача монитора — выбрать САМЫЙ ВЕРНЫЙ и живой ЧЕРНОВИК. '
               'Имена моделей скрыты, чтобы ярлык не искажал восприятие. Расшифровка — в закрытом ключе.</div>')
    out.append('</div>')
    out.append(f'<style>{CSS}</style><script>{JS}</script>')

    (DIAG / "reading").mkdir(parents=True, exist_ok=True)
    (DIAG / "reading" / "monitor13.html").write_text("\n".join(out), encoding="utf-8")
    (DIAG / "reading" / "monitor13.md").write_text(build_markdown(arms, key_map), encoding="utf-8")
    (DIAG / "reading" / "_МОНИТОР13_КЛЮЧ.json").write_text(
        json.dumps({"salt": SALT, "map": key_map, "arms": {a: LEGEND.get(a, a) for a in arms}}, ensure_ascii=False, indent=1),
        encoding="utf-8")
    print(f"монитор ({len(arms)} армов) → diag/reading/monitor13.html + monitor13.md (самодостаточный)")
    for ch in [5, 7, 14]:
        print(f"  гл.{ch}: {[key_map[str(ch)][f'V{i+1}'] for i in range(len(arms))]}")


if __name__ == "__main__":
    main()
