"""Base metric — subclass and implement ``_build_prompt()``."""

from __future__ import annotations

import logging
from abc import ABC, abstractmethod

from evalkit.judges.base import BaseJudge
from evalkit.models import MetricScore, TestCase

logger = logging.getLogger(__name__)


class BaseMetric(ABC):
    """Base class for all evaluation metrics."""

    name: str = ""
    threshold: float = 0.5

    @abstractmethod
    def _build_prompt(self, test_case: TestCase) -> str: ...

    def score(self, test_case: TestCase, judge: BaseJudge | None) -> MetricScore:
        if judge is None:
            raise TypeError(f"Metric {self.name!r} requires a judge but none was provided")
        logger.debug("Scoring metric=%s, question=%s", self.name, test_case.question[:80])
        prompt = self._build_prompt(test_case)
        response = judge.evaluate(prompt)
        passed = response.score >= self.threshold
        logger.debug(
            "Metric %s: score=%.3f, passed=%s, reason=%s", self.name, response.score, passed, response.reason[:100]
        )
        return MetricScore(
            metric_name=self.name,
            score=response.score,
            reason=response.reason,
            passed=passed,
        )

    async def score_async(self, test_case: TestCase, judge: BaseJudge | None) -> MetricScore:
        if judge is None:
            raise TypeError(f"Metric {self.name!r} requires a judge but none was provided")
        logger.debug("Scoring metric=%s (async), question=%s", self.name, test_case.question[:80])
        prompt = self._build_prompt(test_case)
        response = await judge.evaluate_async(prompt)
        passed = response.score >= self.threshold
        logger.debug(
            "Metric %s: score=%.3f, passed=%s, reason=%s", self.name, response.score, passed, response.reason[:100]
        )
        return MetricScore(
            metric_name=self.name,
            score=response.score,
            reason=response.reason,
            passed=passed,
        )
