from typing import Optional, cast

from analogai.deepthink import config as app_config
from analogai.deepthink.infrastructure.gateways.llm.enums.llm_gateway_type import LlmGatewayType
from analogai.deepthink.infrastructure.gateways.llm.gateway import LlmGateway


def _create_gateway_instance(
    gateway_type: LlmGatewayType,
    model: str,
    max_tokens: Optional[int],
) -> LlmGateway:
    try:
        match gateway_type:
            case LlmGatewayType.ANTHROPIC:
                from analogai.deepthink.infrastructure.gateways.llm.providers.anthropic_llm_gateway_impl import (
                    AnthropicLlmGatewayImpl,
                )
                if max_tokens is None:
                    return AnthropicLlmGatewayImpl(model=model)
                return AnthropicLlmGatewayImpl(model=model, max_tokens=max_tokens)
            case LlmGatewayType.OPENAI:
                from analogai.deepthink.infrastructure.gateways.llm.providers.openai_llm_gateway_impl import (
                    OpenaiLlmGatewayImpl,
                )
                if max_tokens is None:
                    return OpenaiLlmGatewayImpl(model=model)
                return OpenaiLlmGatewayImpl(model=model, max_tokens=max_tokens)
            case LlmGatewayType.AZURE:
                from analogai.deepthink.infrastructure.gateways.llm.providers.azure_llm_gateway_impl import (
                    AzureLlmGatewayImpl,
                )
                if max_tokens is None:
                    return AzureLlmGatewayImpl(model=model)
                return AzureLlmGatewayImpl(model=model, max_tokens=max_tokens)
            case LlmGatewayType.AZURE_OPENAI:
                from analogai.deepthink.infrastructure.gateways.llm.providers.azure_openai_llm_gateway_impl import (
                    AzureOpenaiLlmGatewayImpl,
                )
                if max_tokens is None:
                    return AzureOpenaiLlmGatewayImpl(model=model)
                return AzureOpenaiLlmGatewayImpl(model=model, max_tokens=max_tokens)
            case LlmGatewayType.GROK:
                from analogai.deepthink.infrastructure.gateways.llm.providers.xai_llm_gateway_impl import (
                    XaiLlmGatewayImpl,
                )
                if max_tokens is None:
                    return XaiLlmGatewayImpl(model=model)
                return XaiLlmGatewayImpl(model=model, max_tokens=max_tokens)
            case LlmGatewayType.BEDROCK:
                from analogai.deepthink.infrastructure.gateways.llm.providers.bedrock_llm_gateway_impl import (
                    BedrockLlmGatewayImpl,
                )
                if max_tokens is None:
                    return BedrockLlmGatewayImpl(model=model)
                return BedrockLlmGatewayImpl(model=model, max_tokens=max_tokens)
            case _:
                raise ValueError(f"Unsupported LLM gateway type: {gateway_type}")
    except ImportError as exc:
        raise ImportError(
            f"Failed to load LLM gateway '{gateway_type}'. Missing optional dependency."
        ) from exc


class LlmGatewayProviderFactory:
    _default_gateway_type: Optional[LlmGatewayType] = cast(
        Optional[LlmGatewayType],
        getattr(app_config, "DEFAULT_LLM_GATEWAY_TYPE", None),
    )
    _default_model: Optional[str] = None

    @classmethod
    def set_default_gateway_type(cls, gateway_type: LlmGatewayType) -> None:
        cls._default_gateway_type = gateway_type

    @classmethod
    def get_default_gateway_type(cls) -> LlmGatewayType:
        if cls._default_gateway_type is None:
            raise ValueError("LLM gateway type must be provided; defaults are disabled")
        return cls._default_gateway_type

    @classmethod
    def set_default_model(cls, model: Optional[str]) -> None:
        cls._default_model = model

    @classmethod
    def get_default_model(cls) -> Optional[str]:
        return cls._default_model

    @classmethod
    def create_gateway(
        cls,
        gateway_type: Optional[LlmGatewayType] = None,
        system_prompt: Optional[str] = None,
        max_tokens: Optional[int] = None,
        model: Optional[str] = None,
    ) -> LlmGateway:
        resolved_type = gateway_type or cls._default_gateway_type
        if resolved_type is None:
            raise ValueError("LLM gateway type must be provided; defaults are disabled")
        resolved_model = model or cls._default_model
        if not resolved_model:
            raise ValueError("Model name must be provided when creating an LLM gateway")
        gateway = _create_gateway_instance(resolved_type, resolved_model, max_tokens)
        if system_prompt is not None:
            gateway.set_system_prompt(system_prompt)
        return gateway
