"""Project usage rows from stored execution-identity refs."""
from __future__ import annotations

import json
from pathlib import Path
from collections.abc import Mapping
from typing import Any

from .execution_identity import (
    ExecutionManifest,
    execution_identity_for_ref,
    stored_execution_label,
    stored_identity,
)
from .execution_manifest import read_execution_manifest
from .json_boundary import load_owned_object


def unrostered_usage_workers(state: Mapping[str, Any]) -> list[dict[str, Any]]:
    """초기 명부에 없는 번역·비평 실행을 사용량 전용 행으로 투영한다."""
    from .dispatch_state import v2_worker_state_key

    known = {str(row.get("workerId")) for row in state.get("workers") or []
             if isinstance(row, Mapping)}
    additional: dict[str, dict[str, Any]] = {}
    for record in usage_dispatch_records(state):
        key = str(record.get("workerId") or "")
        if not key and record.get("assignmentRef"):
            key = v2_worker_state_key(record)
        if not key or key in known:
            continue
        row = additional.setdefault(key, {
            "workerId": key, "role": record.get("role") or record.get("audience") or key,
            "provider": record.get("provider"), "agent": record.get("provider"),
            "runner": record.get("runner") or "cli-wrapper", "usageAttempts": [],
            **stored_identity(record),
        })
        row.update(status=record.get("status"), promptPath=record.get("promptPath"),
                   model=record.get("modelExecutionValue") or record.get("model"))
        attempt = {name: record.get(name) for name in ("invocationRef", "attempt", "status")}
        if attempt not in row["usageAttempts"]:
            row["usageAttempts"].append(attempt)
    return list(additional.values())


def usage_dispatch_records(
    state: Mapping[str, Any], worker_id: str | None = None,
) -> list[Mapping[str, Any]]:
    from .dispatch_state import worker_dispatch_records

    records: list[Mapping[str, Any]] = []
    seen: set[tuple] = set()
    for collection in ("workerDispatches", "agentDispatches"):
        source = state.get(collection)
        for record in source if isinstance(source, list) else []:
            if not isinstance(record, Mapping):
                continue
            reference = record.get("invocationRef") or record.get("promptPath")
            key = (reference, record.get("attempt", 1))
            if reference and key in seen:
                continue
            seen.add(key)
            records.append(record)
    return worker_dispatch_records({"workerDispatches": records}, worker_id)


def usage_session_ids(state: Mapping[str, Any], worker_id: str) -> list[str]:
    from .dispatch_state import worker_session_ids

    return worker_session_ids({"workerDispatches": usage_dispatch_records(state)}, worker_id)


def run_execution_manifest(run_root: Path) -> ExecutionManifest:
    """Load the first run-manifest under ``run_root/manifests``."""
    return read_execution_manifest(_manifest_path(run_root))


def identity_rows_from_state(state: Mapping[str, Any] | None) -> list[dict[str, Any]]:
    """Collect stored identity rows from a team-state document."""
    if not isinstance(state, Mapping):
        return []
    rows: list[dict[str, Any]] = []
    seen: set[str] = set()
    for collection in (
        state.get("workers") or [],
        state.get("workerDispatches") or [],
        state.get("agentDispatches") or [],
    ):
        if not isinstance(collection, list):
            continue
        for item in collection:
            ident = stored_identity(item if isinstance(item, Mapping) else None)
            if not ident:
                continue
            key = str(ident.get("roleExecutionRef") or ident.get("executionLabel"))
            if key in seen:
                continue
            seen.add(key)
            rows.append(ident)
    return rows


def collect_usage_rows(run_root: Path) -> list[dict[str, Any]]:
    """Project usage rows with stored execution identity refs."""
    manifest = run_execution_manifest(run_root)
    team_state = _load_json(run_root / "state" / "team-state.json")
    rows: list[dict[str, Any]] = []
    for collection in (
        team_state.get("workerDispatches") or [],
        team_state.get("agentDispatches") or [],
    ):
        for item in collection:
            if not isinstance(item, Mapping):
                continue
            rows.append(_usage_row(manifest, item))
    return rows


def _usage_row(manifest: ExecutionManifest, item: Mapping[str, Any]) -> dict[str, Any]:
    ref = str(item.get("roleExecutionRef") or "")
    role = execution_identity_for_ref(manifest, ref)
    return {
        "participantRef": item.get("participantRef") or role.participant_ref,
        "roleExecutionRef": role.role_execution_ref,
        "invocationRef": item.get("invocationRef"),
        "attempt": item.get("attempt", 1),
        "executionLabel": stored_execution_label(
            {"executionLabel": item.get("executionLabel") or role.execution_label}
        ),
    }


def _manifest_path(run_root: Path) -> Path:
    manifests = run_root / "manifests"
    for path in sorted(manifests.glob("*.json")):
        return path
    raise FileNotFoundError(f"no run manifest under {run_root}")


def _load_json(path: Path) -> dict[str, Any]:
    return load_owned_object(path, artifact="usage identity source")
