"""Custom exceptions for ZenOTC SDK."""

from __future__ import annotations

from typing import Any, Optional


class ZenOTCError(Exception):
    """Base exception for all ZenOTC SDK errors."""

    def __init__(
        self,
        message: str,
        status_code: Optional[int] = None,
        error_code: Optional[str] = None,
        details: Optional[dict[str, Any]] = None,
    ) -> None:
        super().__init__(message)
        self.message = message
        self.status_code = status_code
        self.error_code = error_code
        self.details = details or {}

    def __str__(self) -> str:
        parts = [self.message]
        if self.error_code:
            parts.append(f"[{self.error_code}]")
        if self.status_code:
            parts.append(f"(HTTP {self.status_code})")
        return " ".join(parts)


class AuthenticationError(ZenOTCError):
    """Raised when authentication fails."""

    def __init__(
        self,
        message: str = "Authentication failed",
        status_code: Optional[int] = 401,
        error_code: Optional[str] = "AUTH_FAILED",
        details: Optional[dict[str, Any]] = None,
    ) -> None:
        super().__init__(message, status_code, error_code, details)


class RateLimitError(ZenOTCError):
    """Raised when rate limit is exceeded."""

    def __init__(
        self,
        message: str = "Rate limit exceeded",
        retry_after: Optional[float] = None,
        status_code: Optional[int] = 429,
        error_code: Optional[str] = "RATE_LIMIT_EXCEEDED",
        details: Optional[dict[str, Any]] = None,
    ) -> None:
        super().__init__(message, status_code, error_code, details)
        self.retry_after = retry_after


class ValidationError(ZenOTCError):
    """Raised when request validation fails."""

    def __init__(
        self,
        message: str = "Validation failed",
        field_errors: Optional[dict[str, str]] = None,
        status_code: Optional[int] = 400,
        error_code: Optional[str] = "VALIDATION_ERROR",
        details: Optional[dict[str, Any]] = None,
    ) -> None:
        super().__init__(message, status_code, error_code, details)
        self.field_errors = field_errors or {}


class InsufficientFundsError(ZenOTCError):
    """Raised when there are insufficient funds for an operation."""

    def __init__(
        self,
        message: str = "Insufficient funds",
        required: Optional[float] = None,
        available: Optional[float] = None,
        asset: Optional[str] = None,
        status_code: Optional[int] = 400,
        error_code: Optional[str] = "INSUFFICIENT_FUNDS",
        details: Optional[dict[str, Any]] = None,
    ) -> None:
        super().__init__(message, status_code, error_code, details)
        self.required = required
        self.available = available
        self.asset = asset


class OrderNotFoundError(ZenOTCError):
    """Raised when an order is not found."""

    def __init__(
        self,
        order_id: str,
        message: Optional[str] = None,
        status_code: Optional[int] = 404,
        error_code: Optional[str] = "ORDER_NOT_FOUND",
        details: Optional[dict[str, Any]] = None,
    ) -> None:
        message = message or f"Order not found: {order_id}"
        super().__init__(message, status_code, error_code, details)
        self.order_id = order_id


class QuoteNotFoundError(ZenOTCError):
    """Raised when a quote is not found."""

    def __init__(
        self,
        quote_id: str,
        message: Optional[str] = None,
        status_code: Optional[int] = 404,
        error_code: Optional[str] = "QUOTE_NOT_FOUND",
        details: Optional[dict[str, Any]] = None,
    ) -> None:
        message = message or f"Quote not found: {quote_id}"
        super().__init__(message, status_code, error_code, details)
        self.quote_id = quote_id


class ConnectionError(ZenOTCError):
    """Raised when connection to API fails."""

    def __init__(
        self,
        message: str = "Connection failed",
        status_code: Optional[int] = None,
        error_code: Optional[str] = "CONNECTION_ERROR",
        details: Optional[dict[str, Any]] = None,
    ) -> None:
        super().__init__(message, status_code, error_code, details)


class TimeoutError(ZenOTCError):
    """Raised when a request times out."""

    def __init__(
        self,
        message: str = "Request timed out",
        status_code: Optional[int] = None,
        error_code: Optional[str] = "TIMEOUT",
        details: Optional[dict[str, Any]] = None,
    ) -> None:
        super().__init__(message, status_code, error_code, details)


class ServerError(ZenOTCError):
    """Raised when server returns 5xx error."""

    def __init__(
        self,
        message: str = "Server error",
        status_code: Optional[int] = 500,
        error_code: Optional[str] = "SERVER_ERROR",
        details: Optional[dict[str, Any]] = None,
    ) -> None:
        super().__init__(message, status_code, error_code, details)


class RiskCheckFailedError(ZenOTCError):
    """Raised when a pre-trade risk check fails."""

    def __init__(
        self,
        message: str = "Risk check failed",
        reason: Optional[str] = None,
        limit_type: Optional[str] = None,
        current_value: Optional[float] = None,
        limit_value: Optional[float] = None,
        status_code: Optional[int] = 400,
        error_code: Optional[str] = "RISK_CHECK_FAILED",
        details: Optional[dict[str, Any]] = None,
    ) -> None:
        super().__init__(message, status_code, error_code, details)
        self.reason = reason
        self.limit_type = limit_type
        self.current_value = current_value
        self.limit_value = limit_value
