"""
Cross-Encoder Re-Ranking for RAG Search Results.

Uses BGE Reranker v2 (BAAI/bge-reranker-v2-m3, MIT license) to re-rank
search results from Qdrant for improved retrieval quality.

Lazy-loads the model on first use. Disabled by default (RERANK_ENABLED=false).
"""

import logging
import os
from typing import Optional

logger = logging.getLogger(__name__)

RERANK_ENABLED = os.getenv("RERANK_ENABLED", "false").lower() == "true"
RERANK_MODEL = os.getenv("RERANK_MODEL", "BAAI/bge-reranker-v2-m3")


class Reranker:
    """Cross-encoder reranker using sentence-transformers."""

    def __init__(self, model_name: str = RERANK_MODEL):
        self._model = None  # Lazy init
        self._model_name = model_name

    def _ensure_model(self) -> None:
        """Load model on first use."""
        if self._model is not None:
            return
        try:
            from sentence_transformers import CrossEncoder

            logger.info("Loading reranker model: %s", self._model_name)
            self._model = CrossEncoder(self._model_name)
            logger.info("Reranker model loaded successfully")
        except ImportError:
            logger.error(
                "sentence-transformers not installed. "
                "Install with: pip install sentence-transformers"
            )
            raise
        except Exception as e:
            logger.error("Failed to load reranker model: %s", e)
            raise

    def rerank(
        self, query: str, texts: list[str], top_k: int = 5
    ) -> list[int]:
        """
        Return indices of top_k texts sorted by relevance (highest first).

        Args:
            query: The search query.
            texts: List of candidate texts to re-rank.
            top_k: Number of top results to return.

        Returns:
            List of indices into the original texts list, sorted by relevance.
        """
        if not texts:
            return []

        self._ensure_model()

        pairs = [[query, text] for text in texts]
        scores = self._model.predict(pairs)

        # Sort by score descending, return indices
        ranked = sorted(range(len(scores)), key=lambda i: scores[i], reverse=True)
        return ranked[:top_k]


# Module-level singleton
_reranker: Optional[Reranker] = None


def get_reranker() -> Optional[Reranker]:
    """Get the shared reranker instance. Returns None if disabled."""
    global _reranker
    if not RERANK_ENABLED:
        return None
    if _reranker is None:
        _reranker = Reranker()
    return _reranker
