"""OpenAI 兼容 API 基类 — Gemini/OpenRouter/OpenClaw 共用

所有支持 /v1/chat/completions 的 provider 继承此类，
子类只需在 __init__ 中传入 name/base_url/api_key/model/cooldown_name。
"""

from __future__ import annotations

import logging

from ...resilience import ServiceCooldown

logger = logging.getLogger(__name__)


class OpenAICompatProvider:
    """OpenAI /v1/chat/completions 兼容 provider 基类

    子类覆盖 __init__ 传入参数即可，无需重写任何方法。
    """

    def __init__(
        self,
        *,
        name: str,
        base_url: str,
        api_key: str,
        model: str,
        cooldown_name: str,
    ):
        self._name = name
        self._base_url = base_url.rstrip("/")
        self._api_key = api_key
        self._model = model
        self._cooldown = ServiceCooldown(cooldown_name, base_cooldown=60, max_cooldown=300)
        self._client = None

    @property
    def name(self) -> str:
        return self._name

    @property
    def model_name(self) -> str:
        return self._model

    @property
    def available(self) -> bool:
        if self._cooldown.is_cooling:
            return False
        return bool(self._api_key)

    def _auth_header(self) -> dict[str, str]:
        """认证头 — 默认 Bearer token，子类可覆盖"""
        return {"Authorization": f"Bearer {self._api_key}"}

    async def _get_client(self):
        if self._client is None:
            import httpx
            self._client = httpx.AsyncClient()
        return self._client

    async def generate(self, prompt: str) -> str | None:
        """调用 /chat/completions 返回原始文本

        供 SessionObserver.observe_tool_call() 使用，解析在调用方完成。
        """
        if self._cooldown.is_cooling:
            return None

        if not self._api_key:
            return None

        try:
            client = await self._get_client()
            resp = await client.post(
                f"{self._base_url}/chat/completions",
                headers={
                    **self._auth_header(),
                    "Content-Type": "application/json",
                },
                json={
                    "model": self._model,
                    "max_tokens": 1024,
                    "messages": [{"role": "user", "content": prompt}],
                },
                timeout=30.0,
            )
            resp.raise_for_status()
            data = resp.json()
            choices = data.get("choices", [])
            if not choices:
                logger.warning("%s observer 返回空 choices", self._name)
                return None
            content = choices[0].get("message", {}).get("content", "")
            self._cooldown.record_success()
            return content
        except Exception as e:
            logger.warning("%s observer 调用失败: %s", self._name, e)
            self._cooldown.record_failure()
            return None

    async def observe_session(self, prompt: str) -> list[dict] | None:
        """Session-end JSON 模式（旧接口，maintenance 用）"""
        raw = await self.generate(prompt)
        if raw is None:
            return None
        from .parse import parse_llm_json_array
        return parse_llm_json_array(raw, f"{self._name}_observer")

    async def close(self) -> None:
        """关闭 httpx client"""
        if self._client is not None:
            await self._client.aclose()
            self._client = None
