"""
Deterministic string-matching judges: ExactMatchJudge and ContainsJudge.

Both always return confidence=1.0.
"""

from __future__ import annotations

from typing import Any, Dict, Optional

from llmhq_releaseops.models.eval_result import AssertionResult
from llmhq_releaseops.models.eval_suite import Assertion


class ExactMatchJudge:
    """Checks if output exactly matches expected text."""

    def evaluate(
        self,
        output: str,
        assertion: Assertion,
        expected: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> AssertionResult:
        expected_val = assertion.config.get("expected", expected)
        if expected_val is None:
            return AssertionResult(
                judge_type="exact_match",
                passed=False,
                confidence=1.0,
                reasoning="No expected value provided in config or expected param",
                weight=assertion.weight,
            )

        case_sensitive = assertion.config.get("case_sensitive", True)

        if case_sensitive:
            passed = output == expected_val
        else:
            passed = output.lower() == expected_val.lower()

        return AssertionResult(
            judge_type="exact_match",
            passed=passed,
            confidence=1.0,
            weight=assertion.weight,
            details={"expected": expected_val, "actual": output},
        )


class ContainsJudge:
    """Checks if output contains the expected substring."""

    def evaluate(
        self,
        output: str,
        assertion: Assertion,
        expected: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> AssertionResult:
        expected_val = assertion.config.get("expected", expected)
        if expected_val is None:
            return AssertionResult(
                judge_type="contains",
                passed=False,
                confidence=1.0,
                reasoning="No expected value provided in config or expected param",
                weight=assertion.weight,
            )

        case_sensitive = assertion.config.get("case_sensitive", False)

        if case_sensitive:
            found = expected_val in output
        else:
            found = expected_val.lower() in output.lower()

        return AssertionResult(
            judge_type="contains",
            passed=found,
            confidence=1.0,
            weight=assertion.weight,
            details={"expected": expected_val, "found_in_output": found},
        )
