"""
HS Mail SDK — Python exception classes.
All exceptions inherit from HsMailError.
"""


class HsMailError(Exception):
    """Base exception for all HS Mail API errors."""

    def __init__(
        self,
        message: str,
        code: str = "UNKNOWN_ERROR",
        http_status: int = 500,
        response_data: dict | None = None,
    ):
        super().__init__(message)
        self.code = code
        self.http_status = http_status
        self.response_data = response_data or {}

    def __str__(self) -> str:
        return f"[{self.code}] {self.args[0]} (HTTP {self.http_status})"


class AuthenticationError(HsMailError):
    """Raised for authentication failures: invalid key, banned/suspended accounts."""
    pass


class RateLimitError(HsMailError):
    """Raised when the rate limit (100 req/min) is exceeded."""

    def __init__(self, message: str = "Rate limit exceeded. Wait 60s."):
        super().__init__(message, "RATE_LIMIT_EXCEEDED", 429)


class NotFoundError(HsMailError):
    """Raised when a requested resource is not found."""
    pass


class InsufficientBalanceError(HsMailError):
    """Raised when the account does not have enough BDT balance."""

    def __init__(self, message: str = "Insufficient balance."):
        super().__init__(message, "INSUFFICIENT_BALANCE", 400)


class ValidationError(HsMailError):
    """Raised for invalid input parameters, out-of-stock, or closed orders."""
    pass


_AUTH_CODES = {
    "MISSING_API_KEY", "INVALID_API_KEY", "ACCOUNT_DELETED",
    "ACCOUNT_BANNED", "ACCOUNT_SUSPENDED", "ACCOUNT_UNVERIFIED",
    "IP_NOT_WHITELISTED",
}
_VALIDATION_CODES = {
    "INVALID_PARAMETERS", "OUT_OF_STOCK", "ORDER_CLOSED",
    "WARRANTY_EXPIRED", "ORDER_NOT_COMPLETED",
}


def create_typed_error(code: str, message: str, status: int, data: dict) -> HsMailError:
    """Factory: map an API error code to the correct typed exception."""
    if code in _AUTH_CODES:
        return AuthenticationError(message, code, status, data)
    if code == "RATE_LIMIT_EXCEEDED":
        return RateLimitError(message)
    if code == "NOT_FOUND":
        return NotFoundError(message, code, status, data)
    if code == "INSUFFICIENT_BALANCE":
        return InsufficientBalanceError(message)
    if code in _VALIDATION_CODES:
        return ValidationError(message, code, status, data)
    return HsMailError(message, code, status, data)
