"""
🔴 RED TDD: ScreenTopology — The Instagram HD Map

Tests for BFS pathfinding between Instagram screens.
The killer test: HOME_FEED → OWN_PROFILE → FOLLOW_LIST must be a 2-step route.
"""

import os
import sys

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../")))

from GramAddict.core.goap import ScreenType
from GramAddict.core.screen_topology import ScreenTopology


class TestScreenTopologyRouting:
    """BFS pathfinding must compute correct multi-step routes."""

    def test_route_home_to_following_list(self):
        """THE killer test: HomeFeed → OwnProfile → FollowList (2 hops)."""
        route = ScreenTopology.find_route(ScreenType.HOME_FEED, ScreenType.FOLLOW_LIST)
        assert route is not None, "Route from HOME_FEED to FOLLOW_LIST must exist"
        assert len(route) == 2, f"Expected 2 hops, got {len(route)}: {route}"
        assert route[0] == ("tap profile tab", ScreenType.OWN_PROFILE)
        assert route[1] == ("tap following list", ScreenType.FOLLOW_LIST)

    def test_route_already_there(self):
        """Same screen = empty route (no steps needed)."""
        route = ScreenTopology.find_route(ScreenType.HOME_FEED, ScreenType.HOME_FEED)
        assert route == []

    def test_route_single_hop(self):
        """Direct neighbor = 1 step."""
        route = ScreenTopology.find_route(ScreenType.HOME_FEED, ScreenType.EXPLORE_GRID)
        assert route is not None
        assert len(route) == 1
        assert route[0] == ("tap explore tab", ScreenType.EXPLORE_GRID)

    def test_route_reverse_direction(self):
        """FollowList back to HomeFeed: FollowList → OwnProfile → HomeFeed (2 hops)."""
        route = ScreenTopology.find_route(ScreenType.FOLLOW_LIST, ScreenType.HOME_FEED)
        assert route is not None
        assert len(route) == 2
        assert route[0][1] == ScreenType.OWN_PROFILE
        assert route[1][1] == ScreenType.HOME_FEED

    def test_no_route_from_unreachable(self):
        """FOREIGN_APP has no outbound transitions — route should be None."""
        route = ScreenTopology.find_route(ScreenType.FOREIGN_APP, ScreenType.FOLLOW_LIST)
        assert route is None


class TestGoalToTargetScreen:
    """Goal string → target ScreenType mapping."""

    def test_following_list_goal(self):
        assert ScreenTopology.goal_to_target_screen("open following list") == ScreenType.FOLLOW_LIST

    def test_followers_list_goal(self):
        assert ScreenTopology.goal_to_target_screen("open followers list") == ScreenType.FOLLOW_LIST

    def test_profile_goal(self):
        assert ScreenTopology.goal_to_target_screen("open profile") == ScreenType.OWN_PROFILE

    def test_home_feed_goal(self):
        assert ScreenTopology.goal_to_target_screen("open home feed") == ScreenType.HOME_FEED

    def test_explore_goal(self):
        assert ScreenTopology.goal_to_target_screen("open explore feed") == ScreenType.EXPLORE_GRID

    def test_messages_goal(self):
        assert ScreenTopology.goal_to_target_screen("open messages") == ScreenType.DM_INBOX

    def test_interaction_goal_returns_none(self):
        """Non-navigation goals should return None."""
        assert ScreenTopology.goal_to_target_screen("like this post") is None

    def test_unknown_goal_returns_none(self):
        assert ScreenTopology.goal_to_target_screen("do something random") is None


class TestGetTransitions:
    """Get available transitions from a screen."""

    def test_home_feed_has_profile_tab(self):
        transitions = ScreenTopology.get_transitions(ScreenType.HOME_FEED)
        assert "tap profile tab" in transitions
        assert transitions["tap profile tab"] == ScreenType.OWN_PROFILE

    def test_own_profile_has_following_list(self):
        transitions = ScreenTopology.get_transitions(ScreenType.OWN_PROFILE)
        assert "tap following list" in transitions
        assert transitions["tap following list"] == ScreenType.FOLLOW_LIST

    def test_unknown_screen_returns_empty(self):
        transitions = ScreenTopology.get_transitions(ScreenType.FOREIGN_APP)
        assert transitions == {}


class TestScreenNameMap:
    """Bidirectional QNavGraph string ↔ ScreenType mapping."""

    def test_following_list_maps(self):
        assert ScreenTopology.SCREEN_NAME_MAP["FollowingList"] == ScreenType.FOLLOW_LIST

    def test_home_feed_maps(self):
        assert ScreenTopology.SCREEN_NAME_MAP["HomeFeed"] == ScreenType.HOME_FEED

    def test_stories_feed_maps_to_home(self):
        """StoriesFeed is a virtual target — it maps to HOME_FEED."""
        assert ScreenTopology.SCREEN_NAME_MAP["StoriesFeed"] == ScreenType.HOME_FEED

    def test_search_feed_maps_to_explore(self):
        """SearchFeed is a virtual target — it maps to EXPLORE_GRID."""
        assert ScreenTopology.SCREEN_NAME_MAP["SearchFeed"] == ScreenType.EXPLORE_GRID


class TestScreenNameToGoal:
    """Convert QNavGraph screen name to GOAP goal string."""

    def test_following_list(self):
        assert ScreenTopology.screen_name_to_goal("FollowingList") == "open following list"

    def test_home_feed(self):
        assert ScreenTopology.screen_name_to_goal("HomeFeed") == "open home feed"

    def test_explore_feed(self):
        assert ScreenTopology.screen_name_to_goal("ExploreFeed") == "open explore feed"

    def test_stories_feed(self):
        """StoriesFeed → open home feed (stories are on home)."""
        assert ScreenTopology.screen_name_to_goal("StoriesFeed") == "open home feed"

    def test_unknown_target(self):
        assert ScreenTopology.screen_name_to_goal("BogusScreen") == "navigate to BogusScreen"


class TestExpectedScreenForAction:
    """Step-aware validation: what screen should an action land on?"""

    def test_tap_profile_tab_from_home(self):
        result = ScreenTopology.expected_screen_for_action("tap profile tab", ScreenType.HOME_FEED)
        assert result == ScreenType.OWN_PROFILE

    def test_tap_following_list_from_profile(self):
        result = ScreenTopology.expected_screen_for_action("tap following list", ScreenType.OWN_PROFILE)
        assert result == ScreenType.FOLLOW_LIST

    def test_press_back_from_follow_list(self):
        result = ScreenTopology.expected_screen_for_action("press back", ScreenType.FOLLOW_LIST)
        assert result == ScreenType.OWN_PROFILE

    def test_unknown_action_returns_none(self):
        result = ScreenTopology.expected_screen_for_action("do something random", ScreenType.HOME_FEED)
        assert result is None

    def test_action_not_available_on_screen(self):
        """'tap following list' from HOME_FEED should return None (not a valid transition)."""
        result = ScreenTopology.expected_screen_for_action("tap following list", ScreenType.HOME_FEED)
        assert result is None


class TestIsStructuralAction:
    """Topology guard: protect HD Map actions from aversive learning."""

    def test_tap_profile_tab_is_structural(self):
        assert ScreenTopology.is_structural_action(ScreenType.HOME_FEED, "tap profile tab") is True

    def test_tap_following_list_is_structural(self):
        assert ScreenTopology.is_structural_action(ScreenType.OWN_PROFILE, "tap following list") is True

    def test_random_action_is_not_structural(self):
        assert ScreenTopology.is_structural_action(ScreenType.HOME_FEED, "open following list") is False

    def test_action_on_wrong_screen_is_not_structural(self):
        """'tap following list' on HOME_FEED is NOT structural (not in that screen's transitions)."""
        assert ScreenTopology.is_structural_action(ScreenType.HOME_FEED, "tap following list") is False
