from unittest.mock import patch

from GramAddict.core.telepathic_engine import TelepathicEngine

FAILED_XML_PATH = "/Volumes/Alpha SSD/Coding/bot/debug/xml_dumps/manual_interrupt__2026-04-17_13-16-14.xml"


def test_modal_guard_blocks_nav_intent_on_failed_xml():
    """
    Test that the Modal Guard correctly identifies the bottom sheet in the failed XML
    and prevents searching for the 'Home Tab'.
    """
    # Replace hardcoded dump file with inline XML containing a modal to prevent skipping
    xml_content = """<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<hierarchy rotation="0">
  <node index="0" resource-id="com.instagram.android:id/bottom_sheet_container" class="android.widget.FrameLayout" package="com.instagram.android" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,900][1080,2400]" visible-to-user="true">
    <node index="0" text="Add comment" resource-id="com.instagram.android:id/comment_composer" class="android.widget.EditText" bounds="[42,2224][1038,2350]" visible-to-user="true" />
  </node>
  <node index="1" resource-id="com.instagram.android:id/tab_bar" bounds="[0,2200][1080,2400]" visible-to-user="false" />
</hierarchy>"""

    engine = TelepathicEngine()

    # Intent that SHOULD be blocked because Home Tab is obscured by the comment sheet
    intent = "tap home tab"

    # We don't want to trigger actual LLM/VLM calls during the test
    with patch("GramAddict.core.telepathic_engine.query_telepathic_llm") as mock_vlm:
        result = engine.find_best_node(xml_content, intent)

        # 1. Verify that no VLM call was even attempted because the Modal Guard should have caught it early
        assert mock_vlm.called is False, "VLM should not be called when a modal obscures the target zone."

        # 2. Result should be {'blocked_by_modal': True} (meaning 'Target blocked/missing')
        assert result == {
            "blocked_by_modal": True
        }, "Modal Guard should return block status for navigation intents when a sheet is open."


def test_zone_enforcement_blocks_mid_screen_tab_hallucination():
    """
    Tests that even if VLM is triggered (e.g. no modal detected but low confidence),
    any result for a 'tab' intent that is in the middle of the screen is rejected.
    """
    engine = TelepathicEngine()

    # Minimal XML
    xml = "<?xml version='1.0' ?><hierarchy><node index='0' text='Add comment' bounds='[42,2224][1038,2350]' visible-to-user='true' /></hierarchy>"

    intent = "tap home tab"

    # Mock VLM to return the 'Add comment' field which is at Y=2224 (0.917 of 2424)
    # Our guard enforces Tabs MUST be in the bottom 10% (Y > 0.90 * Height).
    # Wait, Y=2224 on H=2424 is 0.917. That IS in the bottom 10%.
    # Let's mock a node at Y=1000 (middle of screen) to test the guard.

    with patch("GramAddict.core.telepathic_engine.query_telepathic_llm") as mock_vlm:
        # Mock VLM returning a middle-screen element (Index 0)
        mock_vlm.return_value = '{"index": 0, "reason": "hallucination test"}'

        # Injected node at middle screen
        with patch.object(TelepathicEngine, "_extract_semantic_nodes") as mock_extract:
            mock_extract.return_value = [
                {
                    "index": 0,
                    "x": 500,
                    "y": 1000,
                    "width": 100,
                    "height": 100,
                    "area": 10000,
                    "raw_bounds": "[450,950][550,1050]",
                    "semantic_string": "text: 'Fake Home', id context: 'fake_tab'",
                }
            ]

            # We also need to patch _is_modal_active to False so it GETS to the VLM step
            with patch.object(TelepathicEngine, "_is_modal_active", return_value=False):
                result = engine.find_best_node(xml, intent)

    # Should be rejected because navigation tabs should be in the nav bar zone
    assert result is None, "Structural Guard should reject mid-screen navigation tab candidates."
