"""
Camera Trap Escape Tests

Validates that ALL perception layers correctly identify the Instagram
camera/story creation overlay as a blocking obstacle, preventing the
softlock discovered in the 2026-04-22 bot run.

Uses the real-world XML fixture captured during the actual incident.
"""

import os
from unittest.mock import MagicMock

import pytest

FIXTURE_PATH = os.path.join(os.path.dirname(__file__), "..", "fixtures", "camera_trap.xml")


@pytest.fixture
def camera_xml():
    with open(FIXTURE_PATH, "r") as f:
        return f.read()


@pytest.fixture
def mock_device():
    device = MagicMock()
    device.deviceV2 = MagicMock()
    device.deviceV2.info = {"screenOn": True}
    device.app_id = "com.instagram.android"
    device._get_current_app.return_value = "com.instagram.android"
    device.get_info.return_value = {"displayWidth": 1080, "displayHeight": 2400}
    return device


class TestSAEPerceivesCameraAsObstacle:
    """Layer 1: SituationalAwarenessEngine.perceive() must classify
    the camera overlay as OBSTACLE_MODAL."""

    def test_sae_perceives_camera_as_obstacle_modal(self, camera_xml, mock_device):
        from GramAddict.core.situational_awareness import (
            SituationalAwarenessEngine,
            SituationType,
        )

        SituationalAwarenessEngine.reset()
        sae = SituationalAwarenessEngine(mock_device)
        # Bypass Qdrant to test pure structural logic
        sae.episodes.recall = MagicMock(return_value=None)
        sae.episodes.learn = MagicMock()

        result = sae.perceive(camera_xml)

        assert (
            result == SituationType.OBSTACLE_MODAL
        ), f"SAE failed to detect camera overlay as OBSTACLE_MODAL (got {result})"


class TestScreenIdentityClassifiesCameraAsModal:
    """Layer 2: ScreenIdentity._classify_screen() must return
    ScreenType.MODAL for the camera overlay."""

    def test_screen_identity_classifies_camera_as_modal(self, camera_xml, mock_device):
        from GramAddict.core.goap import ScreenIdentity, ScreenType

        screen_id = ScreenIdentity("testuser")
        result = screen_id.identify(camera_xml)

        assert (
            result["screen_type"] == ScreenType.MODAL
        ), f"ScreenIdentity classified camera as {result['screen_type']} instead of MODAL"


class TestGOAPTriggersSAEOnCameraDetection:
    """Layer 4: GoalExecutor.achieve() must invoke SAE.ensure_clear_screen()
    when ScreenIdentity classifies the screen as MODAL."""

    def test_goap_triggers_sae_on_camera_detection(self, camera_xml, mock_device):
        from GramAddict.core.goap import GoalExecutor

        GoalExecutor.reset()
        executor = GoalExecutor(mock_device, "testuser")

        # achieve() calls perceive() twice before the SAE branch:
        #   1. Line 866: initial perceive for path recall  → camera_xml (MODAL)
        #   2. Line 883: loop perceive at step 0           → camera_xml (MODAL) → triggers SAE
        #   3+: after SAE clears, next perceives return normal feed
        normal_xml = '<hierarchy><node package="com.instagram.android" resource-id="com.instagram.android:id/feed_tab" selected="true" /><node package="com.instagram.android" /></hierarchy>'
        mock_device.dump_hierarchy.side_effect = [
            camera_xml,
            camera_xml,
            normal_xml,
            normal_xml,
            normal_xml,
            normal_xml,
        ]

        # Mock SAE to report successful clearance and track calls
        mock_sae = MagicMock()
        mock_sae.ensure_clear_screen.return_value = True
        executor._sae = mock_sae

        # Run a goal — should detect MODAL on first loop perceive and call SAE
        executor.achieve("open home feed", max_steps=5)

        assert (
            mock_sae.ensure_clear_screen.called
        ), "GOAP did not invoke SAE.ensure_clear_screen() when camera overlay was detected"


class TestForbiddenGuardBlocksQuickCaptureNodes:
    """Layer 5: _is_forbidden_action() must refuse to click
    any node with quick_capture in its resource-id."""

    def test_forbidden_guard_blocks_quick_capture_nodes(self):
        from GramAddict.core.telepathic_engine import TelepathicEngine

        engine = TelepathicEngine()

        camera_node = {
            "text": "",
            "description": "",
            "resource_id": "com.instagram.android:id/quick_capture_root_container",
            "semantic_string": "id context: 'quick capture root container'",
        }

        assert (
            engine._is_forbidden_action(camera_node) is True
        ), "Forbidden Action Guard failed to block quick_capture node"

    def test_forbidden_guard_allows_normal_nodes(self):
        from GramAddict.core.telepathic_engine import TelepathicEngine

        engine = TelepathicEngine()

        normal_node = {
            "text": "",
            "description": "Like",
            "resource_id": "com.instagram.android:id/row_feed_button_like",
            "semantic_string": "description: 'Like', id context: 'row feed button like'",
        }

        assert (
            engine._is_forbidden_action(normal_node) is False
        ), "Forbidden Action Guard incorrectly blocked a normal Like button"
