import pytest

from GramAddict.core.perception.intent_resolver import IntentResolver
from GramAddict.core.perception.spatial_parser import SpatialNode


@pytest.fixture
def resolver():
    return IntentResolver()


def test_clips_author_fast_path(resolver):
    """
    Ensures that Reel author usernames are resolved via the clips_author_username fast-path.
    """
    reel_author_node = SpatialNode(
        resource_id="com.instagram.android:id/clips_author_username", text="maor.benezri", bounds=(0, 0, 100, 100)
    )

    result = resolver.resolve("tap post username", [reel_author_node])
    assert result is not None
    assert result.resource_id == "com.instagram.android:id/clips_author_username"


def test_scrubber_blacklist_for_author_intent(resolver):
    """
    Ensures that the seeker/scrubber bar is filtered out for author intents.
    """
    scrubber_node = SpatialNode(
        resource_id="com.instagram.android:id/scrubber",
        text="32291.0",
        content_desc="@2131978468",
        bounds=(0, 0, 500, 10),
    )

    # We need a mock device that supports screenshots to enter _visual_discovery
    # where filter_navigation_conflicts is called for visual intents.
    class MockDevice:
        def screenshot(self):
            return None

        @property
        def deviceV2(self):
            return self

    # Since we can't easily mock the VLM response here without more setup,
    # we test filter_navigation_conflicts directly.
    candidates = [scrubber_node]
    filtered = resolver.filter_navigation_conflicts(candidates, "tap post username")

    assert scrubber_node not in filtered, "Scrubber should be filtered out for author intents"


def test_interaction_guard_excludes_scrubber_for_author(resolver):
    """
    Verifies that the interaction guard correctly identifies and excludes the scrubber.
    """
    scrubber_node = SpatialNode(
        resource_id="com.instagram.android:id/scrubber",
        text="32291.0",
        content_desc="@2131978468",
        bounds=(0, 0, 500, 10),
    )

    filtered = resolver.filter_navigation_conflicts([scrubber_node], "post author username")
    assert len(filtered) == 0, "Interaction guard should have excluded the scrubber"


def test_telepathic_grid_selection_uses_structural_id(monkeypatch):
    """
    Ensures TelepathicEngine prefers grid_card_layout_container for grid candidates.
    """
    from GramAddict.core.telepathic_engine import TelepathicEngine

    engine = TelepathicEngine()

    # Mock nodes
    grid_node = SpatialNode(
        resource_id="com.instagram.android:id/grid_card_layout_container", bounds=(10, 10, 300, 300)
    )
    background_node = SpatialNode(
        resource_id="com.instagram.android:id/swipeable_nav_view_pager_inner_recycler_view", bounds=(0, 0, 1080, 2400)
    )

    # Use monkeypatch instead of MagicMock
    monkeypatch.setattr(engine._parser, "parse", lambda x: "mock_root")
    monkeypatch.setattr(engine._parser, "get_all_nodes", lambda x: [grid_node, background_node])

    candidates_captured = []

    def mock_evaluate(device, persona_interests, candidates):
        candidates_captured.extend(candidates)
        return grid_node

    monkeypatch.setattr(engine._evaluator, "evaluate_grid_visuals", mock_evaluate)

    class MockDevice:
        def dump_hierarchy(self):
            return "<xml/>"

    engine.evaluate_grid_visuals(MockDevice(), ["travel"])

    assert background_node not in candidates_captured, "Background recycler view should not be a grid candidate"
