"""Tests for bandit feedback loop integration."""

import os
import tempfile

import pytest

from autodebug.strategies.bandit_selector import (
    StrategyStats,
    ThompsonSamplingSelector,
)


class TestBanditFeedbackLoop:
    """Test that the bandit selector updates work correctly."""

    def test_update_success(self):
        """Successful fix should increase success count."""
        selector = ThompsonSamplingSelector()

        selector.update("KeyError", "timing_strategy", success=True)

        stats = selector.get_stats("KeyError", "timing_strategy")
        assert stats.successes == 1
        assert stats.failures == 0

    def test_update_failure(self):
        """Failed fix should increase failure count."""
        selector = ThompsonSamplingSelector()

        selector.update("KeyError", "timing_strategy", success=False)

        stats = selector.get_stats("KeyError", "timing_strategy")
        assert stats.successes == 0
        assert stats.failures == 1

    def test_update_with_outcome_shaping(self):
        """Outcome type should affect reward."""
        selector = ThompsonSamplingSelector()

        # Modified fix gets partial credit (0.7)
        selector.update("KeyError", "timing_strategy", success=True, outcome="modified")

        stats = selector.get_stats("KeyError", "timing_strategy")
        assert stats.total_reward == pytest.approx(0.7)

    def test_multiple_updates_change_selection(self):
        """After many updates, good strategies should be preferred."""
        selector = ThompsonSamplingSelector()

        # Strategy A succeeds a lot
        for _ in range(20):
            selector.update("KeyError", "strategy_a", success=True)

        # Strategy B fails a lot
        for _ in range(20):
            selector.update("KeyError", "strategy_b", success=False)

        stats_a = selector.get_stats("KeyError", "strategy_a")
        stats_b = selector.get_stats("KeyError", "strategy_b")

        assert stats_a.success_rate > 0.9
        assert stats_b.success_rate < 0.1

    def test_persistence_roundtrip(self):
        """Stats should survive save/load cycle."""
        with tempfile.NamedTemporaryFile(suffix=".json", delete=False) as f:
            path = f.name

        try:
            # Create and update
            selector1 = ThompsonSamplingSelector(persistence_path=path)
            selector1.update("KeyError", "strategy_a", success=True)
            selector1.update("KeyError", "strategy_a", success=True)
            selector1.update("KeyError", "strategy_a", success=False)

            # Reload
            selector2 = ThompsonSamplingSelector(persistence_path=path)
            stats = selector2.get_stats("KeyError", "strategy_a")
            assert stats.successes == 2
            assert stats.failures == 1
        finally:
            os.unlink(path)


class TestStrategyStats:
    """Test StrategyStats dataclass."""

    def test_empty_stats_defaults(self):
        stats = StrategyStats()
        assert stats.total == 0
        assert stats.success_rate == 0.5  # Prior
        assert stats.confidence == 0.0

    def test_sample_returns_valid_range(self):
        stats = StrategyStats(successes=5, failures=5)
        for _ in range(100):
            sample = stats.sample()
            assert 0.0 <= sample <= 1.0

    def test_ucb_infinite_for_untried(self):
        stats = StrategyStats()
        assert stats.ucb_score(100) == float("inf")

    def test_apply_decay(self):
        stats = StrategyStats(successes=100, failures=50, total_reward=75.0)
        stats.apply_decay(0.5)
        assert stats.successes == 50
        assert stats.failures == 25
        assert stats.total_reward == pytest.approx(37.5)
