"""Auto-discovery system for OpenAI-compatible providers."""

import importlib
import inspect
from pathlib import Path
from typing import Dict, List, Optional

from loguru import logger

from .openai_base import OpenAICompatibleProvider


class ProviderInfo:
    """Information about a discovered provider."""

    def __init__(self, provider_class):
        self.provider_class = provider_class
        self.provider_key = getattr(
            provider_class,
            "provider_key",
            provider_class.__name__.replace("Provider", "").upper(),
        )
        self.provider_name = provider_class.provider_name
        self.company_name = getattr(
            provider_class, "company_name", provider_class.provider_name
        )
        self.region = getattr(provider_class, "region", "Unknown")
        self.country = getattr(provider_class, "country", "Unknown")
        self.gdpr_compliant = getattr(provider_class, "gdpr_compliant", False)
        self.data_location = getattr(provider_class, "data_location", "Unknown")
        self.is_cloud = getattr(provider_class, "is_cloud", True)
        # Handle providers that may not have requires_auth_for_models method
        if hasattr(provider_class, "requires_auth_for_models"):
            self.requires_auth_for_models = (
                provider_class.requires_auth_for_models()
            )
        else:
            # Default to True for providers without the method
            self.requires_auth_for_models = True

        # Generate display name from attributes
        self.display_name = self._generate_display_name()

    def _generate_display_name(self):
        """Generate a descriptive display name from provider attributes."""
        # Start with the provider name
        name_parts = [self.provider_name]

        # Add detailed location info
        location_parts = []

        # Add region
        if self.region != "Unknown":
            location_parts.append(self.region)

        # Add specific data location if different from region
        if self.data_location != "Unknown":
            if self.data_location in ["Multiple", "Worldwide"]:
                location_parts.append("Data: Worldwide")
            elif self.data_location != self.country:
                location_parts.append(f"Data: {self.data_location}")

        # Combine location info
        if location_parts:
            name_parts.append(f"({', '.join(location_parts)})")

        # Only highlight GDPR compliance for EU-based providers as a special feature
        if self.gdpr_compliant and self.region == "EU":
            name_parts.append("🔒 GDPR")

        # Add cloud/local indicator
        if self.is_cloud:
            name_parts.append("☁️ Cloud")
        else:
            name_parts.append("💻 Local")

        return " ".join(name_parts)

    def to_dict(self):
        """Convert to dictionary for API responses."""
        return {
            "value": self.provider_key,
            "label": self.display_name,
            "is_cloud": self.is_cloud,
            "region": self.region,
            "country": self.country,
            "gdpr_compliant": self.gdpr_compliant,
            "data_location": self.data_location,
        }


class ProviderDiscovery:
    """Discovers and manages OpenAI-compatible providers."""

    _instance = None
    _providers: Dict[str, ProviderInfo] = {}

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._discovered = False
        return cls._instance

    def discover_providers(
        self, force_refresh: bool = False
    ) -> Dict[str, ProviderInfo]:
        """Discover all providers in the providers directory.

        Args:
            force_refresh: Force re-discovery even if already done

        Returns:
            Dictionary mapping provider keys to ProviderInfo objects
        """
        if self._discovered and not force_refresh:
            return self._providers

        self._providers.clear()
        # Scan the implementations subdirectory for providers
        implementations_dir = Path(__file__).parent / "implementations"

        if not implementations_dir.exists():
            logger.warning(
                f"Implementations directory not found: {implementations_dir}"
            )
            return self._providers

        # Scan all Python files in the implementations directory
        logger.info(f"Scanning directory: {implementations_dir}")
        for file_path in implementations_dir.glob("*.py"):
            # Skip special files (like __init__.py)
            if file_path.name.startswith("_"):
                continue

            module_name = file_path.stem
            logger.debug(f"Processing module: {module_name} from {file_path}")
            try:
                # Import the module from implementations subdirectory
                module = importlib.import_module(
                    f".implementations.{module_name}",
                    package="local_deep_research.llm.providers",
                )

                # Find all Provider classes (both OpenAICompatibleProvider and standalone)
                logger.debug(
                    f"Inspecting module {module_name} for Provider classes"
                )
                for name, obj in inspect.getmembers(module, inspect.isclass):
                    if inspect.isclass(obj):
                        logger.debug(
                            f"  Found class: {name}, bases: {obj.__bases__}"
                        )
                    # Check if it's a Provider class (ends with "Provider" and has provider_name)
                    if (
                        name.endswith("Provider")
                        and hasattr(obj, "provider_name")
                        and obj is not OpenAICompatibleProvider
                    ):
                        # Found a provider class
                        provider_info = ProviderInfo(obj)
                        self._providers[provider_info.provider_key] = (
                            provider_info
                        )

                        # Auto-register the provider
                        register_func_name = f"register_{module_name}_provider"
                        try:
                            register_func = getattr(module, register_func_name)
                            register_func()
                            logger.info(
                                f"Auto-registered provider: {provider_info.provider_key}"
                            )
                        except AttributeError:
                            logger.warning(
                                f"Provider {provider_info.provider_key} from {module_name}.py "
                                f"does not have a {register_func_name} function"
                            )

                        logger.info(
                            f"Discovered provider: {provider_info.provider_key} from {module_name}.py"
                        )

            except Exception as e:
                logger.exception(
                    f"Error loading provider from {module_name}: {e}"
                )

        self._discovered = True
        logger.info(f"Discovered {len(self._providers)} providers")
        return self._providers

    def get_provider_info(self, provider_key: str) -> Optional[ProviderInfo]:
        """Get information about a specific provider.

        Args:
            provider_key: The provider key (e.g., 'IONOS', 'GOOGLE')

        Returns:
            ProviderInfo object or None if not found
        """
        if not self._discovered:
            self.discover_providers()
        return self._providers.get(provider_key.upper())

    def get_provider_options(self) -> List[Dict]:
        """Get list of provider options for UI dropdowns.

        Returns:
            List of dictionaries with 'value' and 'label' keys
        """
        if not self._discovered:
            self.discover_providers()

        options = []
        for provider_info in self._providers.values():
            options.append(provider_info.to_dict())

        # Sort by label
        options.sort(key=lambda x: x["label"])
        return options

    def get_provider_class(self, provider_key: str):
        """Get the provider class for a given key.

        Args:
            provider_key: The provider key (e.g., 'IONOS', 'GOOGLE')

        Returns:
            Provider class or None if not found
        """
        provider_info = self.get_provider_info(provider_key)
        return provider_info.provider_class if provider_info else None


# Global instance
provider_discovery = ProviderDiscovery()


def discover_providers(force_refresh: bool = False) -> Dict[str, ProviderInfo]:
    """Discover all available providers.

    Args:
        force_refresh: Force re-discovery even if already done

    Returns:
        Dictionary mapping provider keys to ProviderInfo objects
    """
    return provider_discovery.discover_providers(force_refresh)


def get_discovered_provider_options() -> List[Dict]:
    """Get list of discovered provider options for UI dropdowns.

    Returns:
        List of dictionaries with 'value' and 'label' keys
    """
    return provider_discovery.get_provider_options()


def get_provider_class(provider_key: str):
    """Get the provider class for a given key.

    Args:
        provider_key: The provider key (e.g., 'IONOS', 'GOOGLE')

    Returns:
        Provider class or None if not found
    """
    return provider_discovery.get_provider_class(provider_key)
