"""
Custom Exception Classes

Provides specific exception types for better error handling and reporting.
Replaces broad 'except Exception' handlers with specific, meaningful exceptions.
"""

from typing import Optional, Dict, Any
from fastapi import HTTPException


# ============================================================================
# BASE EXCEPTIONS
# ============================================================================

class MediaDownloaderError(Exception):
    """Base exception for all Media Downloader errors"""

    def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
        self.message = message
        self.details = details or {}
        super().__init__(self.message)

    def to_dict(self) -> Dict[str, Any]:
        return {
            "error": self.__class__.__name__,
            "message": self.message,
            "details": self.details
        }


# ============================================================================
# DATABASE EXCEPTIONS
# ============================================================================

class DatabaseError(MediaDownloaderError):
    """Database operation failed"""
    pass


class DatabaseConnectionError(DatabaseError):
    """Failed to connect to database"""
    pass


class DatabaseQueryError(DatabaseError):
    """Database query failed"""
    pass


class RecordNotFoundError(DatabaseError):
    """Requested record not found in database"""
    pass


# Alias for generic "not found" scenarios
NotFoundError = RecordNotFoundError


class DuplicateRecordError(DatabaseError):
    """Attempted to insert duplicate record"""
    pass


# ============================================================================
# DOWNLOAD EXCEPTIONS
# ============================================================================

class DownloadError(MediaDownloaderError):
    """Download operation failed"""
    pass


class NetworkError(DownloadError):
    """Network request failed"""
    pass


class RateLimitError(DownloadError):
    """Rate limit exceeded"""
    pass


class AuthenticationError(DownloadError):
    """Authentication failed for external service"""
    pass


class PlatformUnavailableError(DownloadError):
    """Platform or service is unavailable"""
    pass


class ContentNotFoundError(DownloadError):
    """Requested content not found on platform"""
    pass


class InvalidURLError(DownloadError):
    """Invalid or malformed URL"""
    pass


# ============================================================================
# FILE OPERATION EXCEPTIONS
# ============================================================================

class FileOperationError(MediaDownloaderError):
    """File operation failed"""
    pass


class MediaFileNotFoundError(FileOperationError):
    """File not found on filesystem"""
    pass


class FileAccessError(FileOperationError):
    """Cannot access file (permissions, etc.)"""
    pass


class FileHashError(FileOperationError):
    """File hash computation failed"""
    pass


class FileMoveError(FileOperationError):
    """Failed to move file"""
    pass


class ThumbnailError(FileOperationError):
    """Thumbnail generation failed"""
    pass


# ============================================================================
# VALIDATION EXCEPTIONS
# ============================================================================

class ValidationError(MediaDownloaderError):
    """Input validation failed"""
    pass


class InvalidParameterError(ValidationError):
    """Invalid parameter value"""
    pass


class MissingParameterError(ValidationError):
    """Required parameter missing"""
    pass


class PathTraversalError(ValidationError):
    """Path traversal attempt detected"""
    pass


# ============================================================================
# AUTHENTICATION/AUTHORIZATION EXCEPTIONS
# ============================================================================

class AuthError(MediaDownloaderError):
    """Authentication or authorization error"""
    pass


class TokenExpiredError(AuthError):
    """Authentication token has expired"""
    pass


class InvalidTokenError(AuthError):
    """Authentication token is invalid"""
    pass


class InsufficientPermissionsError(AuthError):
    """User lacks required permissions"""
    pass


# ============================================================================
# SERVICE EXCEPTIONS
# ============================================================================

class ServiceError(MediaDownloaderError):
    """External service error"""
    pass


class FlareSolverrError(ServiceError):
    """FlareSolverr service error"""
    pass


class RedisError(ServiceError):
    """Redis cache error"""
    pass


class SchedulerError(ServiceError):
    """Scheduler service error"""
    pass


# ============================================================================
# FACE RECOGNITION EXCEPTIONS
# ============================================================================

class FaceRecognitionError(MediaDownloaderError):
    """Face recognition operation failed"""
    pass


class NoFaceDetectedError(FaceRecognitionError):
    """No face detected in image"""
    pass


class FaceEncodingError(FaceRecognitionError):
    """Failed to encode face"""
    pass


# ============================================================================
# HTTP EXCEPTION HELPERS
# ============================================================================

def to_http_exception(error: MediaDownloaderError) -> HTTPException:
    """Convert a MediaDownloaderError to an HTTPException"""

    # Map exception types to HTTP status codes (most-specific subclasses first)
    status_map = {
        # 400 Bad Request (subclasses before parent)
        InvalidParameterError: 400,
        MissingParameterError: 400,
        InvalidURLError: 400,
        ValidationError: 400,

        # 401 Unauthorized (subclasses before parent)
        TokenExpiredError: 401,
        InvalidTokenError: 401,
        AuthenticationError: 401,
        AuthError: 401,

        # 403 Forbidden
        InsufficientPermissionsError: 403,
        PathTraversalError: 403,
        FileAccessError: 403,

        # 404 Not Found
        RecordNotFoundError: 404,
        MediaFileNotFoundError: 404,
        ContentNotFoundError: 404,

        # 409 Conflict
        DuplicateRecordError: 409,

        # 429 Too Many Requests
        RateLimitError: 429,

        # 500 Internal Server Error (subclasses before parent)
        DatabaseConnectionError: 500,
        DatabaseQueryError: 500,
        DatabaseError: 500,

        # 502 Bad Gateway (subclasses before parent)
        FlareSolverrError: 502,
        ServiceError: 502,
        NetworkError: 502,

        # 503 Service Unavailable
        PlatformUnavailableError: 503,
        SchedulerError: 503,
    }

    # Find the most specific matching status code
    status_code = 500  # Default to internal server error
    for exc_type, code in status_map.items():
        if isinstance(error, exc_type):
            status_code = code
            break

    return HTTPException(
        status_code=status_code,
        detail=error.to_dict()
    )


# ============================================================================
# EXCEPTION HANDLER DECORATOR
# ============================================================================

from functools import wraps
from typing import Callable, TypeVar
import asyncio

T = TypeVar('T')


def handle_exceptions(func: Callable[..., T]) -> Callable[..., T]:
    """
    Decorator to convert MediaDownloaderError exceptions to HTTPException.
    Use this on route handlers for consistent error responses.
    """
    if asyncio.iscoroutinefunction(func):
        @wraps(func)
        async def async_wrapper(*args, **kwargs):
            try:
                return await func(*args, **kwargs)
            except MediaDownloaderError as e:
                raise to_http_exception(e)
            except HTTPException:
                raise  # Let HTTPException pass through
            except Exception as e:
                # Log unexpected exceptions
                from modules.universal_logger import get_logger
                logger = get_logger('API')
                logger.error(f"Unexpected error in {func.__name__}: {e}", module="Core")
                raise HTTPException(
                    status_code=500,
                    detail={"error": "InternalError", "message": str(e)}
                )
        return async_wrapper
    else:
        @wraps(func)
        def sync_wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except MediaDownloaderError as e:
                raise to_http_exception(e)
            except HTTPException:
                raise
            except Exception as e:
                from modules.universal_logger import get_logger
                logger = get_logger('API')
                logger.error(f"Unexpected error in {func.__name__}: {e}", module="Core")
                raise HTTPException(
                    status_code=500,
                    detail={"error": "InternalError", "message": str(e)}
                )
        return sync_wrapper
