import logging
import random
import re
from time import sleep

from GramAddict.core.behaviors import BehaviorContext, BehaviorPlugin, BehaviorResult
from GramAddict.core.physics.humanized_input import humanized_click
from GramAddict.core.physics.timing import wait_for_story_loaded

logger = logging.getLogger(__name__)


class StoryViewPlugin(BehaviorPlugin):
    """
    Views a target user's stories from their profile.

    Priority: 25.
    """

    @property
    def name(self) -> str:
        return "story_view"

    @property
    def priority(self) -> int:
        return 25

    def can_activate(self, ctx: BehaviorContext) -> bool:
        """Activates when story viewing is enabled and probability met."""
        config = self.get_config(ctx)
        stories_pct = float(config.get("percentage", getattr(ctx.configs.args, "stories_percentage", 0))) / 100.0

        if stories_pct <= 0:
            return False

        # Probability gate
        if random.random() >= stories_pct:
            return False

        return True

    def execute(self, ctx: BehaviorContext) -> BehaviorResult:
        """View stories with humanized timing."""
        config = self.get_config(ctx)

        # Parse story count
        stories_count_str = config.get("count", getattr(ctx.configs.args, "stories_count", "1-2"))
        try:
            if "-" in stories_count_str:
                min_st, max_st = map(int, stories_count_str.split("-"))
                count = random.randint(min_st, max_st)
            else:
                count = int(stories_count_str)
        except Exception:
            count = 1

        from GramAddict.core.goap import ScreenType

        is_already_in_story = getattr(ctx, "screen_type", None) == ScreenType.STORY_VIEW

        # Check for story ring
        xml = ctx.context_xml or ctx.device.dump_hierarchy()
        xml_lower = xml.lower()
        has_story_ring = (
            "reel_ring" in xml
            or "has an unseen story" in xml_lower
            or "has a new story" in xml_lower
            or "story von" in xml_lower
        )

        if not has_story_ring and not is_already_in_story:
            return BehaviorResult(executed=False, metadata={"reason": "no_story"})

        if not is_already_in_story:
            # Navigate to story
            nav_graph = ctx.cognitive_stack.get("nav_graph")
            if not nav_graph:
                from GramAddict.core.q_nav_graph import QNavGraph

                nav_graph = QNavGraph(ctx.device)

            if not nav_graph.do("tap story ring avatar"):
                return BehaviorResult(executed=False, metadata={"reason": "nav_failed"})

            # Wait for story to load
            if not wait_for_story_loaded(ctx.device, timeout=5):
                logger.warning(f"❌ [StoryView] Story failed to open for @{ctx.username}.")
                return BehaviorResult(executed=False, metadata={"reason": "load_timeout"})

        logger.info(f"📸 [StoryView] Viewing @{ctx.username}'s story ({count} segments)...")

        info = ctx.device.get_info()
        w = info.get("displayWidth", 1080)
        h = info.get("displayHeight", 2400)

        for i in range(count):
            sleep(random.uniform(2.0, 5.0) * ctx.sleep_mod)
            if i < count - 1:
                # Atomic state validation before click
                xml_dump = ctx.device.dump_hierarchy()
                if not xml_dump:
                    continue

                # Query VLM to find the interactive area for the next segment
                intent = "tap right side of screen to view next story segment"
                node = ctx.telepathic.find_best_node(xml_dump, intent, device=ctx.device, track=False)

                if node:
                    logger.debug(
                        f"📸 [StoryView] VLM selected node '{node.resource_id or node.content_desc or 'unknown'}' for next segment."
                    )
                    # If VLM selects a large container (e.g. the entire screen or story viewer),
                    # we must tap its right side, not its exact center, to avoid pausing the story.
                    if getattr(node, "area", 0) > (w * h * 0.4):
                        target_x = node.x1 + int((node.x2 - node.x1) * 0.85)
                        target_y = node.y1 + int((node.y2 - node.y1) * 0.25)
                        logger.debug(
                            f"📸 [StoryView] Adjusting click to top-right quadrant of large container: ({target_x}, {target_y})"
                        )
                    else:
                        target_x = node.center_x
                        target_y = node.center_y

                    humanized_click(ctx.device, target_x, target_y, sleep_mod=ctx.sleep_mod)
                else:
                    logger.warning(
                        "📸 [StoryView] VLM could not resolve next story segment. Falling back to geometric safety quadrant."
                    )
                    # Click top-right to avoid 'reply' input fields and most stickers
                    humanized_click(ctx.device, int(w * 0.85), int(h * 0.25), sleep_mod=ctx.sleep_mod)

                # Verify we didn't leave Instagram
                xml_dump_after = ctx.device.dump_hierarchy()
                if not xml_dump_after:
                    continue
                packages = set(re.findall(r'package="([^"]+)"', xml_dump_after))
                app_id = getattr(ctx.device, "app_id", "com.instagram.android")
                if packages and app_id not in packages:
                    logger.error(
                        f"🚨 [StoryView] FOREIGN APP DETECTED! Packages: {packages}. "
                        f"A link likely opened an external app. Aborting loop."
                    )
                    ctx.device.press("back")
                    sleep(1.5)
                    break

        ctx.device.press("back")
        sleep(random.uniform(1.0, 2.0) * ctx.sleep_mod)

        # Post-interaction verification: verify we successfully exited the story overlay
        for attempt in range(3):
            xml_dump = ctx.device.dump_hierarchy()
            if not xml_dump:
                break
            xml_lower = xml_dump.lower()
            if "com.instagram.android" not in xml_dump or (
                "row 1, column 1" in xml_lower or "tab" in xml_lower or "home" in xml_lower or "search" in xml_lower
            ):
                # Successfully back to a main view or outside instagram
                break
            logger.warning(
                f"⚠️ [StoryView] Still trapped in story/overlay after back press (attempt {attempt+1}). Pressing back again."
            )
            ctx.device.press("back")
            sleep(1.5)

        return BehaviorResult(executed=True, interactions=count, metadata={"stories_viewed": count})
