"""Backend factory for Django Smart Ratelimit."""

import importlib
import logging
from typing import Any, Dict, Type

from .base import BaseBackend

logger = logging.getLogger(__name__)

# Registry of built-in backends
BUILTIN_BACKENDS: Dict[str, str] = {
    "memory": "django_smart_ratelimit.backends.memory.MemoryBackend",
    "redis": "django_smart_ratelimit.backends.redis_backend.RedisBackend",
    "async_redis": "django_smart_ratelimit.backends.redis_backend.AsyncRedisBackend",
    "mongodb": "django_smart_ratelimit.backends.mongodb.MongoDBBackend",
    "multi": "django_smart_ratelimit.backends.multi.MultiBackend",
    "database": "django_smart_ratelimit.backends.database.DatabaseBackend",
}

# Custom backend registry
_custom_backends: Dict[str, Type[BaseBackend]] = {}


def register_backend(name: str, backend_class: Type[BaseBackend]) -> None:
    """Register a custom backend.

    Args:
        name: Name to register the backend under
        backend_class: The backend class to register
    """
    _custom_backends[name] = backend_class


class BackendFactory:
    """Factory class for creating backend instances."""

    _backend_cache: Dict[str, Type[BaseBackend]] = {}

    @classmethod
    def get_backend_class(cls, backend_path: str) -> Type[BaseBackend]:
        """
        Get backend class from dotted path or short name.

        Args:
            backend_path: Dotted path to backend class or short name (e.g. 'redis')

        Returns:
            Backend class

        Raises:
            ImportError: If backend cannot be imported
            AttributeError: If backend class not found
        """
        # Check custom backends first
        if backend_path in _custom_backends:
            return _custom_backends[backend_path]

        # Check built-in aliases
        if backend_path in BUILTIN_BACKENDS:
            backend_path = BUILTIN_BACKENDS[backend_path]

        if backend_path in cls._backend_cache:
            return cls._backend_cache[backend_path]

        try:
            module_path, class_name = backend_path.rsplit(".", 1)
            module = importlib.import_module(module_path)
            backend_class = getattr(module, class_name)

            if not issubclass(backend_class, BaseBackend):
                raise TypeError(f"Backend {backend_path} must inherit from BaseBackend")

            cls._backend_cache[backend_path] = backend_class
            return backend_class

        except (ImportError, AttributeError) as e:
            logger.error(f"Failed to import backend {backend_path}: {e}")
            raise

    @classmethod
    def create_backend(cls, backend_path: str, **kwargs: Any) -> BaseBackend:
        """
        Create backend instance from dotted path.

        Args:
            backend_path: Dotted path to backend class
            **kwargs: Additional arguments for backend initialization

        Returns:
            Backend instance

        Raises:
            ImportError: If backend cannot be imported
            AttributeError: If backend class not found
        """
        backend_class = cls.get_backend_class(backend_path)
        return backend_class(**kwargs)

    @classmethod
    def create_from_settings(cls) -> BaseBackend:
        """
        Create backend instance from Django settings.

        Returns:
            Backend instance configured from settings

        Raises:
            ImportError: If backend cannot be imported
            AttributeError: If backend class not found
        """
        from django_smart_ratelimit.config import get_settings

        settings = get_settings()

        backend_path = settings.backend_class
        if not backend_path:
            # Default to Redis backend for backward compatibility
            backend_path = "django_smart_ratelimit.backends.redis_backend.RedisBackend"

        backend_config = settings.backend_config
        return cls.create_backend(backend_path, **backend_config)

    @classmethod
    def clear_cache(cls) -> None:
        """Clear backend class cache."""
        cls._backend_cache.clear()
