"""Služba pro generování embeddingů přes Ollama."""

from __future__ import annotations

import logging
from typing import Any

import httpx

from cyberbrain26.knowledge_plane.embedding_config import EmbeddingConfig

logger = logging.getLogger(__name__)


class EmbeddingService:
    """Wrapper kolem Ollama /api/embed pro knowledge plane."""

    def __init__(self, config: EmbeddingConfig | None = None) -> None:
        self.config = config or EmbeddingConfig()
        self._client = httpx.Client(
            base_url=self.config.ollama_base_url,
            timeout=60.0,
        )

    def _request(self, payload: dict[str, object]) -> dict[str, Any]:
        response = self._client.post("/api/embed", json=payload)
        response.raise_for_status()
        return response.json()

    def embed_text(self, text: str, *, num_ctx: int | None = None) -> list[float]:
        """Vrátí embedding pro jeden text."""
        ctx = num_ctx or self.config.max_context
        payload: dict[str, object] = {
            "model": self.config.model,
            "input": text,
            "options": {"num_ctx": ctx},
        }
        data = self._request(payload)
        embeddings = data.get("embeddings", [])
        if not embeddings:
            raise RuntimeError("Ollama nevrátil žádný embedding")
        vector = embeddings[0]
        if len(vector) != self.config.vector_dim:
            raise RuntimeError(
                f"Očekávaná dimenze {self.config.vector_dim}, "
                f"dostal jsem {len(vector)}"
            )
        return vector

    def embed_texts(self, texts: list[str], *, num_ctx: int | None = None) -> list[list[float]]:
        """Batch embedding — Ollama podporuje pole promptů."""
        ctx = num_ctx or self.config.max_context
        payload: dict[str, object] = {
            "model": self.config.model,
            "input": texts,
            "options": {"num_ctx": ctx},
        }
        data = self._request(payload)
        embeddings = data.get("embeddings", [])
        if len(embeddings) != len(texts):
            raise RuntimeError(
                f"Očekávaných {len(texts)} vektorů, dostal jsem {len(embeddings)}"
            )
        for vector in embeddings:
            if len(vector) != self.config.vector_dim:
                raise RuntimeError(
                    f"Očekávaná dimenze {self.config.vector_dim}, "
                    f"dostal jsem {len(vector)}"
                )
        return embeddings

    def embed_with_context(
        self, text: str, *, context: str | None = None, num_ctx: int | None = None
    ) -> list[float]:
        """JuraRAG-pattern: embed with optional domain context prepended."""
        if context:
            enhanced_text = f"Context: {context}\nQuery: {text}"
        else:
            enhanced_text = text
        return self.embed_text(enhanced_text, num_ctx=num_ctx)

    def health_check(self) -> dict[str, object]:
        """Rychlá kontrola dostupnosti providera."""
        try:
            response = self._client.get("/")
            ok = response.status_code == 200
        except Exception as exc:  # noqa: BLE001
            return {"healthy": False, "error": str(exc)}
        return {
            "healthy": ok,
            "provider": "ollama",
            "model": self.config.model,
            "vector_dim": self.config.vector_dim,
        }

    def close(self) -> None:
        self._client.close()

    def __enter__(self) -> EmbeddingService:
        return self

    def __exit__(self, *_exc: object) -> None:
        self.close()
