from unittest.mock import MagicMock, patch

import pytest

from GramAddict.core.behaviors import BehaviorContext
from GramAddict.core.behaviors.ad_guard import AdGuardPlugin


@pytest.fixture
def ad_guard():
    plugin = AdGuardPlugin()
    return plugin


@pytest.fixture
def mock_context():
    device = MagicMock()
    configs = MagicMock()
    session_state = MagicMock()
    # Mocking cognitive stack to have qdrant_memory
    memory = MagicMock()
    # Mocking radome for xml sanitization
    radome = MagicMock()
    radome.sanitize_xml.return_value = "<xml>dummy</xml>"

    # Mocking nav_graph for escape
    nav_graph = MagicMock()

    # Mocking zero_latency_engine
    zero_engine = MagicMock()

    cognitive_stack = {
        "qdrant_memory": memory,
        "radome": radome,
        "nav_graph": nav_graph,
        "zero_latency_engine": zero_engine,
    }

    ctx = BehaviorContext(device=device, configs=configs, session_state=session_state, cognitive_stack=cognitive_stack)
    return ctx


class TestAdGuardPlugin:
    @patch("GramAddict.core.behaviors.ad_guard.is_ad")
    def test_can_activate(self, mock_is_ad, ad_guard, mock_context):
        mock_context.context_xml = "<xml>dummy</xml>"
        mock_is_ad.return_value = True
        assert ad_guard.can_activate(mock_context) is True

        mock_is_ad.return_value = False
        assert ad_guard.can_activate(mock_context) is False

        ad_guard._enabled = False
        assert ad_guard.can_activate(mock_context) is False

    @patch("GramAddict.core.behaviors.ad_guard.sleep")
    @patch("GramAddict.core.behaviors.ad_guard.humanized_scroll")
    def test_execute_single_ad(self, mock_scroll, mock_sleep, ad_guard, mock_context):
        result = ad_guard.execute(mock_context)

        assert result.executed is True
        assert ad_guard.consecutive_ads == 1
        mock_scroll.assert_called_once_with(mock_context.device, is_skip=True)
        mock_sleep.assert_called_once()

    @patch("GramAddict.core.behaviors.ad_guard.sleep")
    @patch("GramAddict.core.behaviors.ad_guard.humanized_scroll")
    def test_execute_triple_ad(self, mock_scroll, mock_sleep, ad_guard, mock_context):
        ad_guard.consecutive_ads = 2

        result = ad_guard.execute(mock_context)

        assert result.executed is True
        assert ad_guard.consecutive_ads == 3
        # Should do aggressive double skip
        assert mock_scroll.call_count == 2
        mock_sleep.assert_called()

    @patch("GramAddict.core.behaviors.ad_guard.sleep")
    @patch("GramAddict.core.behaviors.ad_guard.humanized_scroll")
    def test_execute_deadlock_ad(self, mock_scroll, mock_sleep, ad_guard, mock_context):
        ad_guard.consecutive_ads = 5

        result = ad_guard.execute(mock_context)

        assert result.executed is True
        assert ad_guard.consecutive_ads == 0  # Resets after home feed escape

        nav_graph = mock_context.cognitive_stack["nav_graph"]
        zero_engine = mock_context.cognitive_stack["zero_latency_engine"]
        nav_graph.navigate_to.assert_called_once_with("HomeFeed", zero_engine)
