"""Local LLM client via Ollama."""

from __future__ import annotations

import json
import logging
import urllib.request
from typing import Any

logger = logging.getLogger(__name__)


class OllamaClient:
    """Adapter for Ollama local LLM server."""

    DEFAULT_URL = "http://127.0.0.1:11434"
    DEFAULT_MODEL = "qwen2.5:3b"
    EMBED_MODEL = "nomic-embed-text"
    TIMEOUT = 30

    def __init__(self, base_url: str | None = None, model: str | None = None):
        self._base_url = (base_url or self.DEFAULT_URL).rstrip("/")
        self._model = model or self.DEFAULT_MODEL
        self._available: bool | None = None

    def is_available(self) -> bool:
        """Check if Ollama server is reachable."""
        if self._available is not None:
            return self._available
        try:
            req = urllib.request.Request(f"{self._base_url}/api/tags", method="GET")
            with urllib.request.urlopen(req, timeout=3) as resp:
                self._available = resp.status == 200
        except Exception:
            self._available = False
        return self._available

    def generate(
        self,
        prompt: str,
        system: str = "",
        model: str | None = None,
        temperature: float = 0.3,
        max_tokens: int = 1024,
    ) -> str:
        """Generate text completion from local LLM."""
        if not self.is_available():
            return ""

        payload = {
            "model": model or self._model,
            "prompt": prompt,
            "system": system,
            "stream": False,
            "options": {
                "temperature": temperature,
                "num_predict": max_tokens,
            },
        }

        try:
            data = json.dumps(payload).encode("utf-8")
            req = urllib.request.Request(
                f"{self._base_url}/api/generate",
                data=data,
                headers={"Content-Type": "application/json"},
                method="POST",
            )
            with urllib.request.urlopen(req, timeout=self.TIMEOUT) as resp:
                result = json.loads(resp.read().decode("utf-8"))
                return str(result.get("response", "")).strip()
        except Exception as exc:
            logger.warning("Ollama generate failed: %s", exc)
            return ""

    def embed(self, text: str, model: str | None = None) -> list[float]:
        """Generate embedding vector via Ollama."""
        if not self.is_available():
            return []

        payload = {
            "model": model or self.EMBED_MODEL,
            "input": text,
        }

        try:
            data = json.dumps(payload).encode("utf-8")
            req = urllib.request.Request(
                f"{self._base_url}/api/embed",
                data=data,
                headers={"Content-Type": "application/json"},
                method="POST",
            )
            with urllib.request.urlopen(req, timeout=self.TIMEOUT) as resp:
                result = json.loads(resp.read().decode("utf-8"))
                embeddings = result.get("embeddings", [[]])
                return list(embeddings[0]) if embeddings else []
        except Exception as exc:
            logger.warning("Ollama embed failed: %s", exc)
            return []

    def list_models(self) -> list[dict[str, Any]]:
        """List available models on the Ollama server."""
        if not self.is_available():
            return []
        try:
            req = urllib.request.Request(f"{self._base_url}/api/tags", method="GET")
            with urllib.request.urlopen(req, timeout=5) as resp:
                result = json.loads(resp.read().decode("utf-8"))
                return list(result.get("models", []))
        except Exception:
            return []
