from typing import Type, TypeVar

import httpx
import structlog
from mistralai.client import Mistral
from pydantic import BaseModel

from mistralai.workflows._version import USER_AGENT
from mistralai.workflows.core.config.config import config

logger = structlog.get_logger(__name__)


def get_async_client(
    timeout: float = 60.0,
    api_key: str | None = None,
    headers: httpx.Headers | dict[str, str] | None = None,
) -> httpx.AsyncClient:
    headers = (
        headers
        if isinstance(headers, httpx.Headers)
        else httpx.Headers(headers or config.worker.mistral_api_headers or {})
    )
    if api_key:
        headers["Authorization"] = f"Bearer {api_key}"
    headers.setdefault("User-Agent", USER_AGENT)
    return httpx.AsyncClient(timeout=timeout, verify=config.common.ca_bundle or True, headers=headers)


def get_mistral_client(server_url: str | None = None, api_key: str | None = None) -> Mistral:
    if api_key is None:
        api_key_secret = config.common.mistral_api_key
        if api_key_secret is not None:
            api_key = api_key_secret.get_secret_value()
    return Mistral(
        api_key=api_key,
        server_url=server_url or config.worker.server_url,
        async_client=get_async_client(api_key=api_key),
    )


_TargetModel = TypeVar("_TargetModel", bound=BaseModel)


def translate_model(target_cls: Type[_TargetModel], source: BaseModel) -> _TargetModel:
    """Translate a protocol model into a worker_client (Speakeasy-generated) model, or vice-versa.

    A translation layer is required because the Pydantic models in `protocol/v1/` and the ones
    Speakeasy generates in `worker_client/models/` are not strictly equivalent: Speakeasy
    serialises `uuid` and `datetime` fields as `str`, while the protocol models use native Python
    types. Using `model_dump(mode="json")` normalises every field to JSON-safe primitives before
    re-validating into the target class, ensuring the two model families stay interoperable without
    manual field mapping.

    This translation layer is temporary. The long-term fix is to move `protocol/` out of
    `workflow_sdk` into `abraxas` and have `workflow_sdk` consume Speakeasy-generated models
    directly, which will eliminate the type mismatch and make this helper unnecessary.
    See WFL-468 for details.
    """
    return target_cls.model_validate(source.model_dump(mode="json"))
