"""
E2E: SAE Foreign App Fast-Path
================================
Validates that the SAE classifies known foreign packages (Play Store,
Chrome, Settings) as OBSTACLE_FOREIGN_APP using O(1) structural detection
WITHOUT falling through to LLM classification.

This eliminates 2-5 seconds of LLM inference for detections that
should be instantaneous set lookups.
"""

from GramAddict.core.situational_awareness import SituationalAwarenessEngine, SituationType
from tests.e2e.conftest import E2EDeviceStub, load_fixture_xml


def test_sae_classifies_play_store_without_llm():
    """Play Store XML must be classified as FOREIGN_APP via fast-path, not LLM."""
    xml = load_fixture_xml("play_store_from_story_link.xml")
    device = E2EDeviceStub([xml])
    SituationalAwarenessEngine.reset()
    sae = SituationalAwarenessEngine(device)

    result = sae.perceive(xml)

    assert result == SituationType.OBSTACLE_FOREIGN_APP, (
        f"SAE classified Play Store as {result.value} instead of OBSTACLE_FOREIGN_APP! "
        f"The bot cannot detect it left Instagram."
    )


def test_sae_fast_path_handles_known_foreign_packages():
    """
    Verify the fast-path handles com.android.vending, com.android.chrome,
    com.google.android.youtube etc. without LLM calls.
    com.android.settings may classify as OBSTACLE_SYSTEM which is also valid.
    """
    known_foreign_pkgs = {
        "com.android.vending": SituationType.OBSTACLE_FOREIGN_APP,
        "com.android.chrome": SituationType.OBSTACLE_FOREIGN_APP,
        "com.google.android.youtube": SituationType.OBSTACLE_FOREIGN_APP,
    }
    for pkg, expected in known_foreign_pkgs.items():
        xml = f"""<?xml version="1.0" encoding="utf-8"?>
        <hierarchy rotation="0">
            <node class="android.widget.FrameLayout" package="{pkg}"
                  bounds="[0,0][1080,2400]">
                <node text="Some content" class="android.widget.TextView"
                      package="{pkg}" />
            </node>
        </hierarchy>"""
        device = E2EDeviceStub([xml])
        SituationalAwarenessEngine.reset()
        sae = SituationalAwarenessEngine(device)

        result = sae.perceive(xml)
        assert result == expected, f"Package {pkg} was classified as {result.value}, expected {expected.value}!"


def test_sae_ensure_clear_screen_escapes_foreign_app_without_llm():
    """
    If SAE perceives a FOREIGN_APP, ensure_clear_screen must immediately
    execute a kill_foreign_apps action WITHOUT consulting the LLM.
    """

    xml_foreign = load_fixture_xml("play_store_from_story_link.xml")
    xml_normal = """<?xml version="1.0" encoding="utf-8"?>
        <hierarchy rotation="0">
            <node class="android.widget.FrameLayout" package="com.instagram.android"
                  bounds="[0,0][1080,2400]">
                <node text="Instagram" class="android.widget.TextView" />
            </node>
        </hierarchy>"""

    # device returns foreign first, then normal on next dump
    device = E2EDeviceStub([xml_foreign, xml_normal])
    SituationalAwarenessEngine.reset()
    sae = SituationalAwarenessEngine(device)

    # Patch _plan_escape_via_llm to raise an error if called!
    def _mock_plan(*args, **kwargs):
        raise AssertionError("LLM was called for FOREIGN_APP escape! This should be an O(1) fast-path.")

    sae._plan_escape_via_llm = _mock_plan

    result = sae.ensure_clear_screen(max_attempts=3)

    assert result is True, "SAE failed to clear the foreign app screen"
    assert "com.instagram.android" in device.app_starts, "SAE did not attempt to restart Instagram"
