"""Custom error classes for the Undetecta client."""

from __future__ import annotations

from typing import Any


class UndetectaError(Exception):
    """Base error class for all Undetecta client errors."""

    def __init__(
        self,
        code: str,
        message: str,
        status_code: int | None = None,
    ) -> None:
        """Initialize the error.

        Args:
            code: Error code
            message: Error message
            status_code: HTTP status code if applicable
        """
        self.code = code
        self.message = message
        self.status_code = status_code
        super().__init__(message)

    def __repr__(self) -> str:
        """Return string representation of the error."""
        return f"{self.__class__.__name__}(code={self.code!r}, message={self.message!r})"


class BadRequestError(UndetectaError):
    """Error raised when the API returns a 400 status."""

    def __init__(self, code: str, message: str) -> None:
        """Initialize the error.

        Args:
            code: Error code
            message: Error message
        """
        super().__init__(code, message, 400)


class AuthenticationError(UndetectaError):
    """Error raised when authentication fails."""

    def __init__(self, message: str = "Authentication failed") -> None:
        """Initialize the error.

        Args:
            message: Error message
        """
        super().__init__("UNAUTHORIZED", message, 401)


class ApiKeyError(UndetectaError):
    """Error raised when the API key is missing or invalid."""

    def __init__(self, message: str = "Invalid or missing API key") -> None:
        """Initialize the error.

        Args:
            message: Error message
        """
        super().__init__("INVALID_API_KEY", message, 401)


class RateLimitError(UndetectaError):
    """Error raised when the rate limit is exceeded."""

    def __init__(self, message: str = "Rate limit exceeded") -> None:
        """Initialize the error.

        Args:
            message: Error message
        """
        super().__init__("RATE_LIMIT_EXCEEDED", message, 429)


class NotFoundError(UndetectaError):
    """Error raised when a resource is not found."""

    def __init__(self, message: str = "Resource not found") -> None:
        """Initialize the error.

        Args:
            message: Error message
        """
        super().__init__("NOT_FOUND", message, 404)


class ServerError(UndetectaError):
    """Error raised when the API returns a 500+ status."""

    def __init__(self, code: str, message: str) -> None:
        """Initialize the error.

        Args:
            code: Error code
            message: Error message
        """
        super().__init__(code, message, 500)


class NetworkError(UndetectaError):
    """Error raised when a network request fails."""

    def __init__(self, message: str) -> None:
        """Initialize the error.

        Args:
            message: Error message
        """
        super().__init__("NETWORK_ERROR", message)


class ValidationError(UndetectaError):
    """Error raised when request validation fails."""

    def __init__(self, message: str) -> None:
        """Initialize the error.

        Args:
            message: Error message
        """
        super().__init__("VALIDATION_ERROR", message, 400)


class TimeoutError(UndetectaError):
    """Error raised when a request times out."""

    def __init__(self, message: str = "Request timed out") -> None:
        """Initialize the error.

        Args:
            message: Error message
        """
        super().__init__("TIMEOUT", message)


class HttpError(UndetectaError):
    """HTTP error with status code and response data."""

    def __init__(self, message: str, status_code: int, data: Any = None) -> None:
        """Initialize the error.

        Args:
            message: Error message
            status_code: HTTP status code
            data: Response data
        """
        self.data = data
        super().__init__("HTTP_ERROR", message, status_code)


def parse_error_response(data: Any) -> UndetectaError:
    """Parse an error response from the API and return the appropriate error.

    Args:
        data: Response data from the API

    Returns:
        Appropriate error instance
    """
    if (
        isinstance(data, dict)
        and "error" in data
        and isinstance(data["error"], dict)
    ):
        error_dict: dict[str, Any] = data["error"]
        code: str = error_dict.get("code", "UNKNOWN_ERROR")  # type: ignore[assignment]
        message: str = error_dict.get("message", "An unknown error occurred")  # type: ignore[assignment]

        if code in ("UNAUTHORIZED", "INVALID_API_KEY"):
            return ApiKeyError(message)
        if code == "RATE_LIMIT_EXCEEDED":
            return RateLimitError(message)
        if code == "NOT_FOUND":
            return NotFoundError(message)
        if code == "VALIDATION_ERROR":
            return ValidationError(message)
        return UndetectaError(code, message)

    return UndetectaError("UNKNOWN_ERROR", "An unknown error occurred")


def is_retryable_status(status: int) -> bool:
    """Check if a status code is retryable.

    Args:
        status: HTTP status code

    Returns:
        True if retryable, False otherwise
    """
    return (
        status == 408  # Request Timeout
        or status == 429  # Too Many Requests
        or (500 <= status < 600)  # Server errors
    )
