"""
P1-5: ContextGate Interaction Guards

TDD RED/GREEN: These tests enforce that:
1. Layer 0 (Categorical Ban Matrix) blocks structurally impossible actions instantly.
2. Layer 1 (Qdrant Learned Failures) blocks actions that pass Layer 0 but have a learned failure history.
3. Unknown/new actions are allowed for exploration (fail-open).
"""

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


class FakeContextMemory:
    def __init__(self, allowed_map):
        self.allowed_map = allowed_map
        self.calls = []

    @property
    def is_connected(self):
        return True

    def is_allowed(self, intent, screen_type):
        self.calls.append((intent, screen_type))
        return self.allowed_map.get((intent, screen_type), True)


class TestContextGate:
    def test_block_follow_on_own_profile_categorically(self):
        """Follow is categorically banned on OWN_PROFILE by Layer 0.
        Qdrant is never consulted because the categorical ban catches it first."""
        mock_memory = FakeContextMemory({})
        gate = ContextGate(context_memory=mock_memory)

        screen = {
            "screen_type": ScreenType.OWN_PROFILE,
            "resource_ids": {"profile_tab", "profile_edit_button"},
        }

        assert gate.is_allowed("follow", screen) is False, "Should block 'follow' on OWN_PROFILE categorically"
        # Layer 0 catches it — Qdrant is never consulted
        assert len(mock_memory.calls) == 0, "Layer 0 should short-circuit before Qdrant"

    def test_block_follow_via_learned_failure(self):
        """Layer 1 blocks 'follow' on OTHER_PROFILE if learned to fail (e.g. 'Requested' state)."""
        mock_memory = FakeContextMemory({("follow", "OTHER_PROFILE"): False})
        gate = ContextGate(context_memory=mock_memory)

        screen = {
            "screen_type": ScreenType.OTHER_PROFILE,
            "resource_ids": {"profile_header_follow_button"},
        }

        # Layer 0 allows follow on OTHER_PROFILE, but Layer 1 (Qdrant) blocks it
        assert gate.is_allowed("follow", screen) is False
        assert ("follow", "OTHER_PROFILE") in mock_memory.calls

    def test_allow_comment_if_unknown(self):
        """If memory has no opinion AND Layer 0 allows it, default to allow (exploration)."""
        mock_memory = FakeContextMemory({})
        gate = ContextGate(context_memory=mock_memory)

        screen = {
            "screen_type": ScreenType.POST_DETAIL,
            "resource_ids": {"row_feed_button_comment"},
        }

        assert gate.is_allowed("comment", screen) is True, "Should allow 'comment' if unknown, for exploration"
        assert ("comment", "POST_DETAIL") in mock_memory.calls

    def test_allow_like_on_feed(self):
        """Allow if memory says it's allowed and Layer 0 agrees."""
        mock_memory = FakeContextMemory({("like", "HOME_FEED"): True})
        gate = ContextGate(context_memory=mock_memory)

        screen = {
            "screen_type": ScreenType.HOME_FEED,
            "resource_ids": {"row_feed_button_like", "row_feed_button_comment"},
        }

        assert gate.is_allowed("like", screen) is True
        assert ("like", "HOME_FEED") in mock_memory.calls

    def test_block_post_interaction_on_dm_thread(self):
        """Prevent accidental likes/comments in DM threads — caught by Layer 0."""
        mock_memory = FakeContextMemory({})
        gate = ContextGate(context_memory=mock_memory)

        screen = {
            "screen_type": ScreenType.DM_THREAD,
            "resource_ids": {"direct_text_input", "direct_thread_header"},
        }

        assert gate.is_allowed("like", screen) is False
        assert gate.is_allowed("comment", screen) is False
        # Both blocked by Layer 0 — Qdrant never consulted
        assert len(mock_memory.calls) == 0
