"""
Exception types for the Kronical SDK.

Maps HTTP error codes to typed exceptions for structured error handling.
"""
from typing import Optional


class KronicalAPIError(Exception):
    """Base exception for all Kronical API errors."""

    def __init__(
        self,
        message: str,
        status_code: int,
        error_code: Optional[str] = None,
        request_id: Optional[str] = None,
        retry_after: Optional[int] = None,
    ):
        self.status_code = status_code
        self.error_code = error_code
        self.request_id = request_id
        self.retry_after = retry_after
        super().__init__(message)


class AuthenticationError(KronicalAPIError):
    """401 — Invalid, expired, or revoked API key."""
    pass


class ForbiddenError(KronicalAPIError):
    """403 — Missing scope or IP not whitelisted."""
    pass


class NotFoundError(KronicalAPIError):
    """404 — Resource not found."""
    pass


class ValidationError(KronicalAPIError):
    """422 — Request validation failed."""
    pass


class RateLimitError(KronicalAPIError):
    """429 — Rate limit, quota, or concurrency limit exceeded."""
    pass


class ServiceUnavailableError(KronicalAPIError):
    """503 — Service temporarily unavailable."""
    pass


# Maps error codes to exception classes
_ERROR_MAP = {
    401: AuthenticationError,
    403: ForbiddenError,
    404: NotFoundError,
    422: ValidationError,
    429: RateLimitError,
    503: ServiceUnavailableError,
}


def raise_for_status(status_code: int, body: dict) -> None:
    """Parse an error response and raise the appropriate exception."""
    error = body.get("error", {})
    message = error.get("message", f"HTTP {status_code}")
    error_code = error.get("code")
    request_id = error.get("request_id")
    retry_after = error.get("retry_after")

    exc_class = _ERROR_MAP.get(status_code, KronicalAPIError)
    raise exc_class(
        message=message,
        status_code=status_code,
        error_code=error_code,
        request_id=request_id,
        retry_after=retry_after,
    )
