"""What the run cost, per agent — the Phase 7 usage cells as reader-facing text.

`executionStatus` is the only block that holds a duration per agent, so the
table is built from it rather than from `tokenUsage.workerDetails`, which
repeats the same token figures without saying how long each agent ran.

The formatting happens here rather than in the template because a null cell has
to read as "not measured" everywhere it appears, and `usage_cells` is where both
report views agree on how that looks.
"""
from __future__ import annotations

from ..usage_cells import format_duration_ms, format_int, format_usd


def _number(value: object) -> int | float | None:
    if isinstance(value, bool) or not isinstance(value, (int, float)):
        return None
    return value


def _totals_row(row: object) -> dict[str, str]:
    values = row if isinstance(row, dict) else {}
    return {
        "rawTokens": format_int(values.get("totalTokens")),
        "cacheReadTokens": format_int(values.get("cacheReadTokens")),
        "billableTokens": format_int(values.get("billableTokens")),
        "cost": format_usd(values.get("costUsd")),
    }


def _agent_row(row: dict) -> dict[str, str]:
    """One agent's identity and what it spent.

    The CLI cells stay empty rather than `--` when the agent made no CLI call:
    they render as a second line inside the token and cost cells, and a `--`
    there would read as a missing measurement instead of an absent charge.
    """
    cli_tokens = _number(row.get("cliTotalTokens")) or 0
    cli_cost = _number(row.get("cliCostUsd")) or 0
    cost = _number(row.get("costUsd"))
    if cost is None and cli_cost:
        cost = cli_cost
        cli_cost = 0
    return {
        "agent": str(row.get("agent") or ""),
        "role": str(row.get("role") or ""),
        "model": str(row.get("model") or ""),
        "status": str(row.get("status") or ""),
        "rawTokens": format_int(row.get("totalTokens")),
        "cacheReadTokens": format_int(row.get("cacheReadTokens")),
        "billableTokens": format_int(row.get("billableTokens")),
        "cost": format_usd(cost),
        "duration": format_duration_ms(row.get("durationMs")),
        "cliTokens": format_int(cli_tokens) if cli_tokens else "",
        "cliCost": format_usd(cli_cost) if cli_cost else "",
    }


def _sum(rows: list[dict], key: str) -> int | float:
    return sum(_number(row.get(key)) or 0 for row in rows)


def _unaccounted(rows: list[dict], grand: dict) -> dict[str, str] | None:
    """The part of the total that no row above carries, when there is one.

    Two documented paths leave a gap. Sessions that match no worker are summed
    into `unattributedWorkerUsage`, and where two report rows share one
    team-state aggregate only the first is attributed, leaving the second's
    cells null. Both land in the total, so without this row the column adds up
    to less than the figure beneath it and neither number can be trusted.
    """
    grand_tokens = _number(grand.get("totalTokens"))
    if grand_tokens is None:
        return None
    gap = grand_tokens - _sum(rows, "totalTokens")
    if gap <= 0:
        return None
    cache_gap = (_number(grand.get("cacheReadTokens")) or 0) - _sum(rows, "cacheReadTokens")
    billable_gap = (_number(grand.get("billableTokens")) or 0) - _sum(rows, "billableTokens")
    cost_gap = (_number(grand.get("costUsd")) or 0) - _sum(rows, "costUsd")
    return {
        "rawTokens": format_int(gap),
        "cacheReadTokens": format_int(max(0, cache_gap)),
        "billableTokens": format_int(max(0, billable_gap)),
        "cost": format_usd(max(0.0, cost_gap)),
    }


def _task_cumulative(row: object) -> dict[str, str] | None:
    """What the task has spent over every run, when more than this one exists.

    A single-run task would repeat the grand total word for word, and a reader
    seeing the same figure twice reads it as a second charge.
    """
    if not isinstance(row, dict):
        return None
    run_count = _number(row.get("runCount")) or 0
    if run_count < 2:
        return None
    return {**_totals_row(row), "runCount": format_int(run_count)}


_MEASURED_KEYS = ("totalTokens", "billableTokens", "costUsd", "durationMs")


def run_usage(data: dict) -> dict[str, object] | None:
    """The run-cost table, or nothing when the run has no measured figure.

    Phase 7 fills these cells before the HTML is rendered, so an all-null table
    means the collector found no session to read. A grid of `--` states nothing
    the reader can act on, so the section stays out of the document entirely.
    """
    rows = [row for row in (data.get("executionStatus") or []) if isinstance(row, dict)]
    usage = data.get("tokenUsage") or {}
    totals = {name: _totals_row(usage.get(name)) for name in ("lead", "worker", "grand")}
    measured = any(
        _number(row.get(key)) is not None for row in rows for key in _MEASURED_KEYS
    ) or any(
        _number((usage.get(name) or {}).get(key)) is not None
        for name in ("lead", "worker", "grand")
        for key in _MEASURED_KEYS
    )
    if not measured:
        return None
    cli_cost = _number((usage.get("cli") or {}).get("costUsd")) or 0
    return {
        "rows": [_agent_row(row) for row in rows],
        "unaccounted": _unaccounted(rows, usage.get("grand") or {}),
        **totals,
        "taskCumulative": _task_cumulative(usage.get("taskCumulative")),
        "cliCost": format_usd(cli_cost) if cli_cost else "",
    }
