"""Small sentence embedder shared by the RAG index, the retriever, and the semantic cache.

We use one tiny model (default: BAAI/bge-small-en-v1.5) for everything so the memory/energy
footprint stays low. bge/e5 models expect a short query prefix for retrieval; documents are
embedded without it.
"""
from __future__ import annotations

import numpy as np

from .settings import Config

_MODEL_CACHE: dict[str, object] = {}


class Embedder:
    def __init__(self, cfg: Config):
        self.model_id = cfg.get("embeddings.model_id", "BAAI/bge-small-en-v1.5")
        self.query_prefix = cfg.get("embeddings.query_prefix", "")
        self.device = cfg.get("embeddings.device", "cpu")
        self._model = None  # lazy-loaded on first use

    def _load(self):
        if self._model is not None:
            return self._model
        key = f"{self.model_id}:{self.device}"
        if key not in _MODEL_CACHE:
            # Imported lazily so the config/settings layer stays import-light.
            from sentence_transformers import SentenceTransformer

            _MODEL_CACHE[key] = SentenceTransformer(self.model_id, device=self.device)
        self._model = _MODEL_CACHE[key]
        return self._model

    def embed_documents(self, texts: list[str]) -> np.ndarray:
        model = self._load()
        vecs = model.encode(
            texts, normalize_embeddings=True, convert_to_numpy=True, show_progress_bar=False
        )
        return vecs.astype("float32")

    def embed_query(self, text: str) -> np.ndarray:
        model = self._load()
        vec = model.encode(
            self.query_prefix + text,
            normalize_embeddings=True,
            convert_to_numpy=True,
            show_progress_bar=False,
        )
        return vec.astype("float32")
