from unittest.mock import MagicMock, patch

import pytest

from GramAddict.core.bot_flow import _interact_with_profile, _run_zero_latency_feed_loop


@pytest.fixture
def mock_device():
    device = MagicMock()
    device.get_info.return_value = {"displayWidth": 1080, "displayHeight": 2400}
    device.get_screenshot_b64.return_value = "fake_base64"

    class Args:
        ignore_close_friends = True
        visual_vibe_check_percentage = "0"
        scrape_profiles = False
        follow_percentage = "100"
        likes_percentage = "100"

    device.args = Args()

    # Mock XML with "Enge Freunde" badge in feed
    device.dump_hierarchy.return_value = """<?xml version="1.0"?>
    <hierarchy>
        <node resource-id="com.instagram.android:id/row_feed_photo_profile_name" text="my_real_friend" />
        <node resource-id="com.instagram.android:id/secondary_label" text="Enge Freunde" />
        <node resource-id="com.instagram.android:id/row_feed_photo_imageview" content-desc="Photo by my_real_friend." />
        <node resource-id="com.instagram.android:id/button_like" bounds="[50,50][60,60]" />
    </hierarchy>"""
    return device


@pytest.fixture
def mock_configs(mock_device):
    configs = MagicMock()
    configs.args = mock_device.args
    return configs


def test_ignore_close_friends_in_feed(mock_device, mock_configs):
    # Setup test env
    zero_engine = MagicMock()
    nav_graph = MagicMock()
    session_state = MagicMock()
    session_state.my_username = "bot_account"
    cognitive_stack = {"radome": MagicMock(), "dopamine": MagicMock(), "resonance": MagicMock()}

    cognitive_stack["radome"].sanitize_xml.side_effect = lambda x: x
    cognitive_stack["dopamine"].wants_to_doomscroll.return_value = False
    cognitive_stack["resonance"].evaluate_interaction.return_value = {"should_interact": True}

    # Run a single loop iteration (we mock _humanized_scroll to raise StopIteration to break the loop)
    with patch("GramAddict.core.bot_flow._humanized_scroll", side_effect=StopIteration):
        try:
            _run_zero_latency_feed_loop(
                mock_device, zero_engine, nav_graph, mock_configs, session_state, "Feed", cognitive_stack
            )
        except StopIteration:
            pass

    # Verify nav_graph.do("tap heart") or similar was NEVER called (because it was skipped!)
    nav_calls = [
        call for call in nav_graph.do.call_args_list if "like" in str(call).lower() or "heart" in str(call).lower()
    ]
    assert len(nav_calls) == 0


def test_ignore_close_friends_profile_guard(mock_device, mock_configs):
    logger = MagicMock()
    session_state = MagicMock()
    session_state.my_username = "bot_account"

    # Dump hierarchy for profile with Close Friend indicator
    mock_device.dump_hierarchy.return_value = """<?xml version="1.0"?>
    <hierarchy>
        <node resource-id="com.instagram.android:id/profile_header_full_name" text="My Real Friend" />
        <node resource-id="com.instagram.android:id/button_text" text="Enge Freunde" />
        <node resource-id="com.instagram.android:id/row_profile_header_textview_followers_count" text="10.5K" />
    </hierarchy>"""

    with patch("GramAddict.core.q_nav_graph.QNavGraph.do") as mock_do:
        _interact_with_profile(mock_device, mock_configs, "my_real_friend", session_state, 1.0, logger, {})

        # Verify no interaction happened on profile
        assert not mock_do.called
