"""What a whole task has spent, across every run of every phase.

A report's own figures cover one run, but a task reaches its plan through
several: the first pass, a clarification re-run, a conformance fix. Each of
those bills separately, and a reader who only ever sees the last one has no way
to learn what the task cost. The per-run team-states are the only record of the
earlier passes, so the total is summed from them here rather than carried
forward inside any single run's state.

Every team-state is read directly rather than through its `usageSummary`: the
summary predates the cache-read figure, so an older run would drop out of that
column while still counting in the others.
"""
from __future__ import annotations

import json
from pathlib import Path

_TEAM_STATE_GLOB = "runs/*/state/team-state-*.json"
_SUMMED_KEYS = (
    ("totalTokens", "totalTokens"),
    ("cacheReadTokens", "cacheReadTokens"),
    ("billableTokens", "billableEquivalentTokens"),
    ("costUsd", "estimatedCostUsd"),
)


def _task_root(data_path: Path) -> Path | None:
    """The task-bundle directory a report lives under.

    Report path shape: `<task-id>/runs/<task-type>/reports/<name>.data.json`.
    A path that does not match is not inside a task bundle — a fixture under a
    tmp dir, most often — and has no sibling runs to total.
    """
    parents = data_path.parents
    if len(parents) < 4:
        return None
    if parents[0].name != "reports" or parents[2].name != "runs":
        return None
    return parents[3]


def _usage_blocks(team_state: dict) -> list[dict]:
    blocks = [team_state.get("leadUsage") or {}]
    for worker in team_state.get("workers") or []:
        if isinstance(worker, dict):
            blocks.append(worker.get("usage") or {})
    unattributed = (team_state.get("usageSummary") or {}).get("unattributedWorkerUsage")
    if isinstance(unattributed, dict):
        blocks.append(unattributed)
    return [block for block in blocks if isinstance(block, dict)]


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


def task_cumulative_usage(data_path: Path) -> dict | None:
    """Sum every measured run of this report's task, or None when there is none.

    A run whose collector found no session contributes zero tokens and is left
    out of `runCount` — counting it would make the average per run look cheaper
    than the runs that were actually measured.
    """
    root = _task_root(data_path)
    if root is None:
        return None
    totals = {name: 0 for name, _ in _SUMMED_KEYS}
    run_count = 0
    for state_path in sorted(root.glob(_TEAM_STATE_GLOB)):
        try:
            team_state = json.loads(state_path.read_text(encoding="utf-8"))
        except (OSError, ValueError):
            continue
        if not isinstance(team_state, dict):
            continue
        blocks = _usage_blocks(team_state)
        measured = sum(_number(block.get("totalTokens")) for block in blocks)
        if measured <= 0:
            continue
        run_count += 1
        for name, source_key in _SUMMED_KEYS:
            totals[name] += sum(_number(block.get(source_key)) for block in blocks)
    if not run_count:
        return None
    return {**totals, "runCount": run_count}
