"""Base class for embedding providers."""

from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional

from langchain_core.embeddings import Embeddings


class BaseEmbeddingProvider(ABC):
    """
    Abstract base class for embedding providers.

    All embedding providers should inherit from this class and implement
    the required methods. This provides a consistent interface similar to
    the LLM provider system.
    """

    # Override these in subclasses
    provider_name = "base"  # Display name for logs/UI
    provider_key = "BASE"  # Unique identifier (uppercase)
    requires_api_key = False  # Whether this provider requires an API key
    supports_local = False  # Whether this runs locally
    default_model = None  # Default embedding model

    @classmethod
    @abstractmethod
    def create_embeddings(
        cls,
        model: Optional[str] = None,
        settings_snapshot: Optional[Dict[str, Any]] = None,
        **kwargs,
    ) -> Embeddings:
        """
        Create an embeddings instance for this provider.

        Args:
            model: Name of the embedding model to use
            settings_snapshot: Optional settings snapshot for thread-safe access
            **kwargs: Additional provider-specific parameters

        Returns:
            A LangChain Embeddings instance

        Raises:
            ValueError: If required configuration is missing
            ImportError: If required dependencies are not installed
        """
        pass

    @classmethod
    @abstractmethod
    def is_available(
        cls, settings_snapshot: Optional[Dict[str, Any]] = None
    ) -> bool:
        """
        Check if this embedding provider is available and properly configured.

        Args:
            settings_snapshot: Optional settings snapshot for thread-safe access

        Returns:
            True if the provider can be used, False otherwise
        """
        pass

    @classmethod
    def get_available_models(
        cls, settings_snapshot: Optional[Dict[str, Any]] = None
    ) -> List[Dict[str, Any]]:
        """
        Get list of available embedding models for this provider.

        Implementations should return every model the backend reports.
        Filtering by name is unreliable — users may load custom or
        renamed embedding models — so leave the choice to the user and
        only tag entries when a real capability signal is available.

        Args:
            settings_snapshot: Optional settings snapshot

        Returns:
            List of dicts with ``value`` and ``label`` string keys for
            each model. May include an optional ``is_embedding`` (bool)
            key when the provider can detect embedding capability from
            the backend (e.g. Ollama's ``/api/show`` capabilities).
        """
        return []

    @classmethod
    def is_embedding_model(
        cls,
        model: str,
        settings_snapshot: Optional[Dict[str, Any]] = None,
    ) -> Optional[bool]:
        """
        Check whether a specific model supports embeddings.

        Providers that can distinguish embedding models from chat/LLM models
        should override this method.

        Args:
            model: Model identifier
            settings_snapshot: Optional settings snapshot

        Returns:
            True if the model supports embeddings, False if it does not,
            None if the provider cannot determine this.
        """
        return None

    @classmethod
    def get_model_info(cls, model: str) -> Optional[Dict[str, Any]]:
        """
        Get information about a specific model.

        Args:
            model: Model identifier

        Returns:
            Dict with model metadata (dimensions, description, etc.) or None
        """
        return None

    @classmethod
    def validate_config(
        cls, settings_snapshot: Optional[Dict[str, Any]] = None
    ) -> tuple[bool, Optional[str]]:
        """
        Validate the provider configuration.

        Args:
            settings_snapshot: Optional settings snapshot

        Returns:
            Tuple of (is_valid, error_message)
        """
        if not cls.is_available(settings_snapshot):
            return (
                False,
                f"{cls.provider_name} is not available or not configured",
            )
        return True, None

    @classmethod
    def get_provider_info(cls) -> Dict[str, Any]:
        """
        Get metadata about this provider.

        Returns:
            Dict with provider information
        """
        return {
            "name": cls.provider_name,
            "key": cls.provider_key,
            "requires_api_key": cls.requires_api_key,
            "supports_local": cls.supports_local,
            "default_model": cls.default_model,
        }
