"""
AgniPod SDK — Exception Hierarchy
===================================

Structured exceptions with HTTP status codes, error types,
and original response data for advanced error handling.

All exceptions inherit from ``AgniPodError`` so you can catch everything
with a single ``except AgniPodError``.
"""

from typing import Optional, Any


class AgniPodError(Exception):
    """Base exception for all AgniPod SDK errors."""

    def __init__(
        self,
        message: str,
        *,
        status_code: Optional[int] = None,
        error_type: Optional[str] = None,
        response: Any = None,
    ):
        super().__init__(message)
        self.message = message
        self.status_code = status_code
        self.error_type = error_type
        self.response = response

    def __repr__(self) -> str:
        parts = [f"AgniPodError({self.message!r}"]
        if self.status_code:
            parts.append(f"status_code={self.status_code}")
        if self.error_type:
            parts.append(f"type={self.error_type!r}")
        return ", ".join(parts) + ")"


# ── Authentication ───────────────────────────────────────────────────────

class AuthenticationError(AgniPodError):
    """API key is missing, invalid, or revoked (HTTP 401)."""


class InsufficientBalanceError(AgniPodError):
    """Wallet balance is too low to process the request (HTTP 402)."""


class PermissionDeniedError(AgniPodError):
    """Access denied — wallet inactive or similar (HTTP 403)."""


# ── Client-side ──────────────────────────────────────────────────────────

class BadRequestError(AgniPodError):
    """The request was malformed or invalid (HTTP 400)."""


class NotFoundError(AgniPodError):
    """The requested resource was not found (HTTP 404)."""


class ValidationError(AgniPodError):
    """Request payload failed client-side validation (never sent to server)."""


class ConfigurationError(AgniPodError):
    """SDK misconfiguration (e.g. missing API key, bad base URL)."""


# ── Server-side ──────────────────────────────────────────────────────────

class ServerError(AgniPodError):
    """AgniPod server returned an unexpected error (HTTP 5xx)."""


class ServiceUnavailableError(AgniPodError):
    """No GPU workers available — retry later (HTTP 503)."""


class RateLimitError(AgniPodError):
    """Too many requests — back off and retry (HTTP 429)."""


# ── Network ──────────────────────────────────────────────────────────────

class APIConnectionError(AgniPodError):
    """Could not reach the AgniPod API."""


class APITimeoutError(AgniPodError):
    """Request timed out."""


class StreamError(AgniPodError):
    """Error occurred during SSE streaming."""


# ── Mapping helper ──────────────────────────────────────────────────────

_STATUS_MAP = {
    400: BadRequestError,
    401: AuthenticationError,
    402: InsufficientBalanceError,
    403: PermissionDeniedError,
    404: NotFoundError,
    429: RateLimitError,
    503: ServiceUnavailableError,
}


def raise_for_status(status_code: int, body: Any = None):
    """Raise the correct typed exception based on HTTP status code."""
    if 200 <= status_code < 300:
        return

    message = "Request failed"
    error_type = None

    if isinstance(body, dict):
        err = body.get("error", body.get("detail", body.get("message", "")))
        if isinstance(err, dict):
            message = err.get("message", message)
            error_type = err.get("type") or err.get("code")
        elif isinstance(err, str) and err:
            message = err

    exc_class = _STATUS_MAP.get(
        status_code,
        ServerError if status_code >= 500 else AgniPodError,
    )
    raise exc_class(
        message,
        status_code=status_code,
        error_type=error_type,
        response=body,
    )
