from __future__ import annotations

import inspect
import os
from typing import Any, Dict, Optional, Type


_TRUE_VALUES = {"1", "true", "yes", "on"}
_FALSE_VALUES = {"0", "false", "no", "off"}


def _coerce_bool(value: Optional[str]) -> Optional[bool]:
    if value is None:
        return None
    normalized = value.strip().lower()
    if normalized in _TRUE_VALUES:
        return True
    if normalized in _FALSE_VALUES:
        return False
    return None


def get_openai_base_url() -> Optional[str]:
    for key in ("OPENAI_BASE_URL", "OPENAI_API_BASE", "OPENAI_API_URL"):
        value = os.getenv(key)
        if value:
            return value.rstrip("/")
    return None


def get_openai_use_responses_api() -> bool:
    explicit = _coerce_bool(os.getenv("OPENAI_USE_RESPONSES_API"))
    if explicit is not None:
        return explicit

    mode = os.getenv("OPENAI_API_MODE")
    if mode:
        normalized = mode.strip().lower()
        if normalized in {"responses", "response", "responses_api"}:
            return True
        if normalized in {"chat", "chat_completions", "completions"}:
            return False

    # Default to chat completions when a custom base URL is configured.
    if get_openai_base_url():
        return False

    return True


def get_openai_client_kwargs() -> Dict[str, Any]:
    base_url = get_openai_base_url()
    return {"base_url": base_url} if base_url else {}


def get_chat_openai_base_url_kwargs(chat_openai_cls: Type[Any]) -> Dict[str, Any]:
    base_url = get_openai_base_url()
    if not base_url:
        return {}

    try:
        params = inspect.signature(chat_openai_cls.__init__).parameters
    except (TypeError, ValueError):
        return {}

    if "base_url" in params:
        return {"base_url": base_url}
    if "openai_api_base" in params:
        return {"openai_api_base": base_url}
    return {}


# ---------------------------------------------------------------------------
# Azure OpenAI helpers
# ---------------------------------------------------------------------------

def is_azure_openai() -> bool:
    """Return True when Azure OpenAI env vars are configured."""
    return bool(os.getenv("AZURE_OPENAI_ENDPOINT"))


def get_azure_openai_config() -> Dict[str, Any]:
    """Return Azure-specific connection parameters from env."""
    return {
        "azure_endpoint": os.getenv("AZURE_OPENAI_ENDPOINT", ""),
        "api_key": os.getenv("AZURE_OPENAI_API_KEY", ""),
        "api_version": os.getenv("AZURE_OPENAI_API_VERSION", "2025-04-01-preview"),
    }


def get_effective_model(model: Optional[str] = None) -> str:
    """Return the model/deployment name to use.

    For Azure, always returns ``AZURE_OPENAI_DEPLOYMENT_NAME``.
    For direct OpenAI, returns *model* or the ``OPENAI_MODEL`` env default.
    """
    if is_azure_openai():
        return os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME", "gpt-4")
    return model or os.getenv("OPENAI_MODEL", "gpt-4.1-nano")


def create_openai_client(api_key: Optional[str] = None, async_: bool = False):
    """Factory that returns an OpenAI or AzureOpenAI client instance."""
    if is_azure_openai():
        cfg = get_azure_openai_config()
        if async_:
            from openai import AsyncAzureOpenAI
            return AsyncAzureOpenAI(**cfg)
        from openai import AzureOpenAI
        return AzureOpenAI(**cfg)

    from openai import AsyncOpenAI, OpenAI
    kw = get_openai_client_kwargs()
    if api_key:
        kw["api_key"] = api_key
    return AsyncOpenAI(**kw) if async_ else OpenAI(**kw)


def create_chat_openai_llm(**kwargs):
    """Factory returning AzureChatOpenAI or ChatOpenAI with correct config.

    Accepts the same keyword arguments as ``ChatOpenAI``; Azure-specific
    parameters are injected automatically when Azure env vars are set.
    """
    if is_azure_openai():
        from langchain_openai import AzureChatOpenAI
        cfg = get_azure_openai_config()
        deployment = get_effective_model()
        azure_kwargs = {
            "azure_endpoint": cfg["azure_endpoint"],
            "api_key": cfg["api_key"],
            "api_version": cfg["api_version"],
            "azure_deployment": deployment,
            "model": deployment,
        }
        # Remove keys that conflict with Azure config
        kw = {k: v for k, v in kwargs.items()
               if k not in ("model", "api_key", "base_url", "openai_api_base",
                            "use_responses_api", "output_version")}
        azure_kwargs.update(kw)
        return AzureChatOpenAI(**azure_kwargs)

    from langchain_openai import ChatOpenAI
    return ChatOpenAI(**kwargs)
