from unittest.mock import MagicMock

from GramAddict.core.q_nav_graph import QNavGraph
from GramAddict.core.situational_awareness import SituationType


def test_app_perimeter_guard_after_click():
    """
    Simulates a catastrophic VLM hallucination where clicking an element
    (e.g., an ad) causes the OS to switch to another app (e.g., Google Play Store).
    The QNavGraph MUST detect this post-click, reject the telemetry,
    and return CONTEXT_LOST immediately to prevent memory poisoning.
    """
    mock_device = MagicMock()
    # Initial state is Instagram
    mock_device._get_current_app.side_effect = [
        "com.android.vending",  # POST-CLICK verification at line 361 (App drifted!)
        "com.android.vending",  # double check after BACK press in recovery
        "com.android.vending",  # fallback start check if needed
    ] + ["com.android.vending"] * 50
    mock_device.app_id = "com.instagram.android"

    state_counter = {"calls": 0}

    def dynamic_xml():
        state_counter["calls"] += 1
        if state_counter["calls"] <= 2:
            return '<hierarchy><node resource-id="com.instagram.android:id/row_feed_photo_profile_name" /></hierarchy>'
        return '<hierarchy><node resource-id="play_store_ui" /></hierarchy>'

    mock_device.dump_hierarchy.side_effect = dynamic_xml

    # Mock Telepathic Engine
    mock_engine = MagicMock()
    mock_engine.find_best_node.return_value = {
        "x": 50,
        "y": 50,
        "semantic_string": "fake profile link",
        "source": "vlm",
        "score": 1.0,
    }
    mock_engine.verify_success.return_value = True

    # Mock SAE to be hermetic (no real Ollama calls)
    mock_sae = MagicMock()
    # Before click: no obstacles (return False = nothing cleared)
    # After click: detect foreign app
    mock_sae.ensure_clear_screen.return_value = False
    mock_sae.perceive.return_value = SituationType.OBSTACLE_FOREIGN_APP

    nav_graph = QNavGraph.__new__(QNavGraph)
    nav_graph.device = mock_device
    nav_graph.nodes = {}
    nav_graph.current_state = "UNKNOWN"
    nav_graph.nav_memory = MagicMock()
    nav_graph.sae = mock_sae
    nav_graph.goap = MagicMock()
    nav_graph.compiler = MagicMock()

    # Execute the transition
    result = nav_graph._execute_transition("tap_post_username", mock_semantic_engine=mock_engine)

    # 1. It must return CONTEXT_LOST without saving to memory
    assert result == "CONTEXT_LOST", f"Did not return CONTEXT_LOST after app drifted to Play Store! Got: {result}"

    # 2. It MUST NOT confirm the click and poison telemetry!
    mock_engine.confirm_click.assert_not_called()

    # 3. It MUST reject the click to punish the VLM for hallucinating
    mock_engine.reject_click.assert_called_once()
