"""Exception hierarchy for MCPGateway SDK."""

from __future__ import annotations

from typing import Any, Protocol


class GatewayError(Exception):
    """Base exception for all MCPGateway API errors."""

    def __init__(self, status_code: int, message: str) -> None:
        self.status_code = status_code
        self.message = message
        super().__init__(f"[{status_code}] {message}")


class AuthError(GatewayError):
    """Raised on HTTP 401 Unauthorized."""

    def __init__(self, message: str = "Unauthorized") -> None:
        super().__init__(status_code=401, message=message)


class ForbiddenError(GatewayError):
    """Raised on HTTP 403 Forbidden."""

    def __init__(self, message: str = "Forbidden") -> None:
        super().__init__(status_code=403, message=message)


class NotFoundError(GatewayError):
    """Raised on HTTP 404 Not Found."""

    def __init__(self, message: str = "Not found") -> None:
        super().__init__(status_code=404, message=message)


class ConflictError(GatewayError):
    """Raised on HTTP 409 Conflict."""

    def __init__(self, message: str = "Conflict") -> None:
        super().__init__(status_code=409, message=message)


class ValidationError(GatewayError):
    """Raised on HTTP 422 Unprocessable Entity."""

    def __init__(self, message: str = "Validation error") -> None:
        super().__init__(status_code=422, message=message)


class RateLimitError(GatewayError):
    """Raised on HTTP 429 Too Many Requests."""

    def __init__(self, message: str = "Rate limited") -> None:
        super().__init__(status_code=429, message=message)


class _ErrorFactory(Protocol):
    """Callable that creates a GatewayError from a message string."""

    def __call__(self, message: str) -> GatewayError: ...


_STATUS_MAP: dict[int, _ErrorFactory] = {
    401: AuthError,
    403: ForbiddenError,
    404: NotFoundError,
    409: ConflictError,
    422: ValidationError,
    429: RateLimitError,
}


def _extract_message(body: dict[str, Any]) -> str:
    """Extract a human-readable error message from an API response body."""
    if "detail" in body:
        detail = body["detail"]
        if isinstance(detail, str):
            return detail
        if isinstance(detail, dict) and "message" in detail:
            return str(detail["message"])
        return str(detail)
    if "error" in body and isinstance(body["error"], dict):
        msg: str = body["error"].get("message", str(body["error"]))
        return msg
    return str(body)


def error_from_response(status_code: int, body: dict[str, Any]) -> GatewayError:
    """Create the appropriate exception from an HTTP status code and response body."""
    message = _extract_message(body)
    cls = _STATUS_MAP.get(status_code)
    if cls is not None:
        return cls(message)
    return GatewayError(status_code=status_code, message=message)
