"""Эмбеддинги через Gemini API (SDK google-genai) — без локального torch.

Лёгкая зависимость вместо sentence-transformers: контейнер на маленьком VPS не
раздувается и не держит модель в RAM. Размерность 768 выбрана, чтобы вектор лез в
HNSW-индекс pgvector. Требуется переменная окружения GEMINI_API_KEY.
"""

from __future__ import annotations

import os

import numpy as np

EMBED_DIM = 768


class GeminiEmbedder:
    """Обёртка над Gemini-эмбеддингами с интерфейсом `.encode()` (как у sentence-transformers)."""

    def __init__(
        self,
        model: str = "gemini-embedding-001",
        dim: int = EMBED_DIM,
        api_key: str | None = None,
        batch: int = 100,
    ):
        from google import genai

        self._client = genai.Client(api_key=api_key or os.environ["GEMINI_API_KEY"])
        self.model = model
        self.dim = dim
        self.batch = batch

    def encode(
        self,
        texts,
        normalize_embeddings: bool = True,
        task_type: str = "RETRIEVAL_DOCUMENT",
        show_progress_bar: bool = False,
    ):
        """Векторизовать список строк. Возвращает numpy-массив (n, dim) float32.

        Для справочника используем RETRIEVAL_DOCUMENT, для запросов —
        RETRIEVAL_QUERY: так несвязанные названия расходятся сильнее, чем при
        SEMANTIC_SIMILARITY, и порог отсечения работает надёжнее.
        """
        import time

        from google.genai import types

        items = [t if t and t.strip() else " " for t in texts]
        config = types.EmbedContentConfig(task_type=task_type, output_dimensionality=self.dim)
        vectors: list[list[float]] = []
        for start in range(0, len(items), self.batch):
            chunk = items[start : start + self.batch]
            for attempt in range(8):
                try:
                    response = self._client.models.embed_content(
                        model=self.model, contents=chunk, config=config
                    )
                    vectors.extend(embedding.values for embedding in response.embeddings)
                    break
                except Exception as exc:  # пауза и повтор при превышении квоты (429)
                    if ("RESOURCE_EXHAUSTED" in str(exc) or "429" in str(exc)) and attempt < 7:
                        time.sleep(20)
                        continue
                    raise

        array = np.array(vectors, dtype=np.float32)
        if normalize_embeddings:
            array = array / np.clip(np.linalg.norm(array, axis=1, keepdims=True), 1e-9, None)
        return array
