"""HTTP embedding client for sagellm embedding server."""

from __future__ import annotations

import json
from dataclasses import dataclass
from urllib import error, request


@dataclass(slots=True)
class EmbeddingClient:
    """Client for OpenAI-compatible `/v1/embeddings` endpoint."""

    base_url: str = "http://127.0.0.1:8890"
    default_model: str = "sentence-transformers/all-MiniLM-L6-v2"
    timeout_s: float = 30.0

    def _post_json(self, path: str, payload: dict[str, object]) -> dict[str, object]:
        url = f"{self.base_url.rstrip('/')}{path}"
        req = request.Request(
            url=url,
            data=json.dumps(payload).encode("utf-8"),
            headers={"Content-Type": "application/json"},
            method="POST",
        )
        try:
            with request.urlopen(req, timeout=self.timeout_s) as response:  # noqa: S310
                data = response.read().decode("utf-8")
            return json.loads(data)
        except error.HTTPError as exc:
            body = exc.read().decode("utf-8", errors="replace")
            raise RuntimeError(f"Embedding server returned HTTP {exc.code}: {body}") from exc
        except error.URLError as exc:
            raise RuntimeError(
                f"Cannot connect to embedding server at {self.base_url}: {exc.reason}"
            ) from exc

    def health(self) -> bool:
        """Check embedding server health endpoint."""
        url = f"{self.base_url.rstrip('/')}/health"
        req = request.Request(url=url, method="GET")
        try:
            with request.urlopen(req, timeout=self.timeout_s) as response:  # noqa: S310
                data = response.read().decode("utf-8")
            payload = json.loads(data)
            return bool(payload.get("is_ready", False))
        except Exception:
            return False

    def embed(self, texts: list[str], model: str | None = None) -> list[list[float]]:
        """Embed a list of input texts."""
        if not texts:
            return []

        payload = {
            "input": texts,
            "model": model or self.default_model,
        }
        response = self._post_json("/v1/embeddings", payload)
        data = response.get("data", [])
        if not isinstance(data, list):
            raise RuntimeError("Invalid embedding response format: 'data' is not a list")
        return [item.get("embedding", []) for item in data if isinstance(item, dict)]

    def embed_one(self, text: str, model: str | None = None) -> list[float]:
        """Embed a single text."""
        vectors = self.embed([text], model=model)
        return vectors[0] if vectors else []
