"""NFO Service Factory Module.

This module provides a centralized factory for creating NFOService instances
with consistent configuration and initialization logic.

The factory supports both direct instantiation and FastAPI dependency injection,
while remaining testable through optional dependency overrides.
"""

import logging
from typing import Optional

from src.config.settings import settings
from src.core.services.nfo_service import NFOService

logger = logging.getLogger(__name__)


class NFOServiceFactory:
    """Factory for creating NFOService instances with consistent configuration.
    
    This factory centralizes NFO service initialization logic that was previously
    duplicated across multiple modules (SeriesApp, SeriesManagerService, API endpoints).
    
    The factory follows these precedence rules for configuration:
    1. Explicit parameters (highest priority)
    2. Environment variables via settings
    3. config.json via ConfigService (fallback)
    4. Raise error if TMDB API key unavailable
    
    Example:
        >>> factory = NFOServiceFactory()
        >>> nfo_service = factory.create()
        >>> # Or with custom settings:
        >>> nfo_service = factory.create(tmdb_api_key="custom_key")
    """
    
    def __init__(self):
        """Initialize the NFO service factory."""
        self._config_service = None
    
    def create(
        self,
        tmdb_api_key: Optional[str] = None,
        anime_directory: Optional[str] = None,
        image_size: Optional[str] = None,
        auto_create: Optional[bool] = None
    ) -> NFOService:
        """Create an NFOService instance with proper configuration.
        
        This method implements the configuration precedence:
        1. Use explicit parameters if provided
        2. Fall back to settings (from ENV vars)
        3. Fall back to config.json (only if ENV not set)
        4. Raise ValueError if TMDB API key still unavailable
        
        Args:
            tmdb_api_key: TMDB API key (optional, falls back to settings/config)
            anime_directory: Anime directory path (optional, defaults to settings)
            image_size: Image size for downloads (optional, defaults to settings)
            auto_create: Whether to auto-create NFO files (optional, defaults to settings)
            
        Returns:
            NFOService: Configured NFO service instance
            
        Raises:
            ValueError: If TMDB API key cannot be determined from any source
            
        Example:
            >>> factory = NFOServiceFactory()
            >>> # Use all defaults from settings
            >>> service = factory.create()
            >>> # Override specific settings
            >>> service = factory.create(auto_create=False)
        """
        # Step 1: Determine TMDB API key with fallback logic
        api_key = tmdb_api_key or settings.tmdb_api_key
        
        # Step 2: If no API key in settings, try config.json as fallback
        if not api_key:
            api_key = self._get_api_key_from_config()
        
        # Step 3: Validate API key is available
        if not api_key:
            raise ValueError(
                "TMDB API key not configured. Set TMDB_API_KEY environment "
                "variable or configure in config.json (nfo.tmdb_api_key)."
            )
        
        # Step 4: Use provided values or fall back to settings
        directory = anime_directory or settings.anime_directory
        size = image_size or settings.nfo_image_size
        auto = auto_create if auto_create is not None else settings.nfo_auto_create
        
        # Step 5: Create and return the service
        logger.debug(
            "Creating NFOService: directory=%s, size=%s, auto_create=%s",
            directory, size, auto
        )
        
        return NFOService(
            tmdb_api_key=api_key,
            anime_directory=directory,
            image_size=size,
            auto_create=auto
        )
    
    def create_optional(
        self,
        tmdb_api_key: Optional[str] = None,
        anime_directory: Optional[str] = None,
        image_size: Optional[str] = None,
        auto_create: Optional[bool] = None
    ) -> Optional[NFOService]:
        """Create an NFOService instance, returning None if configuration unavailable.
        
        This is a convenience method for cases where NFO service is optional.
        Unlike create(), this returns None instead of raising ValueError when
        the TMDB API key is not configured.
        
        Args:
            tmdb_api_key: TMDB API key (optional)
            anime_directory: Anime directory path (optional)
            image_size: Image size for downloads (optional)
            auto_create: Whether to auto-create NFO files (optional)
            
        Returns:
            Optional[NFOService]: Configured service or None if key unavailable
            
        Example:
            >>> factory = NFOServiceFactory()
            >>> service = factory.create_optional()
            >>> if service:
            ...     service.create_tvshow_nfo(...)
        """
        try:
            return self.create(
                tmdb_api_key=tmdb_api_key,
                anime_directory=anime_directory,
                image_size=image_size,
                auto_create=auto_create
            )
        except ValueError as e:
            logger.debug("NFO service not available: %s", e)
            return None
    
    def _get_api_key_from_config(self) -> Optional[str]:
        """Get TMDB API key from config.json as fallback.
        
        This method is only called when the API key is not in settings
        (i.e., not set via environment variable). It provides backward
        compatibility with config.json configuration.
        
        Returns:
            Optional[str]: API key from config.json, or None if unavailable
        """
        try:
            # Lazy import to avoid circular dependencies
            from src.server.services.config_service import get_config_service
            
            if self._config_service is None:
                self._config_service = get_config_service()
            
            config = self._config_service.load_config()
            
            if config.nfo and config.nfo.tmdb_api_key:
                logger.debug("Using TMDB API key from config.json")
                return config.nfo.tmdb_api_key
                
        except Exception as e:  # pylint: disable=broad-except
            logger.debug("Could not load API key from config.json: %s", e)
        
        return None


# Global factory instance for convenience
_factory_instance: Optional[NFOServiceFactory] = None


def get_nfo_factory() -> NFOServiceFactory:
    """Get the global NFO service factory instance.
    
    This function provides a singleton factory instance for the application.
    The singleton pattern here is for the factory itself (which is stateless),
    not for the NFO service instances it creates.
    
    Returns:
        NFOServiceFactory: The global factory instance
        
    Example:
        >>> factory = get_nfo_factory()
        >>> service = factory.create()
    """
    global _factory_instance
    
    if _factory_instance is None:
        _factory_instance = NFOServiceFactory()
    
    return _factory_instance


def create_nfo_service(
    tmdb_api_key: Optional[str] = None,
    anime_directory: Optional[str] = None,
    image_size: Optional[str] = None,
    auto_create: Optional[bool] = None
) -> NFOService:
    """Convenience function to create an NFOService instance.
    
    This is a shorthand for get_nfo_factory().create() that can be used
    when you need a quick NFO service instance without interacting with
    the factory directly.
    
    Args:
        tmdb_api_key: TMDB API key (optional)
        anime_directory: Anime directory path (optional)
        image_size: Image size for downloads (optional)
        auto_create: Whether to auto-create NFO files (optional)
        
    Returns:
        NFOService: Configured NFO service instance
        
    Raises:
        ValueError: If TMDB API key cannot be determined
        
    Example:
        >>> service = create_nfo_service()
        >>> # Or with custom settings:
        >>> service = create_nfo_service(auto_create=False)
    """
    factory = get_nfo_factory()
    return factory.create(
        tmdb_api_key=tmdb_api_key,
        anime_directory=anime_directory,
        image_size=image_size,
        auto_create=auto_create
    )
