from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from ._types.common import ApiErrorBody, ErrorType


class ShipMailError(Exception):
    status: int | None
    type: ErrorType | None
    request_id: str | None
    retryable: bool

    def __init__(
        self,
        message: str,
        *,
        status: int | None = None,
        type: ErrorType | None = None,
        request_id: str | None = None,
        retryable: bool = False,
    ) -> None:
        super().__init__(message)
        self.status = status
        self.type = type
        self.request_id = request_id
        self.retryable = retryable


class AuthenticationError(ShipMailError):
    def __init__(self, message: str, request_id: str | None = None) -> None:
        super().__init__(
            message,
            status=401,
            type="authentication_error",
            request_id=request_id,
            retryable=False,
        )


class AuthorizationError(ShipMailError):
    def __init__(self, message: str, request_id: str | None = None) -> None:
        super().__init__(
            message,
            status=403,
            type="authorization_error",
            request_id=request_id,
            retryable=False,
        )


class ValidationError(ShipMailError):
    details: list[dict[str, str]] | None

    def __init__(
        self,
        message: str,
        *,
        request_id: str | None = None,
        details: list[dict[str, str]] | None = None,
    ) -> None:
        super().__init__(
            message,
            status=422,
            type="validation_error",
            request_id=request_id,
            retryable=False,
        )
        self.details = details


class QuotaExceededError(ShipMailError):
    def __init__(self, message: str, request_id: str | None = None) -> None:
        super().__init__(
            message,
            status=403,
            type="quota_exceeded",
            request_id=request_id,
            retryable=False,
        )


class NotFoundError(ShipMailError):
    def __init__(self, message: str, request_id: str | None = None) -> None:
        super().__init__(
            message,
            status=404,
            type="not_found",
            request_id=request_id,
            retryable=False,
        )


class RateLimitError(ShipMailError):
    retry_after: float | None

    def __init__(
        self,
        message: str,
        *,
        request_id: str | None = None,
        retry_after: float | None = None,
    ) -> None:
        super().__init__(
            message,
            status=429,
            type="rate_limit_error",
            request_id=request_id,
            retryable=True,
        )
        self.retry_after = retry_after


class ConflictError(ShipMailError):
    def __init__(self, message: str, request_id: str | None = None) -> None:
        super().__init__(
            message,
            status=409,
            type="conflict",
            request_id=request_id,
            retryable=False,
        )


class InternalServerError(ShipMailError):
    def __init__(self, message: str, request_id: str | None = None) -> None:
        super().__init__(
            message,
            status=500,
            type="internal_error",
            request_id=request_id,
            retryable=True,
        )


class APIConnectionError(ShipMailError):
    def __init__(self, message: str) -> None:
        super().__init__(message, retryable=True)


class WebhookVerificationError(ShipMailError):
    def __init__(self, message: str) -> None:
        super().__init__(message, retryable=False)


def map_error_from_response(
    status: int,
    body: ApiErrorBody,
    request_id: str | None = None,
) -> ShipMailError:
    error = body["error"]
    rid = request_id or error.get("request_id")

    error_type = error.get("type", "")
    message = error.get("message", "")

    if error_type == "authentication_error":
        return AuthenticationError(message, rid)
    if error_type == "authorization_error":
        return AuthorizationError(message, rid)
    if error_type == "quota_exceeded":
        return QuotaExceededError(message, rid)
    if error_type == "validation_error":
        details = error.get("details")
        return ValidationError(message, request_id=rid, details=details)
    if error_type == "not_found":
        return NotFoundError(message, rid)
    if error_type == "rate_limit_error":
        retry_after = error.get("retry_after")
        return RateLimitError(message, request_id=rid, retry_after=retry_after)
    if error_type == "conflict":
        return ConflictError(message, rid)
    if error_type == "internal_error":
        return InternalServerError(message, rid)

    return ShipMailError(
        message,
        status=status,
        type=error_type if error_type else None,
        request_id=rid,
        retryable=status >= 500,
    )
