"""Custom exceptions for the storage SDK."""

from typing import Any, Union


class StorageError(Exception):
    """Base exception for all storage errors."""

    def __init__(
        self,
        message: str,
        *,
        code: Union[str, None] = None,
        status_code: Union[int, None] = None,
        details: Union[dict[str, Any], None] = None,
    ) -> None:
        super().__init__(message)
        self.message = message
        self.code = code
        self.status_code = status_code
        self.details = details or {}

    def __repr__(self) -> str:
        return f"{self.__class__.__name__}(message={self.message!r}, code={self.code!r})"


class AuthenticationError(StorageError):
    """Raised when authentication fails."""

    def __init__(self, message: str = "Authentication failed") -> None:
        super().__init__(message, code="AUTH_ERROR", status_code=401)


class AuthorizationError(StorageError):
    """Raised when user lacks permission."""

    def __init__(self, message: str = "Permission denied") -> None:
        super().__init__(message, code="FORBIDDEN", status_code=403)


class NotFoundError(StorageError):
    """Raised when resource is not found."""

    def __init__(self, resource: str = "Resource") -> None:
        super().__init__(f"{resource} not found", code="NOT_FOUND", status_code=404)


class UploadError(StorageError):
    """Raised when upload fails."""

    def __init__(
        self,
        message: str,
        *,
        session_id: Union[str, None] = None,
        part_number: Union[int, None] = None,
    ) -> None:
        super().__init__(message, code="UPLOAD_ERROR")
        self.session_id = session_id
        self.part_number = part_number


class ValidationError(StorageError):
    """Raised for validation failures."""

    def __init__(self, message: str, field: Union[str, None] = None) -> None:
        super().__init__(message, code="VALIDATION_ERROR", status_code=400)
        self.field = field


class QuotaExceededError(StorageError):
    """Raised when storage quota is exceeded."""

    def __init__(self, message: str = "Storage quota exceeded") -> None:
        super().__init__(message, code="QUOTA_EXCEEDED", status_code=413)


class FileTooLargeError(StorageError):
    """Raised when file exceeds size limit."""

    def __init__(self, max_size: int, actual_size: int) -> None:
        super().__init__(
            f"File size {actual_size} bytes exceeds maximum {max_size} bytes",
            code="FILE_TOO_LARGE",
            status_code=413,
        )
        self.max_size = max_size
        self.actual_size = actual_size


class InvalidFileTypeError(StorageError):
    """Raised for disallowed file types."""

    def __init__(self, filename: str) -> None:
        super().__init__(
            f"File type not allowed: {filename}",
            code="INVALID_FILE_TYPE",
            status_code=400,
        )
        self.filename = filename


class RetryableError(StorageError):
    """Raised for errors that can be retried."""

    def __init__(self, message: str, retry_after: Union[int, None] = None) -> None:
        super().__init__(message, code="RETRYABLE_ERROR")
        self.retry_after = retry_after
