"""
🔴 RED TDD: GOAP False Unlearning Fix

Reproduces Bug 3: The bot taps 'home tab' while ALREADY on home_feed,
detects 'no UI change', and destructively unlearns the correct mapping.

These tests MUST FAIL before the fix and PASS after.
"""

from unittest.mock import MagicMock, patch

from GramAddict.core.goap import GoalExecutor, ScreenType


def _make_goap(screen_type=ScreenType.HOME_FEED, available_actions=None):
    """Create a GoalExecutor with a mocked device that returns a fixed screen state."""
    device = MagicMock()
    device.app_id = "com.instagram.android"
    device._get_current_app.return_value = "com.instagram.android"

    goap = GoalExecutor(device, bot_username="testbot")
    goap._sae = MagicMock()
    goap._sae.ensure_clear_screen.return_value = True

    # Mock perceive to return a fixed screen state
    if available_actions is None:
        available_actions = ["tap profile tab", "tap explore tab", "scroll down", "press back", "tap home tab"]

    goap.perceive = MagicMock(
        return_value={
            "screen_type": screen_type,
            "available_actions": available_actions,
            "context": {},
            "selected_tab": "feed_tab",
        }
    )

    return goap


class TestGoapRecalledPathPreCheck:
    """Bug 3 Part A: Recalled path should skip execution when goal is already achieved."""

    def test_recalled_path_skips_when_goal_already_achieved(self):
        """
        If the bot is already on HOME_FEED and the goal is 'open home feed',
        _execute_recalled_path must return True WITHOUT executing any steps.
        """
        goap = _make_goap(screen_type=ScreenType.HOME_FEED)

        steps = [{"action": "tap home tab"}]

        # Mock _execute_action to track if it was called
        goap._execute_action = MagicMock(return_value=True)

        result = goap._execute_recalled_path(steps, "open home feed")

        assert result is True, "Recalled path should succeed immediately when goal is already achieved."
        (
            goap._execute_action.assert_not_called(),
            ("_execute_action should NOT have been called — goal was already achieved."),
        )


class TestGoapNoUnlearnWhenAlreadyOnTarget:
    """Bug 3 Part B: Navigation to current screen should not trigger reject_click."""

    def test_no_unlearn_when_tapping_home_on_home_feed(self):
        """
        If the bot is on HOME_FEED and taps 'home tab', the XML won't change.
        But since the goal 'open home feed' is already achieved, the action
        should be treated as SUCCESS, not FAILURE.
        """
        goap = _make_goap(screen_type=ScreenType.HOME_FEED)

        # Make dump_hierarchy return the same XML (no change)
        static_xml = "<hierarchy><node resource-id='feed_tab' text='Home' /></hierarchy>"
        goap.device.dump_hierarchy.return_value = static_xml

        # Mock the TelepathicEngine
        mock_engine = MagicMock()
        mock_engine.find_best_node.return_value = {
            "x": 540,
            "y": 2300,
            "score": 0.95,
            "semantic": "description: 'Home', id context: 'feed tab'",
            "source": "qdrant_nav",
            "original_attribs": {},
        }

        with patch("GramAddict.core.telepathic_engine.TelepathicEngine.get_instance", return_value=mock_engine):
            result = goap._execute_action("tap home tab", goal="open home feed")

        # The action should succeed (we're already where we need to be)
        assert result is True, (
            "GOAP incorrectly treated 'tap home tab' on home_feed as a failure. "
            "This causes destructive unlearning of valid navigation knowledge."
        )

        # Critically: reject_click should NEVER have been called
        (
            mock_engine.reject_click.assert_not_called(),
            ("reject_click was called — this destroys the correct 'tap home tab' → 'feed tab' mapping!"),
        )

    def test_genuine_navigation_failure_still_triggers_reject(self):
        """
        If the bot is on HOME_FEED and taps 'tap explore tab' but nothing changes,
        that IS a genuine failure and reject_click SHOULD be called.
        """
        goap = _make_goap(screen_type=ScreenType.HOME_FEED)

        static_xml = "<hierarchy><node resource-id='feed_tab' text='Home' /></hierarchy>"
        goap.device.dump_hierarchy.return_value = static_xml

        mock_engine = MagicMock()
        mock_engine.find_best_node.return_value = {
            "x": 540,
            "y": 2300,
            "score": 0.95,
            "semantic": "description: 'Explore', id context: 'explore_tab'",
            "source": "qdrant_nav",
            "original_attribs": {},
        }

        with patch("GramAddict.core.telepathic_engine.TelepathicEngine.get_instance", return_value=mock_engine):
            result = goap._execute_action("tap explore tab", goal="open explore feed")

        # This should fail — we expected to go to explore but UI didn't change
        assert result is False, (
            "GOAP should reject a navigation that produced no UI change " "when the goal is NOT already achieved."
        )
