"""Plugin loader with fallback mechanism."""

from typing import Any, ClassVar, Dict, Optional

from secure_mcp_gateway.utils import logger


class PluginLoader:
    """
    Centralized plugin loader with fallback to default Enkrypt providers.
    """

    # Default provider mappings
    DEFAULT_PROVIDERS: ClassVar[Dict[str, Dict[str, str]]] = {
        "auth": {
            "class": "secure_mcp_gateway.plugins.auth.local_apikey_provider.LocalApiKeyProvider",
            "name": "enkrypt",
        },
        "guardrails": {
            "class": "secure_mcp_gateway.plugins.guardrails.enkrypt_provider.EnkryptGuardrailProvider",
            "name": "enkrypt",
        },
        "telemetry": {
            "class": "secure_mcp_gateway.plugins.telemetry.opentelemetry_provider.OpenTelemetryProvider",
            "name": "opentelemetry",
        },
    }

    @staticmethod
    def load_plugin_providers(
        config: Dict[str, Any], plugin_type: str, manager: Any
    ) -> None:
        """
        Load plugin providers with fallback to default Enkrypt providers.

        Args:
            config: Full configuration dictionary
            plugin_type: Type of plugin (auth, guardrails, telemetry)
            manager: The plugin manager instance to register providers with
        """
        from secure_mcp_gateway.plugins.provider_loader import (
            create_provider_from_config,
        )

        # Get plugins configuration
        plugins_config = config.get("plugins", {})
        plugin_config = plugins_config.get(plugin_type, {})

        # Check if a custom provider is specified
        if plugin_config and "provider" in plugin_config:
            provider_name = plugin_config["provider"]
            provider_config = plugin_config.get("config", {})

            # Map provider names to their classes
            provider_class_mapping = {
                "enkrypt": PluginLoader.DEFAULT_PROVIDERS[plugin_type]["class"],
                "local_apikey": "secure_mcp_gateway.plugins.auth.local_apikey_provider.LocalApiKeyProvider",
                "otel": PluginLoader.DEFAULT_PROVIDERS["telemetry"]["class"],
                "opentelemetry": PluginLoader.DEFAULT_PROVIDERS["telemetry"]["class"],
            }

            # Get the class path for the provider
            class_path = provider_class_mapping.get(provider_name)
            if not class_path:
                logger.error(f"Unknown {plugin_type} provider: {provider_name}")
                class_path = PluginLoader.DEFAULT_PROVIDERS[plugin_type]["class"]
                provider_name = PluginLoader.DEFAULT_PROVIDERS[plugin_type]["name"]
                logger.info(
                    f"Falling back to default {plugin_type} provider: {provider_name}"
                )

            # Create and register the provider
            try:
                provider = create_provider_from_config(
                    {
                        "name": provider_name,
                        "class": class_path,
                        "config": provider_config,
                    },
                    plugin_type=plugin_type,
                )

                # Check if provider is already registered
                if (
                    hasattr(manager, "list_providers")
                    and provider_name in manager.list_providers()
                ):
                    logger.info(
                        f"[i] {plugin_type} provider '{provider_name}' already registered"
                    )
                else:
                    manager.register_provider(provider)
                    logger.info(f"✓ Registered {plugin_type} provider: {provider_name}")

            except Exception as e:
                logger.error(
                    f"Error loading {plugin_type} provider '{provider_name}': {e}"
                )
                # Fall back to default provider
                PluginLoader._load_default_provider(plugin_type, manager, config)
        else:
            # No custom provider specified, use default
            PluginLoader._load_default_provider(plugin_type, manager, config)

    @staticmethod
    def _load_default_provider(
        plugin_type: str, manager: Any, config: Dict[str, Any]
    ) -> None:
        """
        Load the default Enkrypt provider for the given plugin type.

        Args:
            plugin_type: Type of plugin (auth, guardrails, telemetry)
            manager: The plugin manager instance
            config: Full configuration dictionary
        """
        from secure_mcp_gateway.plugins.provider_loader import (
            create_provider_from_config,
        )

        default_provider = PluginLoader.DEFAULT_PROVIDERS[plugin_type]
        provider_name = default_provider["name"]
        class_path = default_provider["class"]

        # Check if already registered
        if (
            hasattr(manager, "list_providers")
            and provider_name in manager.list_providers()
        ):
            logger.info(
                f"[i] Default {plugin_type} provider '{provider_name}' already registered"
            )
            return

        # Prepare config for default provider
        provider_config = {}

        if plugin_type == "auth":
            # Get from plugins.auth.config, fallback to common config for use_remote_config
            auth_plugin_cfg = (
                config.get("plugins", {}).get("auth", {}).get("config", {})
            )
            provider_config = {
                "api_key": auth_plugin_cfg.get("api_key"),
                "base_url": auth_plugin_cfg.get(
                    "base_url", "https://api.enkryptai.com"
                ),
                "use_remote_config": config.get("enkrypt_use_remote_mcp_config", False),
            }
        elif plugin_type == "guardrails":
            # Get from plugins.guardrails.config
            guardrails_plugin_cfg = (
                config.get("plugins", {}).get("guardrails", {}).get("config", {})
            )
            provider_config = {
                "api_key": guardrails_plugin_cfg.get("api_key"),
                "base_url": guardrails_plugin_cfg.get(
                    "base_url", "https://api.enkryptai.com"
                ),
            }
        elif plugin_type == "telemetry":
            # Prefer plugins.telemetry.config; fall back to safe defaults
            telemetry_plugin_cfg = (
                config.get("plugins", {}).get("telemetry", {}).get("config", {})
            )
            provider_config = {
                "enabled": telemetry_plugin_cfg.get("enabled", True),
                "url": telemetry_plugin_cfg.get("url", "http://localhost:4317"),
                "insecure": telemetry_plugin_cfg.get("insecure", True),
            }

        try:
            provider = create_provider_from_config(
                {"name": provider_name, "class": class_path, "config": provider_config},
                plugin_type=plugin_type,
            )

            manager.register_provider(provider)
            logger.info(f"✓ Registered default {plugin_type} provider: {provider_name}")

        except Exception as e:
            logger.error(f"Error loading default {plugin_type} provider: {e}")


__all__ = ["PluginLoader"]
