from unittest.mock import MagicMock

from GramAddict.core.q_nav_graph import QNavGraph
from GramAddict.core.telepathic_engine import TelepathicEngine


class TestProfileInteractionSync:
    """
    TDD Tests: Reproduces the 'Already Followed -> Favorites' and 'No Story Ring'
    bugs from 2026-04-17 live run.
    """

    def setup_method(self):
        self.engine = TelepathicEngine()
        self.mock_device = MagicMock()
        self.mock_device.deviceV2 = MagicMock()
        self.mock_device.app_id = "com.instagram.android"
        self.mock_device._get_current_app.return_value = "com.instagram.android"
        self.nav_graph = QNavGraph(self.mock_device)

    def test_prevent_tapping_following_button(self):
        """
        If the intent is to follow, but the matching node says 'following' or 'gefolgt',
        the engine must skip the click to prevent opening the Favorites/Mute bottom sheet.
        """
        # Simulate a profile where the user is already followed

        # Test vector-based matching fallback
        self.engine._blacklist = {}

        # Mock the parsing instead of old extraction
        self.engine._parser = MagicMock()
        self.engine._parser.parse.return_value = MagicMock()

        # We must return SpatialNode objects for the new architecture
        from GramAddict.core.perception.spatial_parser import SpatialNode

        mock_node = SpatialNode(MagicMock())
        mock_node.resource_id = "com.instagram.android:id/button"
        mock_node.text = "Following"
        mock_node.bounds = [500, 600, 600, 650]
        self.engine._parser.get_clickable_nodes.return_value = [mock_node]

        self.engine._structural_sanity_check = MagicMock(return_value=True)
        self.engine._is_instagram_context = MagicMock(return_value=True)

        # Mock resolver to return our mock node
        self.engine._resolver = MagicMock()
        self.engine._resolver.resolve.return_value = mock_node

        result = self.engine.find_best_node("<mock></mock>", "tap follow button on profile", device=self.mock_device)

        assert result is not None, "Engine should return a skip result, not None"
        assert result.get("skip") is True, "Must return skip: True to prevent Favorites menu from opening"
        assert result.get("semantic") == "already_followed"

    def test_story_ring_not_present_skips_click(self):
        """
        If no story ring is explicitly in the XML, bot_flow should not execute
        the transition (simulated here by checking our XML evaluation logic).
        """
        xml_without_story = """
        <hierarchy>
          <node resource-id="com.instagram.android:id/row_profile_header_imageview" content-desc="Profile picture" />
          <node text="marisaundmarc" />
        </hierarchy>
        """

        has_story = (
            "reel_ring" in xml_without_story
            or "unseen story" in xml_without_story.lower()
            or "story von" in xml_without_story.lower()
        )

        assert has_story is False, "Logic falsely identified a story when there is only a generic profile picture"

    def test_story_ring_present_allows_click(self):
        """
        If a story ring is present, the logic should allow the interaction.
        """
        xml_with_story = """
        <hierarchy>
          <node resource-id="com.instagram.android:id/reel_ring" />
          <node resource-id="com.instagram.android:id/row_profile_header_imageview" content-desc="mercedesbenz_de's unseen story" />
        </hierarchy>
        """

        has_story = (
            "reel_ring" in xml_with_story
            or "unseen story" in xml_with_story.lower()
            or "story von" in xml_with_story.lower()
        )

        assert has_story is True, "Logic failed to identify active story ring"
