"""
Base judge protocol and factory for releaseops eval engine.

All judges implement the Judge protocol — a single `evaluate()` method
that returns an AssertionResult.
"""

from __future__ import annotations

from typing import Any, Dict, Optional, Protocol

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


class Judge(Protocol):
    """Protocol for all eval judges."""

    def evaluate(
        self,
        output: str,
        assertion: Assertion,
        expected: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> AssertionResult:
        """
        Evaluate an LLM output against a single assertion.

        Args:
            output: The actual LLM output text.
            assertion: The Assertion definition (judge_type, weight, config).
            expected: Optional expected output from EvalCase.expected_output.
            context: Optional additional context (input variables, etc.).

        Returns:
            AssertionResult with passed, confidence, reasoning, details.
        """
        ...


def create_judge(assertion: Assertion) -> Judge:
    """
    Factory: create the right judge for an assertion's judge_type.

    Imports are lazy to avoid circular dependencies (composite imports base).
    """
    jt = assertion.judge_type

    if jt == JudgeType.EXACT_MATCH:
        from llmhq_releaseops.eval.judges.exact_match import ExactMatchJudge

        return ExactMatchJudge()

    if jt == JudgeType.CONTAINS:
        from llmhq_releaseops.eval.judges.exact_match import ContainsJudge

        return ContainsJudge()

    if jt == JudgeType.REGEX:
        from llmhq_releaseops.eval.judges.regex_judge import RegexJudge

        return RegexJudge()

    if jt == JudgeType.LLM_JUDGE:
        from llmhq_releaseops.eval.judges.llm_judge import LLMJudge

        return LLMJudge()

    if jt == JudgeType.COMPOSITE:
        from llmhq_releaseops.eval.judges.composite import CompositeJudge

        return CompositeJudge()

    raise ValueError(f"Unknown judge type: {jt}")
