"""Pydantic models for the plyra-trace collector REST API."""

from typing import Any

from pydantic import BaseModel


class ProjectSummary(BaseModel):
    """Summary of a project with optional aggregated stats."""

    id: str
    span_count: int = 0
    last_seen_at: str | None = None
    # Stats from get_projects_with_stats()
    trace_count: int | None = None
    total_cost: float | None = None
    last_seen: str | None = None


class ProjectsResponse(BaseModel):
    """Response for GET /api/v1/projects."""

    projects: list[ProjectSummary]


class TraceSummary(BaseModel):
    """Summary of a trace (metadata only, for list views)."""

    trace_id: str
    project_id: str
    root_name: str
    root_span_id: str
    started_at: str
    ended_at: str | None
    duration_ms: int | None
    span_count: int
    llm_cost_usd: float
    llm_token_total: int
    llm_cache_hits: int
    llm_cache_total: int
    has_guard_block: bool
    has_error: bool
    status: str
    session_id: str | None
    user_id: str | None


class TracesResponse(BaseModel):
    """Response for GET /api/v1/traces."""

    traces: list[TraceSummary]
    total: int


class SpanRecord(BaseModel):
    """A single span record from the database."""

    span_id: str
    trace_id: str
    parent_id: str | None
    project_id: str
    name: str
    kind: str
    started_at: str
    ended_at: str
    duration_ms: int
    attributes: dict[str, Any]
    events: list[dict[str, Any]]
    status: str


class SpansResponse(BaseModel):
    """Response for GET /api/v1/traces/{trace_id}/spans."""

    spans: list[SpanRecord]


class CostByAgent(BaseModel):
    """LLM cost breakdown per agent."""

    agent_name: str
    cost_usd: float


class CostByModel(BaseModel):
    """LLM cost and call count per model."""

    model_name: str
    cost_usd: float
    call_count: int


class TokenByHour(BaseModel):
    """Token usage per hour."""

    hour: str  # "00" through "23"
    prompt: int
    completion: int


class LLMStatsResponse(BaseModel):
    """Response for GET /api/v1/stats/llm."""

    total_cost_usd: float
    total_calls: int
    cache_hit_rate: float
    cache_hits: int
    cost_by_agent: list[CostByAgent]
    cost_by_model: list[CostByModel]
    token_by_hour: list[TokenByHour]


class AgentStats(BaseModel):
    """Performance stats for one agent."""

    name: str
    invocations: int
    avg_duration_ms: float
    p95_duration_ms: float
    llm_calls: int
    cache_hit_rate: float
    tools_used: list[str]


class AgentsStatsResponse(BaseModel):
    """Response for GET /api/v1/stats/agents."""

    agents: list[AgentStats]


class GuardEvent(BaseModel):
    """A single guard/policy event."""

    time: str
    tool_name: str
    tool_category: str
    action: str  # "allow" | "block"
    agent_name: str
    input_preview: str
    confidence: float | None
    trace_id: str
    policy: str


class GuardsStatsResponse(BaseModel):
    """Response for GET /api/v1/stats/guards."""

    total: int
    allowed: int
    blocked: int
    events: list[GuardEvent]


class DbMetaResponse(BaseModel):
    """Response for GET /api/v1/stats/db."""

    size_mb: float
    trace_count: int
    span_count: int
    oldest_trace_at: str | None
