"""Topology data models -- Pydantic v2 schemas for network topology state."""

from __future__ import annotations

from datetime import datetime, timezone
from enum import Enum

from pydantic import BaseModel, ConfigDict, Field


class BackendStatus(str, Enum):
    """Health status of a backend node."""

    online = "online"
    degraded = "degraded"
    offline = "offline"


class LatencyBucket(str, Enum):
    """Color-coded latency classification."""

    green = "green"  # <100ms
    yellow = "yellow"  # 100-500ms
    red = "red"  # >500ms
    gray = "gray"  # offline / unknown


class BackendNode(BaseModel):
    """A single backend in the network topology."""

    model_config = ConfigDict(frozen=False)

    backend_id: str  # unique identifier (e.g. "ollama-local", "openai-cloud")
    backend_type: str  # "ollama", "openai", "anthropic", "openrouter", "lan"
    name: str  # human-readable display name
    url: str
    is_local: bool = False
    status: BackendStatus = BackendStatus.offline
    latency_ms: float = 0.0  # rolling average latency
    latency_bucket: LatencyBucket = LatencyBucket.gray
    p50_ms: float = 0.0
    p95_ms: float = 0.0
    p99_ms: float = 0.0
    models: list[str] = Field(default_factory=list)
    last_seen: datetime | None = None
    last_check: datetime | None = None
    consecutive_failures: int = 0
    uptime_percent: float = 100.0
    trend: str = "stable"  # "improving", "stable", "degrading"


class TopologySnapshot(BaseModel):
    """Complete snapshot of the network topology at a point in time."""

    timestamp: datetime = Field(default_factory=lambda: datetime.now(tz=timezone.utc))
    nodes: list[BackendNode] = Field(default_factory=list)
    total_backends: int = 0
    healthy_backends: int = 0
    avg_latency_ms: float = 0.0


def classify_latency(latency_ms: float, is_online: bool) -> LatencyBucket:
    """Classify latency into a color bucket."""
    if not is_online:
        return LatencyBucket.gray
    if latency_ms < 100:
        return LatencyBucket.green
    if latency_ms <= 500:
        return LatencyBucket.yellow
    return LatencyBucket.red
