#!/usr/bin/env python3
"""exp12 — предварительный АВТО-разбор draft→final по всем 25 главам (затравка root-cause).

Вопрос: редактор glm-5 «ухудшил», «не спас» или «пассивен»? Меряем:
  - similarity(draft, final): насколько редактор ВООБЩЕ менял черновик (difflib word-ratio).
    ~1.0 = редактор почти ничего не сделал (пассивен) → нечитаемость унаследована от черновика.
  - len_ratio = chars(final)/chars(draft).
  - translationese-маркеры (канцелярит/кальки) в draft и final → снизил ли редактор.
  - дефис-диалоги: доля реплик, начатых '-' (дефис) вместо '—' (em-dash) — Розенталь §47.
  - CJK-остаток в final.
$0. Вход: diag/chunks.json. Выход: diag/rootcause_auto.json + печать сводки.
"""
from __future__ import annotations
import json, re
from difflib import SequenceMatcher
from pathlib import Path

DIAG = Path("/home/ubuntu/books/gu-zhenren/diag")
CJK = re.compile("[一-鿿぀-ヿ]")
# грубые маркеры translationese/канцелярита (RU) — не приговор, а сигнал тренда
CLERICAL = [r"\bявлял?ся\b", r"\bявляется\b", r"\bявляются\b", r"\bосуществля", r"\bданн(ый|ая|ое|ые|ого|ому)\b",
            r"\bв связи с\b", r"\bпо причине\b", r"\bв случае\b", r"\bпредставля(ет|л) собой\b",
            r"\bбыл(а|о|и)? (?:вынужден|способ)", r"\bимел(а|о|и)? место\b", r"\bс целью\b",
            r"\bв результате\b", r"\bпосредством\b", r"\bнесмотря на то,? что\b"]
CLERICAL_RE = re.compile("|".join(CLERICAL), re.I)
# начало прямой речи дефисом вместо тире
DASH_HYPHEN = re.compile(r"(?m)^\s*-\s+[А-ЯЁA-Z]")
DASH_EM = re.compile(r"(?m)^\s*—\s+[А-ЯЁA-Z]")


def words(t: str) -> list[str]:
    return re.findall(r"\w+", t.lower())


def marker_count(t: str) -> int:
    return len(CLERICAL_RE.findall(t))


def main() -> None:
    chunks = json.loads((DIAG / "chunks.json").read_text(encoding="utf-8"))
    rows = []
    for key, v in chunks.items():
        d, f = v["draft"], v["final"]
        if not d.strip() or not f.strip():
            continue  # flagged/skipped edit
        sim = SequenceMatcher(None, words(d), words(f)).ratio()
        rows.append({
            "chunk": key, "chapter": v["chapter"],
            "sim": round(sim, 3),
            "len_ratio": round(len(f) / max(1, len(d)), 3),
            "cler_draft": marker_count(d), "cler_final": marker_count(f),
            "hyphen_dlg_final": len(DASH_HYPHEN.findall(f)),
            "em_dlg_final": len(DASH_EM.findall(f)),
            "cjk_final": len(CJK.findall(f)),
        })

    n = len(rows)
    avg = lambda k: round(sum(r[k] for r in rows) / n, 3)
    tot = lambda k: sum(r[k] for r in rows)
    summary = {
        "n_chunks": n,
        "avg_similarity_draft_final": avg("sim"),
        "median_similarity": sorted(r["sim"] for r in rows)[n // 2],
        "chunks_sim_ge_0.85 (editor near-passive)": sum(1 for r in rows if r["sim"] >= 0.85),
        "chunks_sim_ge_0.95 (editor barely touched)": sum(1 for r in rows if r["sim"] >= 0.95),
        "avg_len_ratio_final_draft": avg("len_ratio"),
        "clerical_markers_draft_total": tot("cler_draft"),
        "clerical_markers_final_total": tot("cler_final"),
        "clerical_reduced_by_editor": tot("cler_draft") - tot("cler_final"),
        "hyphen_dialogue_final_total": tot("hyphen_dlg_final"),
        "em_dialogue_final_total": tot("em_dlg_final"),
        "cjk_residue_final_total": tot("cjk_final"),
    }
    (DIAG / "rootcause_auto.json").write_text(
        json.dumps({"summary": summary, "per_chunk": rows}, ensure_ascii=False, indent=1), encoding="utf-8")

    print("=== AUTO root-cause (draft→final glm-5, all clean chunks) ===")
    for k, val in summary.items():
        print(f"  {k}: {val}")
    print("\n  По similarity (насколько редактор менял черновик), топ-пассивные:")
    for r in sorted(rows, key=lambda x: -x["sim"])[:6]:
        print(f"    {r['chunk']}: sim={r['sim']} len={r['len_ratio']} cler {r['cler_draft']}→{r['cler_final']}")
    print("  Топ-активные (редактор много менял):")
    for r in sorted(rows, key=lambda x: x["sim"])[:6]:
        print(f"    {r['chunk']}: sim={r['sim']} len={r['len_ratio']} cler {r['cler_draft']}→{r['cler_final']}")


if __name__ == "__main__":
    main()
