"""Tests for RouterEvaluator — pure-Python heuristic paths only (no GPU required)."""

from __future__ import annotations

from pathlib import Path
from unittest.mock import patch

from llmhosts.training.curator import TrainingExample
from llmhosts.training.evaluator import RouterEvaluator


def make_examples(complexity_label: str = "simple", n: int = 10) -> list[TrainingExample]:
    return [
        TrainingExample(
            text="sample text",
            complexity_label=complexity_label,
            domain_label="coding",
            quality_label="low",
            privacy_label="external",
        )
        for _ in range(n)
    ]


class TestHeuristicClassify:
    def test_expert_detected(self) -> None:
        evaluator = RouterEvaluator()
        # "phd" is in the expert_patterns list
        assert (
            evaluator._heuristic_classify_complexity(
                "Write a PhD thesis introduction on causal inference in large language models."
            )
            == "expert"
        )

    def test_complex_detected(self) -> None:
        evaluator = RouterEvaluator()
        # "compare and contrast" matches the complexity_word_pattern regex
        assert (
            evaluator._heuristic_classify_complexity(
                "Compare and contrast the pros and cons of three different sorting algorithms in depth."
            )
            == "complex"
        )

    def test_simple_detected(self) -> None:
        evaluator = RouterEvaluator()
        assert evaluator._heuristic_classify_complexity("How do I print hello world in Python?") == "simple"

    def test_trivial_detected(self) -> None:
        evaluator = RouterEvaluator()
        assert evaluator._heuristic_classify_complexity("Hi") == "trivial"

    def test_moderate_fallback(self) -> None:
        evaluator = RouterEvaluator()
        # 6 words, no expert/complex/trivial/simple triggers → moderate
        result = evaluator._heuristic_classify_complexity("What is the meaning of life?")
        assert result in ("simple", "moderate", "complex")  # ambiguous text


class TestEvaluateBaseline:
    def test_returns_float_between_0_and_1(self) -> None:
        evaluator = RouterEvaluator()
        examples = make_examples(n=20)
        acc = evaluator.evaluate_baseline(examples)
        assert 0.0 <= acc <= 1.0

    def test_empty_examples_returns_zero(self) -> None:
        evaluator = RouterEvaluator()
        acc = evaluator.evaluate_baseline([])
        assert acc == 0.0


class TestQualityGate:
    def test_passes_gate_when_criteria_met(self) -> None:
        evaluator = RouterEvaluator()
        examples = make_examples(n=100)
        # Mock _heuristic_accuracy to return improvement of 6pp
        with patch.object(evaluator, "_heuristic_accuracy", return_value=0.78):
            result = evaluator.evaluate(Path("/nonexistent"), examples, baseline_accuracy=0.72)
        assert result.improvement_pp >= 5.0
        assert result.passes_gate is True

    def test_fails_gate_when_improvement_too_small(self) -> None:
        evaluator = RouterEvaluator()
        examples = make_examples(n=100)
        with patch.object(evaluator, "_heuristic_accuracy", return_value=0.74):
            result = evaluator.evaluate(Path("/nonexistent"), examples, baseline_accuracy=0.72)
        assert result.improvement_pp < 5.0
        assert result.passes_gate is False

    def test_evaluate_empty_examples(self) -> None:
        evaluator = RouterEvaluator()
        result = evaluator.evaluate(Path("/nonexistent"), [])
        assert result.n_samples == 0
        assert result.passes_gate is False
