"""Итоговый отчёт.

Собирается перечитыванием состояния и журнала с диска, а не по памяти оркестратора.
Раздел «Сделано» берётся из вердикта слепого приёмщика, а не из собственных отметок
`done` — иначе отчёт подтверждает сам себя.
"""

from __future__ import annotations

from . import gates, runner
from .phases import SCALE_RU
from .store import SPEND_MEASURED, SPEND_REPORTED, Run


def _dur(ms: int | None) -> str:
    if ms is None:
        return "—"
    sec = ms // 1000
    if sec < 60:
        return f"{sec} с"
    minutes = sec // 60
    if minutes < 60:
        return f"{minutes} мин"
    return f"{minutes // 60} ч {minutes % 60:02d} мин"


def _tasks(n: int) -> str:
    return "задаче" if n % 10 == 1 and n % 100 != 11 else "задачам"


def spend_section(run: Run) -> list[str]:
    """Расход по задачам. Измеренное и сообщённое стоят рядом, но не смешаны.

    Сумма считается только по тем задачам, где расход назван. Задачи без расхода
    перечислены поимённо — иначе сумма читается как полная, а она неполная.
    """
    rows = run.spend_rows()
    lines = ["## Расход", ""]
    if not rows:
        return lines + ["Закрытых задач нет — считать нечего.", ""]

    lines += [
        f"Токены — {SPEND_REPORTED}: инструменту их взять неоткуда и проверить нечем. "
        f"Время работы и число прогонов — {SPEND_MEASURED} самим инструментом.",
        "",
    ]

    silent = []
    tokens_total = 0
    time_total = 0
    for r in rows:
        model = (
            f"{r['model']} ({r['agent']})"
            if r.get("model") and r.get("agent") and r["model"] != r["agent"]
            else (r.get("model") or r.get("agent") or "модель не названа")
        )
        if r["tokens"] is None:
            silent.append(r)
            spent = "расход не измерен"
        else:
            tokens_total += r["tokens"]
            spent = f"токены {r['tokens']} ({SPEND_REPORTED})"
        time_total += r["duration_ms"] or 0
        lines.append(
            f"- {r['id']} {r['title']} — {model} · {spent} · "
            f"время {_dur(r['duration_ms'])} ({SPEND_MEASURED}) · "
            f"прогонов {r['runs'] if r['runs'] is not None else '—'} ({SPEND_MEASURED})"
        )
    lines.append("")

    counted = len(rows) - len(silent)
    lines.append(
        f"Сумма токенов: {tokens_total} — {SPEND_REPORTED}, "
        f"по {counted} {_tasks(counted)} из {len(rows)}."
    )
    if silent:
        lines.append(
            "Расход не измерен, и в сумму эти задачи не вошли: "
            + ", ".join(f"{r['id']} {r['title']}" for r in silent)
            + "."
        )
    else:
        lines.append("Задач без расхода нет — сумма полная.")
    lines.append(
        f"Сумма измеренного времени: {_dur(time_total)} по {len(rows)} {_tasks(len(rows))}."
    )
    lines.append("")
    return lines


def build(run: Run) -> str:
    st = run.state
    g4 = st.get("gates", {}).get("G4", {})
    blind = g4.get("blind") or {}
    from .manifest import short_title

    short = short_title(st["title"])
    lines = [f"# {short}", ""]
    if short != st["title"]:
        lines += [st["title"], ""]
    lines += [
        f"Слаг: `{st['slug']}` · режим {st['mode']} · масштаб {SCALE_RU.get(st['tier'], st['tier'])}",
        f"Начат: {st['started_at']}",
        "",
    ]

    lines += ["## Сделано", ""]
    if blind.get("done"):
        lines.append("По вердикту слепого приёмщика — субагента, которому дали только бриф:")
        lines += [f"- {item}" for item in blind["done"]]
    else:
        lines.append(
            "_Слепая приёмка не проводилась. Списку закрытых тасков верить нельзя: "
            "он подтверждает сам себя._"
        )
    lines.append("")

    missing = blind.get("missing") or []
    unfinished = [
        r for r in st["requirements"]
        if r["status"] in ("open", "placeholder", "deferred", "dropped")
    ]
    if missing or unfinished:
        lines += ["## Что не вошло", ""]
        for item in missing:
            lines.append(f"- {item} — не найдено слепым приёмщиком")
        for r in unfinished:
            label = {
                "open": "не разобрано",
                "placeholder": "заглушка, нужны ваши данные",
                "deferred": "отложено",
                "dropped": "снято вами",
            }[r["status"]]
            lines.append(f"- {r['id']} ({label}): «{r['quote']}»")
        lines.append("")

    lines += ["## Доказательства", ""]
    rows = [e for e in run.evidence() if e.get("exit") is not None]
    green = [e for e in rows if e["exit"] == 0]
    lines.append(f"Прогонов записано: {len(rows)}, из них зелёных: {len(green)}.")
    lines.append("")
    for t in st["tasks"]:
        proof = run.green_evidence(t["id"])
        if proof:
            lines.append(f"- {t['id']} {t['title']} — `{proof['cmd']}` → 0, коммит {(proof.get('git_sha') or '')[:8]}")
        else:
            lines.append(f"- {t['id']} {t['title']} — **доказательства нет** (статус {t['status']})")
    lines.append("")
    lines.append(runner.report_line(run))
    lines.append("")

    lines += spend_section(run)

    lines += ["## Гейты", ""]
    for name in gates.CHECKS:
        entry = st.get("gates", {}).get(name, {})
        status = entry.get("status")
        if status == "passed":
            lines.append(f"- {name} {gates.GATE_TITLE[name]}: пройден")
        elif status == "failed":
            lines.append(f"- {name} {gates.GATE_TITLE[name]}: **не пройден**")
            for p in entry.get("problems", [])[:5]:
                lines.append(f"  - {p}")
        else:
            lines.append(f"- {name} {gates.GATE_TITLE[name]}: не проверялся")
    lines.append("")

    placeholders = [r for r in st["requirements"] if r["status"] == "placeholder"]
    if placeholders:
        lines += ["## Нужны ваши данные", ""]
        lines += [f"- {r['id']}: «{r['quote']}»" for r in placeholders]
        lines.append("")

    return "\n".join(lines).rstrip() + "\n"
