"""
Provider registry — creates and caches provider instances.

Usage:
    from providers.registry import get_provider_registry

    db_settings = await get_all_settings()
    registry = get_provider_registry(db_settings)
    provider = registry.get_image_provider()   # Returns active image provider
    provider = registry.get_video_provider()   # Returns active video provider
    provider = registry.get_tts_provider()     # Returns active TTS provider
"""

from __future__ import annotations

import logging
from typing import Any

from providers.ports import ImageProvider, VideoProvider, TTSProvider
from providers.settings import ProviderSettings
from providers.errors import ProviderUnavailableError

logger = logging.getLogger(__name__)


# Factory registry: maps (provider_type, name) → lazy factory function
_IMAGE_FACTORIES: dict[str, type] = {}
_VIDEO_FACTORIES: dict[str, type] = {}
_TTS_FACTORIES: dict[str, type] = {}


def _lazy_import_image(name: str) -> type[ImageProvider]:
    """Lazy-import and instantiate an image provider by name."""
    if name == "google_flow":
        from providers.google_flow_adapter import GoogleFlowBrowserAdapter

        return GoogleFlowBrowserAdapter
    elif name == "google_flow_v2":
        from providers.google_flow_v2_provider import GoogleFlowV2ImageProvider

        return GoogleFlowV2ImageProvider
    elif name == "dalle3":
        from providers.image_provider import DallE3ImageProvider

        return DallE3ImageProvider
    elif name == "pollinations":
        from providers.pollinations_image_provider import PollinationsImageProvider

        return PollinationsImageProvider
    else:
        raise ProviderUnavailableError(name, f"Unknown image provider: {name}")


def _lazy_import_video(name: str) -> type[VideoProvider]:
    """Lazy-import a video provider class by name."""
    if name == "grok":
        from providers.grok_video_provider import GrokVideoProvider

        return GrokVideoProvider
    elif name == "leonardo":
        from providers.leonardo_video_provider import LeonardoVideoProvider

        return LeonardoVideoProvider
    elif name == "pollinations":
        from providers.pollinations_video_provider import PollinationsVideoProvider

        return PollinationsVideoProvider
    elif name == "runway":
        from providers.video_provider import RunwayVideoProvider

        return RunwayVideoProvider
    elif name == "google_veo":
        from providers.google_veo_provider import GoogleVeoVideoProvider

        return GoogleVeoVideoProvider
    else:
        raise ProviderUnavailableError(name, f"Unknown video provider: {name}")


def _lazy_import_tts(name: str) -> type[TTSProvider]:
    """Lazy-import a TTS provider class by name."""
    if name == "elevenlabs":
        from providers.tts_provider import ElevenLabsTTSProvider

        return ElevenLabsTTSProvider
    elif name == "pollinations":
        from providers.pollinations_tts_provider import PollinationsTTSProvider

        return PollinationsTTSProvider
    else:
        raise ProviderUnavailableError(name, f"Unknown TTS provider: {name}")


class ProviderRegistry:
    """Creates and caches provider instances based on DB settings.

    Instances are cached per registry lifetime. Create a new registry
    (or call invalidate()) when settings change.
    """

    def __init__(self, settings: ProviderSettings) -> None:
        self._settings = settings
        self._cache: dict[tuple[str, str], Any] = {}

    def get_image_provider(self, name: str | None = None) -> ImageProvider:
        """Get the active image provider (or a specific one by name)."""
        name = name or self._settings.get_active_provider("image")
        return self._get_or_create("image", name)

    def get_video_provider(self, name: str | None = None) -> VideoProvider:
        """Get the active video provider (or a specific one by name)."""
        name = name or self._settings.get_active_provider("video")
        return self._get_or_create("video", name)

    def get_tts_provider(self, name: str | None = None) -> TTSProvider:
        """Get the active TTS provider (or a specific one by name)."""
        name = name or self._settings.get_active_provider("tts")
        return self._get_or_create("tts", name)

    def invalidate(self) -> None:
        """Clear cached providers (call when settings change)."""
        self._cache.clear()

    def _get_or_create(self, provider_type: str, name: str) -> Any:
        key = (provider_type, name)
        if key not in self._cache:
            config = self._settings.get_provider_config(provider_type, name)
            cls = self._resolve_class(provider_type, name)
            try:
                self._cache[key] = cls(**config) if config else cls()
            except Exception as exc:
                raise ProviderUnavailableError(
                    name, f"Failed to create {provider_type} provider: {exc}"
                ) from exc
            logger.info("Created %s provider: %s", provider_type, name)
        return self._cache[key]

    @staticmethod
    def _resolve_class(provider_type: str, name: str) -> type:
        if provider_type == "image":
            return _lazy_import_image(name)
        elif provider_type == "video":
            return _lazy_import_video(name)
        elif provider_type == "tts":
            return _lazy_import_tts(name)
        raise ValueError(f"Unknown provider type: {provider_type}")


def get_provider_registry(
    db_settings: dict[str, str] | None = None,
) -> ProviderRegistry:
    """Convenience: create a ProviderRegistry from raw DB settings dict."""
    return ProviderRegistry(ProviderSettings(db_settings))
