import importlib
from typing import Any, ClassVar

from sinapsis_chat_history.helpers.schemas import ProviderName
from sinapsis_chat_history.providers.base import BaseStorageProvider, DatabaseConfig


class StorageProviderFactory:
    """Factory for resolving chat history storage providers and their configs."""

    _registry: ClassVar[dict[str, tuple[str, str, str]]] = {
        "postgres": (
            "sinapsis_chat_history.providers.postgres",
            "PostgresStorageProvider",
            "PostgresDatabaseConfig",
        ),
        "sqlite": (
            "sinapsis_chat_history.providers.sqlite",
            "SQLiteStorageProvider",
            "SQLiteDatabaseConfig",
        ),
        "supabase": (
            "sinapsis_chat_history.providers.supabase",
            "SupabaseStorageProvider",
            "SupabaseDatabaseConfig",
        ),
    }

    @classmethod
    def get_provider_class(cls, provider: ProviderName) -> type[BaseStorageProvider]:
        """Resolve and return the provider class for a given backend name.

        Args:
            provider (ProviderName): Provider name to resolve.

        Returns:
            type[BaseStorageProvider]: Provider class registered for the given
                backend.
        """
        module_name, provider_name, _ = cls._registry[provider]
        module = importlib.import_module(module_name)
        return getattr(module, provider_name)

    @classmethod
    def get_config_model(cls, provider: ProviderName) -> type[DatabaseConfig]:
        """Resolve and return the provider config model for a given backend name.

        Args:
            provider (ProviderName): Provider name to resolve.

        Returns:
            type[DatabaseConfig]: Provider-specific configuration model.
        """
        module_name, _, config_name = cls._registry[provider]
        module = importlib.import_module(module_name)
        return getattr(module, config_name)

    @classmethod
    def validate_config(cls, provider: ProviderName, config: DatabaseConfig | dict[str, Any] | None) -> DatabaseConfig:
        """Validate a provider config against the backend-specific model.

        Args:
            provider (ProviderName): Provider whose config model should be used.
            config (DatabaseConfig | dict[str, Any] | None): Raw or partially
                validated configuration.

        Returns:
            DatabaseConfig: Provider-specific validated configuration.
        """
        config_model = cls.get_config_model(provider)
        if isinstance(config, config_model):
            return config
        return config_model.model_validate(config or {})

    @classmethod
    def create(
        cls, provider: ProviderName, config: DatabaseConfig | dict[str, Any] | None = None
    ) -> BaseStorageProvider:
        """Instantiate a configured storage provider.

        Args:
            provider (ProviderName): Provider backend to instantiate.
            config (DatabaseConfig | dict[str, Any] | None): Optional provider
                configuration.

        Returns:
            BaseStorageProvider: Configured storage provider instance.
        """
        provider_class = cls.get_provider_class(provider)
        validated_config = cls.validate_config(provider, config)
        return provider_class(validated_config)
