from unittest.mock import MagicMock, patch

from GramAddict.core.bot_flow import _run_zero_latency_feed_loop


@patch("GramAddict.core.behaviors.PluginRegistry.get_instance")
@patch("GramAddict.core.bot_flow.sleep")
@patch("GramAddict.core.bot_flow._humanized_scroll")
@patch("GramAddict.core.bot_flow._extract_post_content")
@patch("GramAddict.core.bot_flow._align_active_post")
@patch("GramAddict.core.telepathic_engine.TelepathicEngine.get_instance")
def test_plugin_skip_breaks_feed_loop(
    mock_telepathic, mock_align, mock_extract, mock_scroll, mock_sleep, mock_registry_get_instance
):
    # Setup mocks
    device = MagicMock()
    zero_engine = MagicMock()
    nav_graph = MagicMock()
    configs = MagicMock()
    session_state = MagicMock()

    # Cognitive stack setup
    cognitive_stack = {
        "dopamine": MagicMock(),
        "darwin": MagicMock(),
        "resonance": MagicMock(),
        "active_inference": MagicMock(),
    }

    # Dopamine should not abort the session on first run, but abort on second
    cognitive_stack["dopamine"].is_app_session_over.side_effect = [False, True]

    mock_align.return_value = False

    device.dump_hierarchy.return_value = "<xml>row_feed_photo_profile_name</xml>"
    mock_telepathic_instance = MagicMock()
    mock_telepathic_instance._extract_semantic_nodes.return_value = [{"x": 10}]
    mock_telepathic.return_value = mock_telepathic_instance
    mock_extract.return_value = {"username": "test", "description": "", "caption": ""}

    # Setup PluginRegistry to return a skip result
    mock_registry_instance = MagicMock()
    mock_plugin_result = MagicMock()
    mock_plugin_result.executed = True
    mock_plugin_result.should_skip = True
    mock_registry_instance.execute_all.return_value = [mock_plugin_result]
    mock_registry_get_instance.return_value = mock_registry_instance

    _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session_state, "HomeFeed", cognitive_stack)

    # Assert that because should_skip was True, active_inference.predict_state was NEVER called
    # (Meaning the 'continue' correctly bypassed the rest of the feed loop)
    cognitive_stack["active_inference"].predict_state.assert_not_called()
