"""Provider registry and selection."""

from __future__ import annotations

from typing import Any

from ai_qa.core.config import get_config
from ai_qa.exceptions import ProviderNotConfiguredError
from ai_qa.providers.anthropic import AnthropicProvider
from ai_qa.providers.base import BaseProvider
from ai_qa.providers.local import LocalProvider
from ai_qa.providers.openai import OpenAIProvider


class ProviderRegistry:
    """Registry for LLM providers.

    Maps provider names to provider classes and manages provider instances.
    """

    _providers: dict[str, type[BaseProvider]] = {
        "anthropic": AnthropicProvider,
        "openai": OpenAIProvider,
        "local": LocalProvider,
    }

    _instance: BaseProvider | None = None

    @classmethod
    def register(cls, name: str, provider_class: type[BaseProvider]) -> None:
        """Register a provider class.

        Args:
            name: Provider name (e.g., "anthropic").
            provider_class: Provider class (must extend BaseProvider).
        """
        cls._providers[name] = provider_class

    @classmethod
    def get(cls, name: str) -> type[BaseProvider]:
        """Get provider class by name.

        Args:
            name: Provider name.

        Returns:
            Provider class.

        Raises:
            ProviderNotConfiguredError: If provider not found.
        """
        if name not in cls._providers:
            available = ", ".join(cls._providers.keys())
            raise ProviderNotConfiguredError(
                f"Unknown provider: {name}\n"
                f"Available providers: {available}"
            )
        return cls._providers[name]

    @classmethod
    def list(cls) -> list[str]:
        """List all registered provider names.

        Returns:
            List of provider names.
        """
        return list(cls._providers.keys())

    @classmethod
    def set_instance(cls, provider: BaseProvider) -> None:
        """Set the global provider instance.

        Args:
            provider: Provider instance.
        """
        cls._instance = provider

    @classmethod
    def get_instance(cls) -> BaseProvider | None:
        """Get the global provider instance.

        Returns:
            Provider instance or None if not set.
        """
        return cls._instance


def configure_provider(
    provider_name: str,
    model: str,
    **kwargs: Any,
) -> BaseProvider:
    """Configure and return a provider instance.

    Args:
        provider_name: Provider name ("anthropic", "openai", "local").
        model: Model name.
        **kwargs: Additional provider config (api_key, base_url, etc.).

    Returns:
        Configured provider instance.

    Raises:
        ProviderNotConfiguredError: If provider not found or config invalid.
    """
    provider_class = ProviderRegistry.get(provider_name)
    provider = provider_class(model=model, **kwargs)
    ProviderRegistry.set_instance(provider)
    return provider


def get_provider() -> BaseProvider:
    """Get the current LLM provider.

    Uses the global Config to determine which provider to use.
    Auto-configures if not already set.

    Returns:
        Configured provider instance.

    Raises:
        ProviderNotConfiguredError: If provider cannot be determined.
    """
    # Check if already configured
    instance = ProviderRegistry.get_instance()
    if instance is not None:
        return instance

    # Get config
    config = get_config()

    # Determine provider name
    provider_name = config.provider
    if not provider_name:
        raise ProviderNotConfiguredError(
            "No provider configured.\n"
            "Set provider with:\n"
            "  from ai_qa import configure\n"
            "  configure(provider='anthropic', model='claude-3-sonnet')\n"
            "Or set environment variables:\n"
            "  ANTHROPIC_API_KEY (for anthropic provider)\n"
            "  OPENAI_API_KEY (for openai provider)"
        )

    # Get model
    model = config.model
    if not model:
        raise ProviderNotConfiguredError(
            f"No model configured for {provider_name} provider.\n"
            "Set model with:\n"
            "  from ai_qa import configure\n"
            f"  configure(provider='{provider_name}', model='<model_name>')"
        )

    # Create and cache provider
    return configure_provider(provider_name, model)


__all__ = [
    "BaseProvider",
    "AnthropicProvider",
    "OpenAIProvider",
    "LocalProvider",
    "ProviderRegistry",
    "configure_provider",
    "get_provider",
]
