from unittest.mock import MagicMock, patch

import pytest

from GramAddict.core.behaviors import BehaviorContext
from GramAddict.core.behaviors.anomaly_handler import AnomalyHandlerPlugin


@pytest.fixture
def anomaly_handler():
    plugin = AnomalyHandlerPlugin()
    return plugin


@pytest.fixture
def mock_context():
    device = MagicMock()
    configs = MagicMock()
    session_state = MagicMock()

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


class TestAnomalyHandlerPlugin:
    def test_can_activate(self, anomaly_handler, mock_context):
        assert anomaly_handler.can_activate(mock_context) is True

    @patch("GramAddict.core.behaviors.anomaly_handler.TelepathicEngine")
    @patch("GramAddict.core.behaviors.anomaly_handler.sleep")
    @patch("GramAddict.core.behaviors.anomaly_handler.humanized_scroll")
    def test_execute_with_nodes(self, mock_scroll, mock_sleep, mock_telepathic, anomaly_handler, mock_context):
        mock_instance = MagicMock()
        mock_instance._extract_semantic_nodes.return_value = [{"node": "dummy"}]
        mock_telepathic.get_instance.return_value = mock_instance

        result = anomaly_handler.execute(mock_context)

        # It shouldn't execute exclusive action, but it should populate shared_state
        assert result.executed is False
        assert mock_context.shared_state["interactive_nodes"] == [{"node": "dummy"}]
        mock_scroll.assert_not_called()

    @patch("GramAddict.core.behaviors.anomaly_handler.TelepathicEngine")
    @patch("GramAddict.core.behaviors.anomaly_handler.sleep")
    @patch("GramAddict.core.behaviors.anomaly_handler.humanized_scroll")
    def test_execute_zero_nodes(self, mock_scroll, mock_sleep, mock_telepathic, anomaly_handler, mock_context):
        mock_instance = MagicMock()
        mock_instance._extract_semantic_nodes.return_value = []
        mock_telepathic.get_instance.return_value = mock_instance

        result = anomaly_handler.execute(mock_context)

        # Should execute recovery
        assert result.executed is True
        assert mock_context.shared_state["interactive_nodes"] == []
        mock_context.device.press.assert_called_once_with("back")
        mock_scroll.assert_called_once()
        assert mock_sleep.call_count == 2
