"""Provider registry and factory for auto-detection and instantiation."""

import logging

from ..config import get_settings
from .base import Provider
from .bedrock import BedrockProvider
from .mistral import MistralProvider
from .ollama import OllamaProvider
from .openai import OpenAIProvider
from .simple import SimpleProvider

logger = logging.getLogger(__name__)


class ProviderRegistry:
    """
    Registry for provider auto-detection and instantiation.

    Reads configuration via dynaconf-backed Settings (see ``config.py``).
    Checks provider settings in priority order and creates the appropriate
    provider:

    1. Bedrock (``AWS_REGION`` or ``BEDROCK_*_MODEL``)
    2. OpenAI (``OPENAI_API_KEY``)
    3. Mistral (``MISTRAL_API_KEY``)
    4. Ollama (``OLLAMA_BASE_URL``)
    5. Simple (fallback for testing/development)
    """

    @staticmethod
    def create_provider() -> Provider:
        """
        Auto-detect and create provider based on configured settings.

        Settings are sourced via :func:`nextcloud_mcp_server.config.get_settings`,
        which reads from settings files and environment variables (env vars
        always win, see ADR-024/025).

        Priority order:

        1. Bedrock - if ``aws_region`` or ``bedrock_embedding_model`` is set
        2. OpenAI - if ``openai_api_key`` is set
        3. Mistral - if ``mistral_api_key`` is set
        4. Ollama - if ``ollama_base_url`` is set
        5. Simple - fallback for testing/development

        Returns:
            Provider instance
        """
        settings = get_settings()

        # 0. Gateway (manual-only; never autodetected). When
        #    EMBEDDING_PROVIDER=gateway, bypass the autodetect chain entirely
        #    and route embeddings through the Astrolabe Cloud embedding gateway
        #    (design §10.1/§10.2). Lazy import to avoid an import cycle
        #    (embedding/gateway_client → providers/openai → ... → registry).
        if settings.embedding_provider == "gateway":
            from ..embedding.gateway_client import (  # noqa: PLC0415
                GatewayProvider,
                GatewayTokenProvider,
            )

            # Settings.__post_init__ guarantees the URL is set when the
            # provider is gateway; assert narrows the type for the checker.
            assert settings.embedding_gateway_url is not None
            # __post_init__ enforces all-or-nothing on the M2M creds, so
            # checking one is enough to know the full triple is present.
            token_provider = None
            if settings.embedding_gateway_client_id:
                assert settings.embedding_gateway_token_url is not None
                assert settings.embedding_gateway_client_secret is not None
                token_provider = GatewayTokenProvider(
                    token_url=settings.embedding_gateway_token_url,
                    client_id=settings.embedding_gateway_client_id,
                    client_secret=settings.embedding_gateway_client_secret,
                    scope=settings.embedding_gateway_scope,
                )
            logger.info(
                "Using embedding gateway provider: url=%s, model=%s, auth=%s",
                settings.embedding_gateway_url,
                settings.embedding_gateway_model,
                "oidc-m2m" if token_provider else "none",
            )
            return GatewayProvider(
                base_url=settings.embedding_gateway_url,
                embedding_model=settings.embedding_gateway_model,
                token_provider=token_provider,
            )

        # 1. Bedrock
        if (
            settings.aws_region
            or settings.bedrock_embedding_model
            or settings.bedrock_generation_model
        ):
            logger.info(
                "Using Bedrock provider: region=%s, embedding_model=%s, "
                "generation_model=%s",
                settings.aws_region,
                settings.bedrock_embedding_model,
                settings.bedrock_generation_model,
            )
            return BedrockProvider(
                region_name=settings.aws_region,
                embedding_model=settings.bedrock_embedding_model,
                generation_model=settings.bedrock_generation_model,
                aws_access_key_id=settings.aws_access_key_id,
                aws_secret_access_key=settings.aws_secret_access_key,
            )

        # 2. OpenAI
        if settings.openai_api_key:
            logger.info(
                "Using OpenAI provider: base_url=%s, embedding_model=%s, "
                "generation_model=%s",
                settings.openai_base_url or "default",
                settings.openai_embedding_model,
                settings.openai_generation_model,
            )
            return OpenAIProvider(
                api_key=settings.openai_api_key,
                base_url=settings.openai_base_url,
                embedding_model=settings.openai_embedding_model,
                generation_model=settings.openai_generation_model,
            )

        # 3. Mistral
        if settings.mistral_api_key:
            logger.info(
                "Using Mistral provider: base_url=%s, embedding_model=%s",
                settings.mistral_base_url or "default",
                settings.mistral_embedding_model,
            )
            return MistralProvider(
                api_key=settings.mistral_api_key,
                base_url=settings.mistral_base_url,
                embedding_model=settings.mistral_embedding_model,
            )

        # 4. Ollama
        if settings.ollama_base_url:
            logger.info(
                "Using Ollama provider: %s, embedding_model=%s, generation_model=%s",
                settings.ollama_base_url,
                settings.ollama_embedding_model,
                settings.ollama_generation_model,
            )
            return OllamaProvider(
                base_url=settings.ollama_base_url,
                embedding_model=settings.ollama_embedding_model,
                generation_model=settings.ollama_generation_model,
                verify_ssl=settings.ollama_verify_ssl,
            )

        # 5. Simple (fallback)
        logger.warning(
            "No provider configured (AWS_REGION, OPENAI_API_KEY, "
            "MISTRAL_API_KEY, OLLAMA_BASE_URL not set). "
            "Using SimpleProvider for testing/development. "
            "For production, configure Bedrock, OpenAI, Mistral, or Ollama."
        )
        return SimpleProvider(dimension=settings.simple_embedding_dimension)


# Singleton instance
_provider: Provider | None = None


def get_provider() -> Provider:
    """
    Get singleton provider instance.

    Returns:
        Global Provider instance (auto-detected on first call)
    """
    global _provider
    if _provider is None:
        _provider = ProviderRegistry.create_provider()
    return _provider


def reset_provider():
    """
    Reset singleton provider instance.

    Useful for testing or reconfiguration.
    """
    global _provider
    _provider = None
