from collections.abc import Callable
from importlib.util import find_spec

from yera.models.llm_interfaces.base import BaseLLMInterface
from yera.models.llm_interfaces.mock import MockLLMInterface

# Cache for loaded classes
_loaded_cache: dict[str, type[BaseLLMInterface]] = {}
_loaders: dict[str, Callable[[], type[BaseLLMInterface]]] = {}
_initialized = False


def _lazy_init():
    """Initialize the registry on first access."""
    global _initialized
    if _initialized:
        return

    _initialized = True

    # Define all interfaces to check
    interfaces = [
        (
            "llama-cpp",
            "yera.models.llm_interfaces.llama_cpp",
            "LlamaCppLLM",
            "llama_cpp",
        ),
        (
            "anthropic-sdk",
            "yera.models.llm_interfaces.anthropic",
            "AnthropicLLM",
            "anthropic",
        ),
        ("openai-sdk", "yera.models.llm_interfaces.open_ai", "OpenAILLM", "openai"),
        (
            "azure-sdk",
            "yera.models.llm_interfaces.azure_openai",
            "AzureOpenAILLM",
            "openai",
        ),
        (
            "ollama",
            "yera.models.llm_interfaces.ollama_interface",
            "OllamaLLM",
            "ollama",
        ),
        ("bedrock", "yera.models.llm_interfaces.aws_bedrock", "AwsBedrockLLM", "boto3"),
    ]

    # Check availability and register loaders
    for name, module_path, class_name, check_package in interfaces:
        if find_spec(check_package) is not None:

            def loader(mod=module_path, cls=class_name, n=name):
                if n not in _loaded_cache:
                    module = __import__(mod, fromlist=[cls])
                    _loaded_cache[n] = getattr(module, cls)
                return _loaded_cache[n]

            _loaders[name] = loader

    # Mock is always available
    _loaders["Mock"] = lambda: MockLLMInterface


def get_interface(name: str) -> type[BaseLLMInterface]:
    """Get an interface class by name, loading it lazily."""
    _lazy_init()  # Only runs once, on first call

    if name not in _loaders:
        raise ValueError(
            f"Interface '{name}' not available. Available: {list(_loaders.keys())}"
        )
    return _loaders[name]()
