"""
Ollama Provider - Phase 24 ADR-052
====================================
本地 LLM 推理 (192.168.0.188 VMware VM, CPU-only)

搬移自: openclaw.py _call_ollama (L349-409)
特性: 免費、隱私安全 (local)、但 CPU 慢 (~97s/30tokens for qwen2.5:7b)

2026-04-02 ogt: Phase 24-A 從 openclaw.py 抽出
"""

from __future__ import annotations

import time

import httpx
import structlog

from src.core.config import get_settings
from src.services.ai_providers.interfaces import AIProvider, AIResult, is_provider_enabled_by_env
from src.services.model_registry import get_model_registry

logger = structlog.get_logger(__name__)
settings = get_settings()


class OllamaProvider:
    """
    Ollama 本地 LLM Provider

    privacy_level: local (可處理機密資料)
    capabilities: rca, chat, code_review
    """

    def __init__(self) -> None:
        self._http_client: httpx.AsyncClient | None = None

    async def _get_client(self) -> httpx.AsyncClient:
        if self._http_client is None or self._http_client.is_closed:
            self._http_client = httpx.AsyncClient(
                timeout=httpx.Timeout(120.0, connect=10.0),
            )
        return self._http_client

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

    @property
    def is_enabled(self) -> bool:
        return is_provider_enabled_by_env("ollama")

    @property
    def capabilities(self) -> set[str]:
        return {"rca", "chat", "code_review"}

    @property
    def privacy_level(self) -> str:
        return "local"

    async def analyze(
        self,
        prompt: str,
        context: dict | None = None,
    ) -> AIResult:
        start = time.perf_counter()
        try:
            client = await self._get_client()

            registry = get_model_registry()
            model_name = registry.get_model("ollama", "rca")
            options = registry.get_provider_options("ollama")

            # P0 2026-04-04 Claude Code: per-task timeout（Option C 分情境）
            # FORCE_LOCAL/diagnose → OLLAMA_DIAGNOSE_TIMEOUT_SECONDS (200s，實測 ~173s)
            # 其他 → OPENCLAW_TIMEOUT（既有設定）
            task_type = (context or {}).get("task_type", "")
            if task_type in ("diagnose", "force_local"):
                read_timeout = float(getattr(settings, "OLLAMA_DIAGNOSE_TIMEOUT_SECONDS", 200))
            else:
                read_timeout = float(settings.OPENCLAW_TIMEOUT)

            response = await client.post(
                f"{settings.OLLAMA_URL}/api/generate",
                json={
                    "model": model_name,
                    "prompt": prompt,
                    "stream": False,
                    "format": "json",
                    "options": {
                        "num_predict": options.get("num_predict", 1024),
                        "temperature": options.get("temperature", 0.1),
                        "top_p": options.get("top_p", 0.9),
                    },
                },
                timeout=httpx.Timeout(read_timeout, connect=10.0),
            )
            response.raise_for_status()
            data = response.json()
            result = data.get("response", "")
            # I3 修復: 追蹤 tokens
            tokens = data.get("eval_count", 0) + data.get("prompt_eval_count", 0)
            latency = (time.perf_counter() - start) * 1000

            logger.info("ollama_provider_success", response_length=len(result), tokens=tokens, latency_ms=round(latency, 1))
            return AIResult(
                raw_response=result,
                success=True,
                provider=self.name,
                tokens=tokens,
                latency_ms=latency,
            )

        except httpx.TimeoutException as e:
            latency = (time.perf_counter() - start) * 1000
            logger.warning("ollama_provider_timeout", error=str(e), latency_ms=round(latency, 1))
            return AIResult(raw_response="", success=False, provider=self.name, latency_ms=latency, error=f"Timeout: {e}")

        except Exception as e:
            latency = (time.perf_counter() - start) * 1000
            logger.warning("ollama_provider_failed", error=str(e), latency_ms=round(latency, 1))
            return AIResult(raw_response="", success=False, provider=self.name, latency_ms=latency, error=str(e))

    async def health_check(self) -> bool:
        try:
            client = await self._get_client()
            resp = await client.get(f"{settings.OLLAMA_URL}/api/tags", timeout=5.0)
            return resp.status_code == 200
        except Exception:
            return False

    async def close(self) -> None:
        if self._http_client:
            await self._http_client.aclose()
            self._http_client = None
