"""
TDD: ContextGate Action Compatibility Matrix

Tests that the ContextGate blocks ALL structurally impossible actions,
not just the ones that happen to have matching resource-id markers.

Red-Green-Blue: These tests MUST fail first, then we implement.
"""

import pytest

from GramAddict.core.perception.context_gate import ContextGate
from GramAddict.core.perception.screen_identity import ScreenType


@pytest.fixture
def gate():
    return ContextGate()


def _make_screen(screen_type: ScreenType, resource_ids=None):
    """Helper to create a minimal screen_state dict."""
    return {
        "screen_type": screen_type,
        "resource_ids": resource_ids or set(),
        "available_actions": [],
        "context": {},
    }


class TestContextGateCategoricalBans:
    """P2-2: Every screen/action combination that is structurally impossible
    must be categorically banned — not reliant on marker presence."""

    def test_save_blocked_on_story_view(self, gate):
        """Cannot save on STORY_VIEW — no bookmark button exists."""
        screen = _make_screen(ScreenType.STORY_VIEW)
        assert gate.is_allowed("save", screen) is False

    def test_repost_blocked_on_story_view(self, gate):
        """Cannot repost on STORY_VIEW — only share button, no repost."""
        screen = _make_screen(ScreenType.STORY_VIEW)
        assert gate.is_allowed("repost", screen) is False

    def test_like_allowed_on_story_view(self, gate):
        """Stories have toolbar_like_button — like IS valid."""
        screen = _make_screen(ScreenType.STORY_VIEW)
        assert gate.is_allowed("like", screen) is True

    def test_comment_allowed_on_story_view(self, gate):
        """Stories have reel_viewer_comments_button — comment/reply IS valid."""
        screen = _make_screen(ScreenType.STORY_VIEW)
        assert gate.is_allowed("comment", screen) is True

    def test_follow_allowed_on_story_view(self, gate):
        """Stories have reel_header_unconnected_follow_button_stub."""
        screen = _make_screen(ScreenType.STORY_VIEW)
        assert gate.is_allowed("follow", screen) is True

    def test_like_blocked_on_follow_list(self, gate):
        """Cannot like on FOLLOW_LIST — it's a list of users, not posts."""
        screen = _make_screen(ScreenType.FOLLOW_LIST)
        assert gate.is_allowed("like", screen) is False

    def test_comment_blocked_on_follow_list(self, gate):
        """Cannot comment on FOLLOW_LIST."""
        screen = _make_screen(ScreenType.FOLLOW_LIST)
        assert gate.is_allowed("comment", screen) is False

    def test_comment_blocked_on_explore_grid(self, gate):
        """Cannot comment on EXPLORE_GRID — it's a grid of thumbnails."""
        screen = _make_screen(ScreenType.EXPLORE_GRID)
        assert gate.is_allowed("comment", screen) is False

    def test_save_blocked_on_dm_inbox(self, gate):
        """Cannot save on DM_INBOX."""
        screen = _make_screen(ScreenType.DM_INBOX)
        assert gate.is_allowed("save", screen) is False

    def test_save_blocked_on_dm_thread(self, gate):
        """Cannot save on DM_THREAD."""
        screen = _make_screen(ScreenType.DM_THREAD)
        assert gate.is_allowed("save", screen) is False

    def test_follow_blocked_on_home_feed(self, gate):
        """Cannot follow from HOME_FEED — there's no follow button on feed posts."""
        screen = _make_screen(ScreenType.HOME_FEED)
        assert gate.is_allowed("follow", screen) is False

    def test_follow_blocked_on_explore_grid(self, gate):
        """Cannot follow from EXPLORE_GRID."""
        screen = _make_screen(ScreenType.EXPLORE_GRID)
        assert gate.is_allowed("follow", screen) is False

    def test_repost_blocked_on_follow_list(self, gate):
        """Cannot repost from FOLLOW_LIST."""
        screen = _make_screen(ScreenType.FOLLOW_LIST)
        assert gate.is_allowed("repost", screen) is False


class TestContextGatePositiveCases:
    """Ensure that valid actions are NOT blocked."""

    def test_like_allowed_on_post_detail(self, gate):
        """Like IS valid on POST_DETAIL with proper markers."""
        screen = _make_screen(ScreenType.POST_DETAIL, {"row_feed_button_like", "row_feed_button_comment"})
        assert gate.is_allowed("like", screen) is True

    def test_comment_allowed_on_post_detail(self, gate):
        """Comment IS valid on POST_DETAIL with proper markers."""
        screen = _make_screen(ScreenType.POST_DETAIL, {"row_feed_button_comment", "row_feed_button_like"})
        assert gate.is_allowed("comment", screen) is True

    def test_follow_allowed_on_other_profile(self, gate):
        """Follow IS valid on OTHER_PROFILE with proper markers."""
        screen = _make_screen(ScreenType.OTHER_PROFILE, {"profile_header_follow_button"})
        assert gate.is_allowed("follow", screen) is True

    def test_like_allowed_on_home_feed(self, gate):
        """Like IS valid on HOME_FEED with proper markers."""
        screen = _make_screen(ScreenType.HOME_FEED, {"row_feed_button_like"})
        assert gate.is_allowed("like", screen) is True


class TestScreenTopologyBackTransitions:
    """P2-3: HD Map must NOT claim to know where 'press back' goes.
    Back is inherently non-deterministic."""

    def test_press_back_has_no_expected_screen(self):
        """press back must NEVER return a specific expected screen."""
        from GramAddict.core.screen_topology import ScreenTopology

        # For every screen that has a 'press back' transition,
        # we verify it should NOT be in the topology
        for screen_type, transitions in ScreenTopology.TRANSITIONS.items():
            if "press back" in transitions:
                # This test SHOULD fail until we remove press back from TRANSITIONS
                # for screens where it's non-deterministic
                if screen_type in (
                    ScreenType.DM_INBOX,
                    ScreenType.FOLLOW_LIST,
                    ScreenType.STORY_VIEW,
                    ScreenType.COMMENTS,
                    ScreenType.NOTIFICATIONS,
                ):
                    # These are "leaf" screens with a deterministic parent — OK to keep
                    continue
                # NON-DETERMINISTIC back: OTHER_PROFILE, POST_DETAIL, SEARCH_RESULTS
                assert False, (
                    f"ScreenTopology claims 'press back' from {screen_type.name} goes to "
                    f"{transitions['press back'].name}, but this is non-deterministic! "
                    f"Remove this transition — it causes GOAP to reject valid navigation states."
                )
