"""Tests for the rollback mechanism."""

from unittest.mock import AsyncMock, patch

import pytest

from api.ai.rollback import FixRollback, RollbackResult


class TestFixRollback:
    """Test the fix rollback mechanism."""

    @pytest.mark.asyncio
    async def test_no_event_found(self):
        """Should not rollback if no event found for PR."""
        rollback = FixRollback(org_id="org_1")

        with patch("api.ai.rollback.get_self_heal_event_by_pr", return_value=None):
            result = await rollback.check_and_rollback(
                pr_url="https://github.com/test/repo/pull/1",
                new_failures=[],
            )

        assert result.should_rollback is False
        assert "No self-heal event" in result.reason

    @pytest.mark.asyncio
    async def test_no_new_failures(self):
        """Should not rollback if no new failures."""
        rollback = FixRollback(org_id="org_1")

        mock_event = {
            "id": "evt_1",
            "test_name": "test_flaky",
            "org_id": "org_1",
        }

        with patch("api.ai.rollback.get_self_heal_event_by_pr", return_value=mock_event):
            result = await rollback.check_and_rollback(
                pr_url="https://github.com/test/repo/pull/1",
                new_failures=[],
            )

        assert result.should_rollback is False
        assert "No new failures" in result.reason

    @pytest.mark.asyncio
    async def test_rollback_on_correlated_failures(self):
        """Should rollback if fix caused failures in the same test or module."""
        rollback = FixRollback(org_id="org_1")

        mock_event = {
            "id": "evt_1",
            "test_name": "tests.test_auth::test_flaky",
            "org_id": "org_1",
        }

        mock_manager = AsyncMock()

        with patch("api.ai.rollback.get_self_heal_event_by_pr", return_value=mock_event), \
             patch("api.ai.rollback.update_self_heal_event") as mock_update, \
             patch("api.ai.rollback.QuarantineManager", return_value=mock_manager), \
             patch.object(rollback, "_create_revert_pr", return_value="https://github.com/test/repo/pull/2"):

            result = await rollback.check_and_rollback(
                pr_url="https://github.com/test/repo/pull/1",
                new_failures=[
                    {"test_name": "tests.test_auth::test_flaky"},
                    {"test_name": "tests.test_auth::test_login"},
                ],
            )

        assert result.should_rollback is True
        assert len(result.affected_tests) == 2
        assert result.revert_pr_url == "https://github.com/test/repo/pull/2"
        mock_update.assert_called_once()

    @pytest.mark.asyncio
    async def test_no_rollback_on_uncorrelated_failures(self):
        """Should NOT rollback if new failures are in unrelated modules."""
        rollback = FixRollback(org_id="org_1")

        mock_event = {
            "id": "evt_1",
            "test_name": "tests.test_auth::test_flaky",
            "org_id": "org_1",
        }

        with patch("api.ai.rollback.get_self_heal_event_by_pr", return_value=mock_event):
            result = await rollback.check_and_rollback(
                pr_url="https://github.com/test/repo/pull/1",
                new_failures=[
                    {"test_name": "tests.test_billing::test_checkout"},
                    {"test_name": "tests.test_worker::test_queue"},
                ],
            )

        assert result.should_rollback is False
        assert "not correlated" in result.reason

    @pytest.mark.asyncio
    async def test_rollback_result_dataclass(self):
        """Test RollbackResult fields."""
        result = RollbackResult(
            should_rollback=True,
            reason="test reason",
            affected_tests=["test_a", "test_b"],
            revert_pr_url="https://github.com/test/repo/pull/2",
            original_event_id="evt_1",
        )

        assert result.should_rollback is True
        assert result.reason == "test reason"
        assert len(result.affected_tests) == 2
        assert result.revert_pr_url is not None
        assert result.original_event_id == "evt_1"
