"""Baichuan（百川智能）Provider 适配器.

百川 API 兼容 OpenAI 格式（/v1/chat/completions），认证使用 Bearer token。
复用 OpenAI SSE 解析逻辑。
"""

from collections.abc import AsyncGenerator
from typing import Any

import httpx
import structlog

from ..errors import AILLMUnavailableError
from .base import LLMProvider, LLMResponse, LLMStreamChunk
from .openai_provider import OpenAIProvider

logger = structlog.get_logger()


class BaichuanProvider(LLMProvider):
    """百川智能 Provider.

    API 兼容 OpenAI 格式，复用 OpenAIProvider 的 SSE 解析。
    """

    def __init__(
        self,
        api_key: str,
        base_url: str = "https://api.baichuan-ai.com/v1",
        timeout: float = 30.0,
        stream_connect_timeout: float = 30.0,
        stream_read_timeout: float = 60.0,
    ) -> None:
        self._api_key = api_key
        self._base_url = base_url.rstrip("/")
        self._timeout = timeout
        self._stream_connect_timeout = stream_connect_timeout
        self._stream_read_timeout = stream_read_timeout

    @property
    def name(self) -> str:
        return "baichuan"

    def is_available(self) -> bool:
        return bool(self._api_key)

    def _build_url(self) -> str:
        return f"{self._base_url}/chat/completions"

    def _build_headers(self) -> dict[str, str]:
        return {
            "Authorization": f"Bearer {self._api_key}",
            "Content-Type": "application/json",
        }

    async def chat(
        self,
        messages: list[dict[str, str]],
        model: str,
        temperature: float = 0.7,
        **kwargs: Any,
    ) -> LLMResponse:
        if not self.is_available():
            raise AILLMUnavailableError("baichuan api_key not configured")

        payload: dict[str, Any] = {
            "model": model,
            "messages": messages,
            "temperature": temperature,
            "stream": False,
        }
        payload.update(kwargs)

        try:
            async with httpx.AsyncClient(timeout=self._timeout) as client:
                resp = await client.post(
                    self._build_url(),
                    json=payload,
                    headers=self._build_headers(),
                )
                resp.raise_for_status()
                data = resp.json()
        except httpx.HTTPStatusError as exc:
            logger.error(
                "baichuan_chat_http_error",
                status_code=exc.response.status_code,
                body=exc.response.text[:500],
            )
            raise AILLMUnavailableError(
                f"baichuan http {exc.response.status_code}: {exc.response.text[:200]}",
            ) from exc
        except httpx.HTTPError as exc:
            logger.error("baichuan_chat_http_error", error=str(exc))
            raise AILLMUnavailableError(f"baichuan http error: {exc}") from exc

        choices = data.get("choices", [])
        content = ""
        if choices:
            content = choices[0].get("message", {}).get("content", "") or ""
        usage_raw = data.get("usage", {}) or {}
        usage = {
            "prompt_tokens": int(usage_raw.get("prompt_tokens", 0)),
            "completion_tokens": int(usage_raw.get("completion_tokens", 0)),
            "total_tokens": int(usage_raw.get("total_tokens", 0)),
        }
        return LLMResponse(
            content=content,
            model=data.get("model", model),
            usage=usage,
            provider=self.name,
            raw=data,
        )

    async def stream_chat(
        self,
        messages: list[dict[str, str]],
        model: str,
        temperature: float = 0.7,
        **kwargs: Any,
    ) -> AsyncGenerator[LLMStreamChunk, None]:
        if not self.is_available():
            raise AILLMUnavailableError("baichuan api_key not configured")

        payload: dict[str, Any] = {
            "model": model,
            "messages": messages,
            "temperature": temperature,
            "stream": True,
        }
        payload.update(kwargs)

        timeout = httpx.Timeout(
            connect=self._stream_connect_timeout,
            read=self._stream_read_timeout,
            write=self._stream_connect_timeout,
            pool=self._stream_connect_timeout,
        )

        try:
            async with (
                httpx.AsyncClient(timeout=timeout) as client,
                client.stream(
                    "POST",
                    self._build_url(),
                    json=payload,
                    headers=self._build_headers(),
                ) as resp,
            ):
                resp.raise_for_status()
                async for line in resp.aiter_lines():
                    # 复用 OpenAI SSE 解析（百川兼容 OpenAI 格式）
                    chunk = OpenAIProvider._parse_sse_line(line, model)
                    if chunk is not None:
                        chunk.provider = "baichuan"
                        yield chunk
                        if chunk.finish_reason == "stop":
                            return
        except httpx.HTTPStatusError as exc:
            logger.error(
                "baichuan_stream_http_error",
                status_code=exc.response.status_code,
            )
            raise AILLMUnavailableError(
                f"baichuan stream http {exc.response.status_code}",
            ) from exc
        except httpx.HTTPError as exc:
            logger.error("baichuan_stream_http_error", error=str(exc))
            raise AILLMUnavailableError(f"baichuan stream error: {exc}") from exc

    async def embed(self, text: str, model: str) -> list[float]:
        """百川暂不支持 embedding，调用方应优先使用 OpenAI embed."""
        raise NotImplementedError("baichuan does not support embed")
