"""Ollama Observer Provider — L1 本地模型 session 观察

复用 maintenance.py _chat() 模式：httpx + /api/generate + ServiceCooldown。
"""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from ...resilience import ServiceCooldown

if TYPE_CHECKING:
    from ...config import Config

logger = logging.getLogger(__name__)


class OllamaObserverProvider:
    """Ollama 本地模型 — L1 observer provider"""

    def __init__(self, config: Config):
        self.config = config
        self._cooldown = ServiceCooldown("observer_ollama", base_cooldown=30, max_cooldown=300)
        self._client = None
        self._checked = False
        self._is_available = False

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

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

    @property
    def available(self) -> bool:
        if self._cooldown.is_cooling:
            return False
        if not self._checked:
            return True  # 未检查时假设可用，observe_session 中验证
        return self._is_available

    async def _get_client(self):
        if self._client is None:
            import httpx
            # 显式 transport 故意绕过系统代理 — Ollama 是 localhost 服务，
            # 走 SOCKS 代理会连接失败。如果未来支持远程 Ollama，需移除此 transport。
            self._client = httpx.AsyncClient(
                base_url=self.config.ollama_url,
                transport=httpx.AsyncHTTPTransport(),
            )
        return self._client

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

    async def _check_model(self) -> bool:
        """检测 cognition_model 是否可用"""
        self._checked = True
        try:
            client = await self._get_client()
            resp = await client.get("/api/tags", timeout=3.0)
            resp.raise_for_status()
            models = resp.json().get("models", [])
            model_names = [m.get("name", "") for m in models]
            found = any(
                n == self.config.cognition_model
                or n.startswith(f"{self.config.cognition_model}:")
                for n in model_names
            )
            self._is_available = found
            if found:
                self._cooldown.record_success()
            return found
        except Exception as e:
            logger.debug("Ollama observer 模型检测失败: %s", e)
            self._is_available = False
            self._cooldown.record_failure()
            return False

    async def generate(self, prompt: str) -> str | None:
        """调用 Ollama /api/generate 返回原始文本（不做解析）

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

        if not self._checked:
            if not await self._check_model():
                return None

        try:
            client = await self._get_client()
            resp = await client.post(
                "/api/generate",
                json={
                    "model": self.config.cognition_model,
                    "prompt": prompt,
                    "stream": False,
                },
                timeout=30.0,
            )
            resp.raise_for_status()
            self._cooldown.record_success()
            return resp.json().get("response", "")
        except Exception as e:
            logger.warning("Ollama observer 调用失败: %s", e)
            self._cooldown.record_failure()
            return None

    async def observe_session(self, prompt: str) -> list[dict] | None:
        """调用 Ollama 执行 session 观察（旧接口，JSON 格式）"""
        raw = await self.generate(prompt)
        if raw is None:
            return None
        return self._parse_response(raw)

    def _parse_response(self, raw: str) -> list[dict] | None:
        """解析 LLM JSON 输出（旧格式）"""
        from .parse import parse_llm_json_array
        return parse_llm_json_array(raw, "ollama_observer")
