from unittest.mock import MagicMock, patch

import pytest

from GramAddict.core.goap import GoalPlanner, NavigationKnowledge, ScreenType


@pytest.fixture
def mock_db():
    with patch("GramAddict.core.goap.QdrantBase") as MockBase:
        mock_instance = MagicMock()
        mock_instance.is_connected = True
        mock_instance._get_embedding.return_value = [0.1] * 768

        # Simulate an empty scroll result initially
        mock_instance.client.scroll.return_value = ([], None)

        MockBase.return_value = mock_instance
        yield mock_instance


def test_learn_trap_persists_and_filters_actions(mock_db):
    """
    TDD Test: Verify that aversive learning (Traps) prevents the agent
    from planning navigation through a burned action.
    """
    knowledge = NavigationKnowledge("test_user")

    # Simulate a blank start where the agent sees these actions
    available_actions = ["tap home tab", "tap profile tab", "tap external ad"]
    screen_type = ScreenType.EXPLORE_GRID

    # 1. Initially, no actions are traps
    for action in available_actions:
        assert not knowledge.is_trap(screen_type, action), f"Action {action} should not be a trap yet."

    # 2. Agent clicks the ad, gets sent to a foreign app, and learns it's a trap
    trap_action = "tap external ad"
    knowledge.learn_trap(screen_type, trap_action, trap_reason="foreign_app_triggered")

    # Verify DB was called to persist
    mock_db.upsert_point.assert_called()

    # 3. Verify it's now recognized as a trap
    assert knowledge.is_trap(screen_type, trap_action)
    assert not knowledge.is_trap(screen_type, "tap profile tab")

    # 4. Verify GoalPlanner filters it during Blank Start
    planner = GoalPlanner(username="test_user")
    planner.knowledge = knowledge

    planner.knowledge.get_requirements = MagicMock(return_value=[])
    planner.knowledge.get_screen_for_action = MagicMock(return_value=None)

    # Since there are no known mappings, it will guess from available via linguistic match.
    # We must ensure 'tap external ad' is filtered out.
    selected_action = planner._plan_navigation(
        goal="open profile", screen_type=screen_type, available=available_actions
    )

    # The guesser should select 'tap profile tab' because it linguistically matches 'profile'
    assert selected_action == "tap profile tab"
