"""Structured routing logger for llm-rotator."""

from __future__ import annotations

import logging
import uuid
from dataclasses import dataclass, field

from llm_rotator._types import Candidate, Usage
from llm_rotator.exceptions import (
    KeyDeadError,
    LLMRotatorError,
    ModelRateLimitError,
    QuotaExceededError,
    ServerError,
)


@dataclass
class RoutingStep:
    """A single step in the routing chain."""

    candidate: Candidate
    result: str  # e.g. "200 OK", "429 RateLimit", "Skip (circuit breaker)"


@dataclass
class RoutingTrace:
    """Accumulates routing steps and formats the final log line."""

    request_id: str = field(default_factory=lambda: uuid.uuid4().hex[:8])
    steps: list[RoutingStep] = field(default_factory=list)
    _success: bool = False
    _usage: Usage | None = None

    def add_skip(self, candidate: Candidate, reason: str) -> None:
        """Record a skipped candidate."""
        self.steps.append(RoutingStep(
            candidate=candidate,
            result=f"Skip ({reason})",
        ))

    def add_error(self, candidate: Candidate, error: LLMRotatorError) -> None:
        """Record a failed candidate."""
        self.steps.append(RoutingStep(
            candidate=candidate,
            result=_format_error(error),
        ))

    def add_success(self, candidate: Candidate, usage: Usage) -> None:
        """Record a successful candidate."""
        self._success = True
        self._usage = usage
        self.steps.append(RoutingStep(
            candidate=candidate,
            result=f"200 OK (usage: {usage.total_tokens} tokens)",
        ))

    def add_all_failed(self) -> None:
        """Mark the routing as completely failed."""
        self._success = False

    def format(self) -> str:
        """Format the routing chain as a single log line."""
        parts: list[str] = [f"[req:{self.request_id}]"]

        for step in self.steps:
            c = step.candidate
            group = c.model_group or "_default"
            parts.append(
                f"[{c.provider_name}/{group}] "
                f"{c.model} ({c.key_alias})"
                f" \u2192 {step.result}"
            )

        if not self._success and self.steps:
            parts.append("\u2192 AllAttemptsFailed")

        return " ".join(parts)

    def emit(self, target_logger: logging.Logger) -> None:
        """Write the formatted routing chain to a logger."""
        message = self.format()
        if self._success:
            if len(self.steps) > 1:
                target_logger.warning(message)
            else:
                target_logger.info(message)
        else:
            target_logger.warning(message)


def _format_error(error: LLMRotatorError) -> str:
    """Format an error for the routing log."""
    if isinstance(error, ModelRateLimitError):
        return "429 RateLimit"
    if isinstance(error, KeyDeadError):
        return f"{error.status_code} KeyDead"
    if isinstance(error, QuotaExceededError):
        current_k = f"{error.current // 1000}k" if error.current >= 1000 else str(error.current)
        limit_k = f"{error.limit // 1000}k" if error.limit >= 1000 else str(error.limit)
        return f"QuotaExceeded ({current_k}/{limit_k})"
    if isinstance(error, ServerError):
        return f"{error.status_code} ServerError"
    return type(error).__name__
