"""
Enhanced Exception Handling for Connectors
Comprehensive exception hierarchy for better error management
"""

from typing import Optional, Dict, Any
import logging


class ConnectorError(Exception):
    """Base exception for all connector-related errors"""
    
    def __init__(
        self, 
        message: str, 
        error_code: Optional[str] = None,
        details: Optional[Dict[str, Any]] = None,
        original_exception: Optional[Exception] = None
    ):
        super().__init__(message)
        self.message = message
        self.error_code = error_code
        self.details = details or {}
        self.original_exception = original_exception
        self.logger = logging.getLogger(self.__class__.__name__)
    
    def __str__(self) -> str:
        error_str = f"{self.message}"
        if self.error_code:
            error_str += f" (Code: {self.error_code})"
        if self.details:
            error_str += f" | Details: {self.details}"
        return error_str
    
    def log_error(self, level: int = logging.ERROR):
        """Log the error with context"""
        self.logger.log(level, str(self), exc_info=self.original_exception)


class AuthenticationError(ConnectorError):
    """Raised when authentication fails"""
    pass


class ConfigurationError(ConnectorError):
    """Raised when configuration is invalid"""
    pass


class NetworkError(ConnectorError):
    """Raised when network operations fail"""
    pass


class RateLimitError(ConnectorError):
    """Raised when rate limits are exceeded"""
    
    def __init__(
        self, 
        message: str, 
        retry_after: Optional[int] = None,
        **kwargs
    ):
        super().__init__(message, **kwargs)
        self.retry_after = retry_after


class APIError(ConnectorError):
    """Raised when API operations fail"""
    
    def __init__(
        self, 
        message: str, 
        status_code: Optional[int] = None,
        response_data: Optional[Dict[str, Any]] = None,
        **kwargs
    ):
        super().__init__(message, **kwargs)
        self.status_code = status_code
        self.response_data = response_data or {}


class ValidationError(ConnectorError):
    """Raised when data validation fails"""
    pass


class TimeoutError(ConnectorError):
    """Raised when operations timeout"""
    pass


class ResourceNotFoundError(ConnectorError):
    """Raised when requested resource is not found"""
    pass


class PermissionError(ConnectorError):
    """Raised when user lacks required permissions"""
    pass


class QuotaExceededError(ConnectorError):
    """Raised when API quota is exceeded"""
    pass


class ServiceUnavailableError(ConnectorError):
    """Raised when the service is temporarily unavailable"""
    pass


class DataProcessingError(ConnectorError):
    """Raised when data processing fails"""
    pass


class CacheError(ConnectorError):
    """Raised when cache operations fail"""
    pass


class RetryExhaustedError(ConnectorError):
    """Raised when retry attempts are exhausted"""
    
    def __init__(
        self, 
        message: str, 
        attempts: int,
        last_error: Optional[Exception] = None,
        **kwargs
    ):
        super().__init__(message, original_exception=last_error, **kwargs)
        self.attempts = attempts


def handle_api_error(response, operation: str = "API call") -> None:
    """Handle API response errors appropriately"""
    status_code = response.status_code
    
    if status_code == 401:
        raise AuthenticationError(
            f"Authentication failed for {operation}",
            error_code="AUTH_401",
            status_code=status_code,
            response_data=response.json() if response.content else {}
        )
    elif status_code == 403:
        raise PermissionError(
            f"Permission denied for {operation}",
            error_code="PERM_403",
            status_code=status_code,
            response_data=response.json() if response.content else {}
        )
    elif status_code == 404:
        raise ResourceNotFoundError(
            f"Resource not found for {operation}",
            error_code="NOTFOUND_404",
            status_code=status_code,
            response_data=response.json() if response.content else {}
        )
    elif status_code == 429:
        retry_after = response.headers.get('Retry-After')
        raise RateLimitError(
            f"Rate limit exceeded for {operation}",
            error_code="RATE_429",
            status_code=status_code,
            retry_after=int(retry_after) if retry_after else None,
            response_data=response.json() if response.content else {}
        )
    elif status_code >= 500:
        raise ServiceUnavailableError(
            f"Service unavailable for {operation}",
            error_code="SERVICE_5XX",
            status_code=status_code,
            response_data=response.json() if response.content else {}
        )
    else:
        raise APIError(
            f"API error for {operation}",
            error_code=f"API_{status_code}",
            status_code=status_code,
            response_data=response.json() if response.content else {}
        )
