"""
Composite judge: combines multiple judges and aggregates results.
"""

from __future__ import annotations

from typing import Any, Dict, List, Optional

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


class CompositeJudge:
    """
    Combines multiple judges and aggregates results.

    Config keys:
        judges: List[dict] - each dict has {type, config, weight}
        require_all: bool (default True) - if True, ALL must pass
    """

    def evaluate(
        self,
        output: str,
        assertion: Assertion,
        expected: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> AssertionResult:
        judges_config: List[dict] = assertion.config.get("judges", [])
        require_all: bool = assertion.config.get("require_all", True)

        if not judges_config:
            return AssertionResult(
                judge_type="composite",
                passed=False,
                confidence=1.0,
                reasoning="No sub-judges configured",
                weight=assertion.weight,
            )

        # Lazy import to avoid circular dependency
        from llmhq_releaseops.eval.judges.base import create_judge

        sub_results: List[AssertionResult] = []

        for jconf in judges_config:
            sub_assertion = Assertion(
                judge_type=JudgeType(jconf["type"]),
                weight=jconf.get("weight", 1.0),
                config=jconf.get("config", {}),
            )
            judge = create_judge(sub_assertion)
            result = judge.evaluate(output, sub_assertion, expected, context)
            sub_results.append(result)

        if require_all:
            passed = all(r.passed for r in sub_results)
        else:
            # Weighted majority
            total_weight = sum(r.weight for r in sub_results)
            passing_weight = sum(r.weight for r in sub_results if r.passed)
            passed = passing_weight > (total_weight / 2) if total_weight > 0 else False

        # Confidence = weighted average
        total_weight = sum(r.weight for r in sub_results)
        if total_weight > 0:
            confidence = sum(r.confidence * r.weight for r in sub_results) / total_weight
        else:
            confidence = 0.0

        return AssertionResult(
            judge_type="composite",
            passed=passed,
            confidence=confidence,
            weight=assertion.weight,
            details={
                "sub_results": [
                    {
                        "type": r.judge_type,
                        "passed": r.passed,
                        "confidence": r.confidence,
                    }
                    for r in sub_results
                ],
                "require_all": require_all,
            },
        )
