"""HAX SDK exception classes."""

from __future__ import annotations

from typing import Any


class HaxError(Exception):
    """Base exception for all HAX SDK errors."""

    def __init__(self, message: str, details: dict[str, Any] | None = None) -> None:
        super().__init__(message)
        self.message = message
        self.details = details or {}

    def __str__(self) -> str:
        if self.details:
            return f"{self.message}: {self.details}"
        return self.message


class AuthenticationError(HaxError):
    """Raised when API authentication fails (401)."""

    pass


class NotFoundError(HaxError):
    """Raised when a resource is not found (404)."""

    pass


class ValidationError(HaxError):
    """Raised when request validation fails (422)."""

    pass


class RateLimitError(HaxError):
    """Raised when rate limited (429).

    Attributes:
        retry_after: Seconds to wait before retrying (from Retry-After header).
        limit: The maximum number of notifications allowed per month.
        used: The number of notifications used this month.
        remaining: The number of notifications remaining this month.
        resets_at: ISO timestamp when the rate limit resets (start of next month).
    """

    def __init__(
        self,
        message: str = "Rate limit exceeded",
        retry_after: int | None = None,
        details: dict[str, Any] | None = None,
    ) -> None:
        super().__init__(message, details)
        self.retry_after = retry_after
        # Extract rate limit details from response
        self.limit: int | None = details.get("limit") if details else None
        self.used: int | None = details.get("used") if details else None
        self.remaining: int | None = details.get("remaining") if details else None
        self.resets_at: str | None = details.get("resetsAt") if details else None


class ServerError(HaxError):
    """Raised for server errors (5xx)."""

    def __init__(
        self,
        message: str = "Server error",
        status_code: int = 500,
        details: dict[str, Any] | None = None,
    ) -> None:
        super().__init__(message, details)
        self.status_code = status_code


class DecryptionError(HaxError):
    """Raised when decryption fails (wrong key, corrupted data, invalid format)."""

    pass
