"""Engine registry and factory for screen capture engines."""

from typing import Any, Dict, List, Optional, Type

from wled_controller.core.capture_engines.base import CaptureEngine, CaptureStream
from wled_controller.config import is_demo_mode
from wled_controller.utils import get_logger

logger = get_logger(__name__)


class EngineRegistry:
    """Registry for available capture engines.

    Maintains a registry of all capture engine implementations
    and provides factory methods for creating capture streams.
    """

    _engines: Dict[str, Type[CaptureEngine]] = {}

    @classmethod
    def register(cls, engine_class: Type[CaptureEngine]):
        """Register a capture engine.

        Args:
            engine_class: Engine class to register (must inherit from CaptureEngine)

        Raises:
            ValueError: If engine_class is not a subclass of CaptureEngine
        """
        if not issubclass(engine_class, CaptureEngine):
            raise ValueError(f"{engine_class} must be a subclass of CaptureEngine")

        engine_type = engine_class.ENGINE_TYPE
        if engine_type == "base":
            raise ValueError("Cannot register base engine type")

        if engine_type in cls._engines:
            logger.warning(f"Engine '{engine_type}' already registered, overwriting")

        cls._engines[engine_type] = engine_class
        logger.info(f"Registered capture engine: {engine_type}")

    @classmethod
    def get_engine(cls, engine_type: str) -> Type[CaptureEngine]:
        """Get engine class by type.

        Args:
            engine_type: Engine type identifier (e.g., "mss", "dxcam")

        Returns:
            Engine class

        Raises:
            ValueError: If engine type not found
        """
        if engine_type not in cls._engines:
            available = ", ".join(cls._engines.keys()) or "none"
            raise ValueError(
                f"Unknown engine type: '{engine_type}'. Available engines: {available}"
            )
        return cls._engines[engine_type]

    @classmethod
    def get_available_engines(cls) -> List[str]:
        """Get list of available engine types on this system.

        Returns:
            List of engine type identifiers that are available
        """
        demo = is_demo_mode()
        available = []
        for engine_type, engine_class in cls._engines.items():
            try:
                # In demo mode, only demo engines are available
                if demo and engine_type != "demo":
                    continue
                if engine_class.is_available():
                    available.append(engine_type)
            except Exception as e:
                logger.error(
                    f"Error checking availability for engine '{engine_type}': {e}"
                )

        return available

    @classmethod
    def get_best_available_engine(cls) -> Optional[str]:
        """Get the highest-priority available engine type.

        Returns:
            Engine type string, or None if no engines are available.
        """
        demo = is_demo_mode()
        best_type = None
        best_priority = -1
        for engine_type, engine_class in cls._engines.items():
            try:
                if demo and engine_type != "demo":
                    continue
                if engine_class.is_available() and engine_class.ENGINE_PRIORITY > best_priority:
                    best_priority = engine_class.ENGINE_PRIORITY
                    best_type = engine_type
            except Exception as e:
                logger.error(
                    f"Error checking availability for engine '{engine_type}': {e}"
                )
        return best_type

    @classmethod
    def get_all_engines(cls) -> Dict[str, Type[CaptureEngine]]:
        """Get all registered engines (available or not).

        In demo mode, only demo engines are returned.

        Returns:
            Dictionary mapping engine type to engine class
        """
        if is_demo_mode():
            return {k: v for k, v in cls._engines.items() if k == "demo"}
        return cls._engines.copy()

    @classmethod
    def create_stream(
        cls,
        engine_type: str,
        display_index: int,
        config: Dict[str, Any],
    ) -> CaptureStream:
        """Create a CaptureStream for the specified engine and display.

        Looks up the engine class, validates availability, and creates
        an uninitialized CaptureStream for the specified display.

        Args:
            engine_type: Engine type identifier
            display_index: Display index for the stream
            config: Engine-specific configuration

        Returns:
            Uninitialized CaptureStream instance

        Raises:
            ValueError: If engine type not found or not available
        """
        engine_class = cls.get_engine(engine_type)

        if not engine_class.is_available():
            raise ValueError(
                f"Engine '{engine_type}' is not available on this system"
            )

        try:
            stream = engine_class.create_stream(display_index, config)
            logger.debug(f"Created capture stream: {engine_type} (display={display_index})")
            return stream
        except Exception as e:
            logger.error(f"Failed to create stream for engine '{engine_type}': {e}")
            raise RuntimeError(f"Failed to create stream for engine '{engine_type}': {e}")

    @classmethod
    def clear_registry(cls):
        """Clear all registered engines (for testing)."""
        cls._engines.clear()
        logger.debug("Cleared engine registry")
