"""Tests for openjarvis.learning.spec_search.gate.benchmark_gate module.

All tests use mock scorers — no live EvalRunner.
"""

from __future__ import annotations

from openjarvis.learning.spec_search.models import BenchmarkSnapshot


def _make_scorer(scores: dict[str, float], overall: float | None = None):
    """Return a callable that produces a BenchmarkSnapshot with given scores."""

    def scorer(
        *, benchmark_version: str, subsample_size: int, seed: int
    ) -> BenchmarkSnapshot:
        computed = sum(scores.values()) / max(len(scores), 1)
        return BenchmarkSnapshot(
            benchmark_version=benchmark_version,
            overall_score=overall if overall is not None else computed,
            cluster_scores=scores,
            task_count=subsample_size,
            elapsed_seconds=5.0,
        )

    return scorer


class TestBenchmarkGate:
    """Tests for BenchmarkGate."""

    def test_accepts_improving_edit(self) -> None:
        from openjarvis.learning.spec_search.gate.benchmark_gate import (
            BenchmarkGate,
        )

        before = BenchmarkSnapshot(
            benchmark_version="v1",
            overall_score=0.6,
            cluster_scores={"c1": 0.5, "c2": 0.7},
            task_count=50,
            elapsed_seconds=10.0,
        )
        gate = BenchmarkGate(
            scorer=_make_scorer({"c1": 0.6, "c2": 0.75}, overall=0.68),
            benchmark_version="v1",
            min_improvement=0.0,
            max_regression=0.05,
            subsample_size=50,
        )
        result = gate.evaluate(before=before, session_seed=42)
        assert result.accepted
        assert result.snapshot.overall_score == 0.68
        assert result.delta > 0

    def test_rejects_no_improvement(self) -> None:
        from openjarvis.learning.spec_search.gate.benchmark_gate import (
            BenchmarkGate,
        )

        before = BenchmarkSnapshot(
            benchmark_version="v1",
            overall_score=0.7,
            cluster_scores={"c1": 0.6, "c2": 0.8},
            task_count=50,
            elapsed_seconds=10.0,
        )
        gate = BenchmarkGate(
            scorer=_make_scorer({"c1": 0.6, "c2": 0.8}, overall=0.7),
            benchmark_version="v1",
            min_improvement=0.0,
            max_regression=0.05,
            subsample_size=50,
        )
        result = gate.evaluate(before=before, session_seed=42)
        assert not result.accepted
        assert "no improvement" in result.reason.lower()

    def test_rejects_regression(self) -> None:
        from openjarvis.learning.spec_search.gate.benchmark_gate import (
            BenchmarkGate,
        )

        before = BenchmarkSnapshot(
            benchmark_version="v1",
            overall_score=0.7,
            cluster_scores={"c1": 0.6, "c2": 0.8},
            task_count=50,
            elapsed_seconds=10.0,
        )
        # overall improves but c2 regresses badly
        gate = BenchmarkGate(
            scorer=_make_scorer({"c1": 0.75, "c2": 0.65}, overall=0.72),
            benchmark_version="v1",
            min_improvement=0.0,
            max_regression=0.05,
            subsample_size=50,
        )
        result = gate.evaluate(before=before, session_seed=42)
        assert not result.accepted
        assert "regression" in result.reason.lower()

    def test_min_improvement_threshold(self) -> None:
        from openjarvis.learning.spec_search.gate.benchmark_gate import (
            BenchmarkGate,
        )

        before = BenchmarkSnapshot(
            benchmark_version="v1",
            overall_score=0.7,
            cluster_scores={"c1": 0.6, "c2": 0.8},
            task_count=50,
            elapsed_seconds=10.0,
        )
        # Tiny improvement of 0.01, but min_improvement requires 0.05
        gate = BenchmarkGate(
            scorer=_make_scorer({"c1": 0.61, "c2": 0.81}, overall=0.71),
            benchmark_version="v1",
            min_improvement=0.05,
            max_regression=0.05,
            subsample_size=50,
        )
        result = gate.evaluate(before=before, session_seed=42)
        assert not result.accepted

    def test_result_contains_snapshot(self) -> None:
        from openjarvis.learning.spec_search.gate.benchmark_gate import (
            BenchmarkGate,
        )

        before = BenchmarkSnapshot(
            benchmark_version="v1",
            overall_score=0.5,
            cluster_scores={"c1": 0.5},
            task_count=50,
            elapsed_seconds=10.0,
        )
        gate = BenchmarkGate(
            scorer=_make_scorer({"c1": 0.7}, overall=0.7),
            benchmark_version="v1",
            min_improvement=0.0,
            max_regression=0.05,
            subsample_size=50,
        )
        result = gate.evaluate(before=before, session_seed=42)
        assert isinstance(result.snapshot, BenchmarkSnapshot)
        assert result.snapshot.benchmark_version == "v1"
