"""
Reel Interaction Tests — The Tests That Must Match Reality

These tests reproduce the EXACT failures from production (2026-04-27 15:55):
1. VLM selected POST CAPTION for "tap like button" (caption contained word "like")
2. VLM selected COMMENT INPUT for "tap follow button" (follow button doesn't exist on Reels)
3. ActionMemory falsely confirmed success for both

These tests use the REAL reels_feed_dump.xml fixture and call the REAL VLM.
If the VLM makes wrong decisions, these tests MUST fail RED.
No mocks. No fakes. No synthetic screenshots. Pure production truth.
"""

import pytest

from GramAddict.core.perception.intent_resolver import IntentResolver
from GramAddict.core.perception.spatial_parser import SpatialParser


def _load_reel_xml():
    with open("tests/fixtures/reels_feed_dump.xml", "r", encoding="utf-8") as f:
        return f.read()


# ═══════════════════════════════════════════════════════════════════════════
# TEST 1: "tap like button" must select the HEART, not the caption
# ═══════════════════════════════════════════════════════════════════════════


@pytest.mark.live_llm
def test_reel_like_button_not_caption(make_real_device_with_image):
    """
    PRODUCTION BUG: VLM selected the caption ('would you like to try this...')
    instead of the heart icon for 'tap like button'.

    The word "like" in the caption is a TRAP. The VLM must visually
    identify the heart ♡ icon on the right side, not grep for "like" in text.

    This test MUST be RED until the VLM correctly identifies UI buttons.
    """
    xml = _load_reel_xml()
    parser = SpatialParser()
    root = parser.parse(xml)
    candidates = parser.get_clickable_nodes(root)

    device = make_real_device_with_image("tests/fixtures/reels_feed_dump.jpg")
    resolver = IntentResolver()

    result = resolver.resolve("tap like button", candidates, device)

    assert result is not None, "Visual discovery returned None for 'tap like button' on Reel"

    rid = (result.resource_id or "").lower()
    desc = (result.content_desc or "").lower()

    # Must be the actual like_button, NOT the caption
    assert "like_button" in rid or (desc == "like"), (
        f"VLM picked WRONG element for 'tap like button'!\n"
        f"  Selected: id='{result.resource_id}', desc='{result.content_desc}', "
        f"text='{result.text}'\n"
        f"  Expected: id containing 'like_button' or desc='Like'"
    )

    # Must NOT be the caption that contains the word "like" in its text
    assert "masterclass" not in desc and "would you" not in desc, (
        f"VLM selected the CAPTION instead of the like button!\n" f"  Selected desc: '{result.content_desc}'"
    )


# ═══════════════════════════════════════════════════════════════════════════
# TEST 2: "tap follow button" must return None when no Follow button exists
# ═══════════════════════════════════════════════════════════════════════════


@pytest.mark.live_llm
def test_reel_follow_button_returns_none_when_absent(make_real_device_with_image):
    """
    PRODUCTION BUG: VLM selected the comment input field ('Add comment…')
    for 'tap follow button' because there IS no follow button on Reels.

    The correct behavior is to return None — "I can't find a follow button
    on this screen". The bot should then navigate to the profile first.

    This test MUST be RED until the VLM correctly returns null/None.
    """
    xml = _load_reel_xml()
    parser = SpatialParser()
    root = parser.parse(xml)
    candidates = parser.get_clickable_nodes(root)

    device = make_real_device_with_image("tests/fixtures/reels_feed_dump.jpg")
    resolver = IntentResolver()

    result = resolver.resolve("tap follow button", candidates, device)

    if result is not None:
        rid = (result.resource_id or "").lower()
        desc = (result.content_desc or "").lower()
        text = (result.text or "").lower()

        # If it returns something, it MUST be an actual follow button
        assert "follow" in rid or "follow" in text or "follow" in desc, (
            f"VLM hallucinated a follow button that doesn't exist on Reels!\n"
            f"  Selected: id='{result.resource_id}', desc='{result.content_desc}', "
            f"text='{result.text}'\n"
            f"  Expected: None (no follow button on Reel screen) or an element "
            f"with 'follow' in its id/text"
        )

        # Must NEVER select the comment composer
        assert "comment" not in rid, (
            f"VLM selected comment field for 'tap follow button'!\n" f"  Selected: id='{result.resource_id}'"
        )


# ═══════════════════════════════════════════════════════════════════════════
# TEST 3: "post author username" must select the actual username
# ═══════════════════════════════════════════════════════════════════════════


@pytest.mark.live_llm
def test_reel_post_author_selects_username(make_real_device_with_image):
    """
    PRODUCTION BUG: VLM selected the action_bar container for 'post author header'.

    On a Reel, the author username is in the bottom-left area
    (clips_author_username / clips_author_info_component).
    The VLM must visually identify the username text, not the top action bar.
    """
    xml = _load_reel_xml()
    parser = SpatialParser()
    root = parser.parse(xml)
    candidates = parser.get_clickable_nodes(root)

    device = make_real_device_with_image("tests/fixtures/reels_feed_dump.jpg")
    resolver = IntentResolver()

    result = resolver.resolve("tap 'Profile picture' of the author", candidates, device)

    assert result is not None, "Visual discovery returned None for author profile picture on Reel"

    rid = (result.resource_id or "").lower()
    desc = (result.content_desc or "").lower()
    text = (result.text or "").lower()

    # Must be the author info component or username, NOT the top action bar
    is_author = "author" in rid or "cappadocia.cowboy" in desc or "cappadocia.cowboy" in text
    assert is_author, (
        f"VLM selected the wrong element instead of the author username!\n"
        f"Selected id='{rid}', desc='{desc}', text='{text}'"
    )


# ═══════════════════════════════════════════════════════════════════════════
# TEST 4: Dedup preserves the like button as a distinct box
# ═══════════════════════════════════════════════════════════════════════════


def test_reel_dedup_preserves_like_button(make_real_device_with_image):
    """
    The spatial dedup must NOT suppress the like_button.
    If the like_button is inside a parent container and gets deduped,
    the VLM will never see it as an option.
    """
    xml = _load_reel_xml()
    parser = SpatialParser()
    root = parser.parse(xml)
    candidates = parser.get_clickable_nodes(root)

    device = make_real_device_with_image("tests/fixtures/reels_feed_dump.jpg")
    resolver = IntentResolver()

    _, box_map = resolver._annotate_screenshot_with_candidates(device, candidates)

    # Find the like_button in the box_map
    like_boxes = [(idx, node) for idx, node in box_map.items() if "like_button" in (node.resource_id or "").lower()]

    assert len(like_boxes) >= 1, "Like button was SUPPRESSED by dedup! Available boxes:\n" + "\n".join(
        f"  [{idx}] id='{n.resource_id}', desc='{n.content_desc}'" for idx, n in sorted(box_map.items())
    )


# ═══════════════════════════════════════════════════════════════════════════
# TEST 5: Caption with "like" word must NOT be confused with like button
# ═══════════════════════════════════════════════════════════════════════════


def test_reel_caption_with_like_word_is_not_like_button(make_real_device_with_image):
    """
    The reel fixture has a caption: 'would you like to try this line?'
    This text contains the word "like" but is NOT a like button.

    This test verifies that the dedup/annotation correctly creates
    SEPARATE boxes for the caption and the like button.
    """
    xml = _load_reel_xml()
    parser = SpatialParser()
    root = parser.parse(xml)
    candidates = parser.get_clickable_nodes(root)

    device = make_real_device_with_image("tests/fixtures/reels_feed_dump.jpg")
    resolver = IntentResolver()

    _, box_map = resolver._annotate_screenshot_with_candidates(device, candidates)

    caption_boxes = [
        (idx, node)
        for idx, node in box_map.items()
        if "would you" in (node.content_desc or "").lower() or "masterclass" in (node.content_desc or "").lower()
    ]

    like_button_boxes = [
        (idx, node) for idx, node in box_map.items() if "like_button" in (node.resource_id or "").lower()
    ]

    # Both must exist as SEPARATE boxes
    if caption_boxes and like_button_boxes:
        caption_idx = caption_boxes[0][0]
        like_idx = like_button_boxes[0][0]
        assert caption_idx != like_idx, "Caption and like button have the same box number!"
