from typing import Optional


class CacheError(Exception):
    """Base exception for cache-related errors"""
    pass


class CacheFullError(CacheError):
    """Exception raised when cache is full"""
    pass


class CacheNotFoundError(CacheError):
    """Exception raised when cache entry is not found"""
    pass


class CacheExpiredError(CacheError):
    """Exception raised when cache entry is expired"""
    pass


class ModelNotFoundError(Exception):
    """Exception raised when model is not found"""
    pass


class ProviderError(Exception):
    """Exception raised for provider-related errors"""
    def __init__(self, message: str, provider: Optional[str] = None, status_code: Optional[int] = None):
        self.provider = provider
        self.status_code = status_code
        super().__init__(f"[{provider}] {message}" if provider else message)


class AuthenticationError(Exception):
    """Exception raised for authentication errors"""
    def __init__(self, message: str, provider: str):
        self.provider = provider
        super().__init__(f"[{provider}] Authentication failed: {message}")


class RateLimitError(Exception):
    """Exception raised when rate limit is exceeded"""
    def __init__(self, message: str, provider: str, retry_after: Optional[int] = None):
        self.provider = provider
        self.retry_after = retry_after
        super().__init__(f"[{provider}] Rate limit exceeded: {message}")


class InvalidRequestError(Exception):
    """Exception raised for invalid requests"""
    def __init__(self, message: str, provider: str):
        self.provider = provider
        super().__init__(f"[{provider}] Invalid request: {message}")


class ConnectionError(Exception):
    """Exception raised for connection errors"""
    def __init__(self, message: str, provider: str):
        self.provider = provider
        super().__init__(f"[{provider}] Connection error: {message}")


class OperationTimeoutError(Exception):
    """Exception raised when operation times out"""
    def __init__(self, message: str, provider: str):
        self.provider = provider
        super().__init__(f"[{provider}] Timeout error: {message}")