"""Retrieval grounding verifier — checks answer support via cosine similarity.

No LLM call required. Uses sentence-transformer embeddings.
Purpose:    Zero-cost verification that measures semantic similarity between the final answer and the most relevant retrieved observation using sentence-transformer embeddings.
Exports:    RetrievalGroundingVerifier, GroundingResult
Added:      v0.1.0
Status:     Experimental
"""
from __future__ import annotations
from dataclasses import dataclass


@dataclass
class GroundingResult:
    risk: float
    grounded: bool
    max_sim: float
    threshold: float


class RetrievalGroundingVerifier:
    """Zero-cost retrieval grounding check via cosine similarity.

    Args:
        model_name: sentence-transformers model.
        grounded_threshold: cosine sim above which answer is considered grounded.
        experimental: considered experimental.
    """

    def __init__(
        self,
        model_name: str = "sentence-transformers/all-MiniLM-L6-v2",
        grounded_threshold: float = 0.55,
        experimental: bool = True,
    ) -> None:
        self.model_name = model_name
        self.grounded_threshold = grounded_threshold
        self.experimental = experimental
        self._model = None

    def _get_model(self):
        if self._model is None:
            from sentence_transformers import SentenceTransformer
            self._model = SentenceTransformer(self.model_name)
        return self._model

    def verify(self, answer: str, contexts: list[str]) -> GroundingResult:
        """Verify that answer is grounded in contexts.

        Returns GroundingResult with risk = 1 - max_cosine_sim(answer, contexts).
        """
        if not contexts:
            return GroundingResult(risk=0.5, grounded=False,
                                   max_sim=0.0, threshold=self.grounded_threshold)

        model = self._get_model()
        texts = [answer] + contexts
        embeddings = model.encode(texts, normalize_embeddings=True)
        ans_emb = embeddings[0]
        ctx_embs = embeddings[1:]

        sims = [float(ans_emb @ ctx_emb) for ctx_emb in ctx_embs]
        max_sim = max(sims)
        risk = max(0.0, min(1.0, 1.0 - max_sim))

        return GroundingResult(
            risk=risk,
            grounded=max_sim >= self.grounded_threshold,
            max_sim=max_sim,
            threshold=self.grounded_threshold,
        )
