"""Completeness metric — does the answer cover the expected answer?"""

from __future__ import annotations

from evalkit.judges.base import BaseJudge
from evalkit.metrics.base import BaseMetric
from evalkit.models import MetricScore, TestCase
from evalkit.prompts.completeness import TEMPLATE


class CompletenessMetric(BaseMetric):
    """Measures whether the actual answer covers all key points in the expected answer.

    Requires ``test_case.expected_answer`` to be set.  If it is ``None``, the
    metric returns immediately with ``score=0.0`` and an explanatory reason
    rather than calling the judge.

    A score of 1.0 means the actual answer covers all key points from the
    expected answer.  A score of 0.0 means important parts are missing.
    """

    name: str = "completeness"

    def __init__(self, threshold: float = 0.5) -> None:
        self.threshold = threshold

    def _build_prompt(self, test_case: TestCase) -> str:
        return TEMPLATE.format(
            question=test_case.question,
            expected_answer=test_case.expected_answer,
            actual_answer=test_case.answer,
        )

    def score(self, test_case: TestCase, judge: BaseJudge) -> MetricScore:
        if test_case.expected_answer is None:
            return MetricScore(
                metric_name=self.name,
                score=0.0,
                reason="Completeness metric requires expected_answer",
                passed=False,
            )
        return super().score(test_case, judge)

    async def score_async(self, test_case: TestCase, judge: BaseJudge) -> MetricScore:
        if test_case.expected_answer is None:
            return MetricScore(
                metric_name=self.name,
                score=0.0,
                reason="Completeness metric requires expected_answer",
                passed=False,
            )
        return await super().score_async(test_case, judge)
