"""Exception hierarchy for AgentiCraft packages."""

from __future__ import annotations

from typing import Any


class AgentiCraftError(Exception):
    """Base exception for all AgentiCraft errors."""

    def __init__(
        self,
        message: str,
        *,
        details: dict[str, Any] | None = None,
    ):
        super().__init__(message)
        self.message = message
        self.details = details or {}


class ProviderError(AgentiCraftError):
    """Error from an LLM provider."""

    def __init__(
        self,
        message: str,
        *,
        provider: str | None = None,
        model: str | None = None,
        status_code: int | None = None,
        details: dict[str, Any] | None = None,
    ):
        super().__init__(message, details=details)
        self.provider = provider
        self.model = model
        self.status_code = status_code

    def __str__(self) -> str:
        parts = [self.message]
        if self.provider:
            parts.append(f"provider={self.provider}")
        if self.model:
            parts.append(f"model={self.model}")
        return " | ".join(parts)


class RateLimitError(ProviderError):
    """Rate limit exceeded."""

    def __init__(
        self,
        message: str,
        *,
        provider: str | None = None,
        model: str | None = None,
        retry_after: float | None = None,
        details: dict[str, Any] | None = None,
    ):
        super().__init__(message, provider=provider, model=model, details=details)
        self.retry_after = retry_after


class AuthenticationError(ProviderError):
    """Authentication error -- API key invalid, expired, or missing."""


class ModelNotFoundError(ProviderError):
    """Model not found or unavailable."""

    def __init__(
        self,
        message: str,
        *,
        provider: str | None = None,
        model: str | None = None,
        available_models: list[str] | None = None,
        details: dict[str, Any] | None = None,
    ):
        super().__init__(message, provider=provider, model=model, details=details)
        self.available_models = available_models or []


class ContentFilterError(ProviderError):
    """Content filtered by provider safety systems."""


class TimeoutError(ProviderError):
    """Request timeout."""

    def __init__(
        self,
        message: str,
        *,
        provider: str | None = None,
        model: str | None = None,
        timeout_seconds: float | None = None,
        details: dict[str, Any] | None = None,
    ):
        super().__init__(message, provider=provider, model=model, details=details)
        self.timeout_seconds = timeout_seconds


class CircuitOpenError(AgentiCraftError):
    """Circuit breaker is open, rejecting requests."""

    def __init__(
        self,
        message: str,
        *,
        provider: str | None = None,
        details: dict[str, Any] | None = None,
    ):
        super().__init__(message, details=details)
        self.provider = provider


class ConfigError(AgentiCraftError):
    """Configuration error."""

    def __init__(
        self,
        message: str,
        *,
        field: str | None = None,
        value: Any = None,
        details: dict[str, Any] | None = None,
    ):
        super().__init__(message, details=details)
        self.field = field
        self.value = value


class QuotaExceededError(AgentiCraftError):
    """Quota exceeded."""

    def __init__(
        self,
        message: str,
        *,
        tenant_id: str | None = None,
        resource: str | None = None,
        limit: int | None = None,
        current: int | None = None,
        details: dict[str, Any] | None = None,
    ):
        super().__init__(message, details=details)
        self.tenant_id = tenant_id
        self.resource = resource
        self.limit = limit
        self.current = current


class OrchestrationError(AgentiCraftError):
    """Orchestration error -- all providers failed."""

    def __init__(
        self,
        message: str,
        *,
        strategy: str | None = None,
        providers_tried: list[str] | None = None,
        errors: list[Exception] | None = None,
        details: dict[str, Any] | None = None,
    ):
        super().__init__(message, details=details)
        self.strategy = strategy
        self.providers_tried = providers_tried or []
        self.errors = errors or []


class NoProvidersAvailableError(OrchestrationError):
    """No providers available for the request."""


__all__ = [
    "AgentiCraftError",
    "ProviderError",
    "RateLimitError",
    "AuthenticationError",
    "ModelNotFoundError",
    "ContentFilterError",
    "TimeoutError",
    "CircuitOpenError",
    "ConfigError",
    "QuotaExceededError",
    "OrchestrationError",
    "NoProvidersAvailableError",
]
