from __future__ import annotations

from typing import Dict, Optional

import httpx

from .exceptions import AuthMaterializationError, ConfigurationError, SecretProviderError
from .secrets import SecretProvider, fetch_secret as _fetch


def _build_api_key(mapping: Dict[str, str], provider: SecretProvider) -> Dict[str, object]:
    endpoint = _fetch(provider, mapping, "endpoint")
    api_key = _fetch(provider, mapping, "api_key")
    model = _fetch(provider, mapping, "model")
    return {"base_url": endpoint, "api_key": api_key, "model": model}


def _build_basic_auth(mapping: Dict[str, str], provider: SecretProvider) -> Dict[str, object]:
    endpoint = _fetch(provider, mapping, "endpoint")
    username = _fetch(provider, mapping, "username")
    password = _fetch(provider, mapping, "password")
    model = _fetch(provider, mapping, "model")
    http_client = httpx.Client(auth=(username, password))
    return {"base_url": endpoint, "http_client": http_client, "model": model}


def _build_no_auth(mapping: Dict[str, str], provider: SecretProvider) -> Dict[str, object]:
    endpoint = _fetch(provider, mapping, "endpoint")
    model = _fetch(provider, mapping, "model")
    return {"base_url": endpoint, "api_key": "not-needed", "model": model}


def _build_azure_ad(mapping: Dict[str, str], provider: SecretProvider) -> Dict[str, object]:
    raise AuthMaterializationError("azure_ad is disallowed because it issues short-lived tokens.")


def _build_azure_key(mapping: Dict[str, str], provider: SecretProvider) -> Dict[str, object]:
    endpoint = _fetch(provider, mapping, "endpoint")
    api_key = _fetch(provider, mapping, "api_key")
    api_version = _fetch(provider, mapping, "api_version")
    deployment_name = _fetch(provider, mapping, "deployment_name")
    base_url = f"{endpoint}/openai/deployments/{deployment_name}"
    return {"base_url": base_url, "api_key": api_key, "api_version": api_version, "model": deployment_name}


def _build_oauth_client_credentials(mapping: Dict[str, str], provider: SecretProvider) -> Dict[str, object]:
    raise AuthMaterializationError(
        "oauth_client_credentials is disallowed because it issues short-lived access tokens."
    )


def _build_bearer(mapping: Dict[str, str], provider: SecretProvider) -> Dict[str, object]:
    """Build config for Bearer token authentication.

    Uses a pre-provisioned bearer token in the Authorization header.
    This is for long-lived tokens, not short-lived OAuth tokens.
    """
    endpoint = _fetch(provider, mapping, "endpoint")
    token = _fetch(provider, mapping, "token")
    model = _fetch(provider, mapping, "model")
    http_client = httpx.Client(headers={"Authorization": f"Bearer {token}"})
    return {"base_url": endpoint, "http_client": http_client, "api_key": "not-needed", "model": model}


LLM_BUILDERS = {
    "api_key": _build_api_key,
    "basic_auth": _build_basic_auth,
    "bearer": _build_bearer,
    "no_auth": _build_no_auth,
    "azure_ad": _build_azure_ad,
    "azure_key": _build_azure_key,
    "oauth_client_credentials": _build_oauth_client_credentials,
}


def build_llm_config(auth_type: str, mapping: Dict[str, str], provider: SecretProvider) -> Dict[str, object]:
    if auth_type not in LLM_BUILDERS:
        raise ConfigurationError(f"Unsupported LLM auth_type '{auth_type}'")
    builder = LLM_BUILDERS[auth_type]
    try:
        return builder(mapping, provider)
    except (ConfigurationError, SecretProviderError, AuthMaterializationError):
        raise
    except Exception as exc:
        raise AuthMaterializationError(f"Failed to materialize LLM auth '{auth_type}': {exc}") from exc
