from unittest.mock import MagicMock, patch

from GramAddict.core.q_nav_graph import QNavGraph


def test_autonomous_retry_on_ambiguity_failure():
    """
    Verifies that _execute_transition uses an internal retry loop.
    If the first attempt fails semantic verification (Ambiguity Guard),
    it should press BACK, blacklist the node, and retry automatically.
    """
    mock_device = MagicMock()
    mock_device._get_current_app.side_effect = ["com.instagram.android"] * 100
    mock_device.app_id = "com.instagram.android"

    normal_xml = '<hierarchy><node package="com.instagram.android" /></hierarchy>'
    wrong_context = '<hierarchy><node package="com.instagram.android" text="wrong" /></hierarchy>'
    correct_context = '<hierarchy><node package="com.instagram.android" text="correct" /></hierarchy>'

    # Each attempt consumes:
    #  1. Initial context_xml dump
    #  2. Re-acquire dump (triggered because _clear_anomaly_obstacles returns True when NORMAL)
    #  3. Post-click verification dump
    # Attempt 1 → normal, normal, wrong_context  (verify=False → retry)
    # Attempt 2 → normal, normal, correct_context (verify=True → return True)
    mock_device.dump_hierarchy.side_effect = [
        normal_xml,  # Attempt 1: initial
        normal_xml,  # Attempt 1: re-acquire (cleared_something=True from SAE perceive=NORMAL)
        wrong_context,  # Attempt 1: post-click (verify_success=False)
        normal_xml,  # Attempt 2: initial
        normal_xml,  # Attempt 2: re-acquire
        correct_context,  # Attempt 2: post-click (verify_success=True)
    ] + [normal_xml] * 20

    mock_engine = MagicMock()
    # Return a different node on each find_best_node call (plus extras for safety)
    mock_engine.find_best_node.side_effect = [
        {"x": 10, "y": 10, "semantic_string": "Wrong Menu", "source": "vlm"},
        {"x": 20, "y": 20, "semantic_string": "Correct Grid", "source": "vlm"},
        {"x": 20, "y": 20, "semantic_string": "Correct Grid", "source": "vlm"},  # safety extra
    ]

    # Mock verify_success: fail first (triggering Ambiguity Guard), succeed second
    mock_engine.verify_success.side_effect = [False, True]

    nav_graph = QNavGraph(mock_device)

    with (
        patch("time.sleep"),
        patch("random.uniform"),
        patch("GramAddict.core.telepathic_engine.TelepathicEngine.get_instance", return_value=mock_engine),
    ):
        result = nav_graph._execute_transition("tap_grid_first_post", mock_semantic_engine=mock_engine)

    assert result is True, "Autonomous retry loop failed to complete successfully."
    assert mock_device.click.call_count >= 2, "Should have attempted at least two different coordinates."
    mock_engine.reject_click.assert_called()  # Should have rejected the first mapping
    mock_engine.confirm_click.assert_called()  # Should have confirmed the final successful mapping
