"""Curvestone SDK exceptions."""

from __future__ import annotations


class CurvestoneError(Exception):
    """Base exception for all Curvestone SDK errors."""

    def __init__(
        self,
        message: str,
        *,
        status_code: int | None = None,
        code: str | None = None,
        param: str | None = None,
        request_id: str | None = None,
    ) -> None:
        super().__init__(message)
        self.message = message
        self.status_code = status_code
        self.code = code
        self.param = param
        self.request_id = request_id

    def __repr__(self) -> str:
        return f"{self.__class__.__name__}(message={self.message!r}, code={self.code!r})"


class AuthenticationError(CurvestoneError):
    """Raised when the API key is invalid or missing (HTTP 401)."""


class PermissionDeniedError(CurvestoneError):
    """Raised when the API key lacks required permissions (HTTP 403)."""


class NotFoundError(CurvestoneError):
    """Raised when the requested resource does not exist (HTTP 404)."""


class BadRequestError(CurvestoneError):
    """Raised when the request is malformed (HTTP 400)."""


class RateLimitError(CurvestoneError):
    """Raised when the rate limit is exceeded (HTTP 429)."""


class InternalServerError(CurvestoneError):
    """Raised when the API returns a server error (HTTP 5xx)."""


class TimeoutError(CurvestoneError):
    """Raised when a polling operation exceeds the timeout."""


_STATUS_CODE_MAP: dict[int, type[CurvestoneError]] = {
    400: BadRequestError,
    401: AuthenticationError,
    403: PermissionDeniedError,
    404: NotFoundError,
    429: RateLimitError,
}


def _raise_for_status(status_code: int, body: dict | None) -> None:
    """Raise the appropriate exception for an error HTTP response."""
    if status_code < 400:
        return

    error = body.get("error", {}) if body else {}
    message = error.get("message") or f"HTTP {status_code}"
    code = error.get("code")
    param = error.get("param")
    request_id = body.get("request_id") if body else None

    exc_class = _STATUS_CODE_MAP.get(status_code, InternalServerError)
    raise exc_class(
        message,
        status_code=status_code,
        code=code,
        param=param,
        request_id=request_id,
    )
