"""
Click and Type Action Helpers for Family Safety Agent

This module isolates click/type execution logic from the main agent to keep
execute_action more focused and readable.
"""

from typing import Any, Dict, Optional, Tuple
from playwright.async_api import Page

from .page_objects import ElementFinder, ClickableElementPage, FormPage, DialogPage


class ClickTypeActions:
    """Helpers for click/dblclick/type actions with shared element lookup."""

    @staticmethod
    async def prepare_element_for_action(
        page: Page,
        locator: str,
        value: Any,
    ) -> Tuple[ElementFinder, Optional[Any], Any, Optional[Any]]:
        """
        Find an element for a locator/value across the main page and frames.

        Returns:
            Tuple of (finder, element, frame, scope)
        """
        dialog_page = DialogPage(page)
        modal_present = await dialog_page.detect_modal()
        modal_root = await dialog_page.get_modal_root() if modal_present else None

        finder = ElementFinder(page, page.main_frame, modal_root)
        element = None
        frame = page.main_frame
        scope = modal_root

        if locator == "aria-label":
            element = await finder.find_by_aria_label(str(value))
        elif locator == "text":
            element = await finder.find_by_text(str(value))
        elif locator == "id":
            element = await finder.find_by_id(str(value))
        elif locator == "placeholder":
            element = await finder.find_by_placeholder(str(value))
        elif locator == "xpath":
            element = await finder.find_by_xpath(str(value))

        if not element:
            element, found_frame = await finder.find_in_frames(locator, str(value))
            if element and found_frame:
                frame = found_frame

        return finder, element, frame, scope

    @staticmethod
    async def finalize_action_result(
        result: Dict[str, Any],
        finder: ElementFinder,
        element: Optional[Any],
        frame: Any,
    ) -> Dict[str, Any]:
        """
        Attach element metadata and frame info to the result.
        """
        if result.get("success") and element:
            try:
                result["details"]["element_info"] = await finder.get_element_info(element)
            except Exception:
                result["details"]["element_info"] = {}

        result["details"]["frame"] = frame.name if hasattr(frame, "name") else "main"
        return result

    @staticmethod
    async def execute_click_type_action(
        page: Page,
        action: Dict[str, Any],
        result: Dict[str, Any],
    ) -> Dict[str, Any]:
        """
        Execute click/dblclick/type actions with shared element lookup.
        """
        locator = action["locator"]
        value = action["value"]
        action_type = action["action"]

        finder, element, frame, scope = await ClickTypeActions.prepare_element_for_action(page, locator, value)

        if not element:
            result["error"] = f"Element not found with {locator}='{value}'"
            return result

        if action_type in ("click", "dblclick"):
            clicker = ClickableElementPage(page, frame, scope)
            if await clicker.click(element, action_type):
                result["success"] = True
                result["details"]["action_performed"] = action_type
            else:
                result["error"] = f"{action_type} failed"
        elif action_type == "type":
            form = FormPage(page, frame, scope)
            input_text = action.get("input_text", "")
            if await form.type_text(element, input_text):
                result["success"] = True
                result["details"]["action_performed"] = "type"
                result["details"]["input_text"] = input_text
            else:
                result["error"] = "Type failed"

        return await ClickTypeActions.finalize_action_result(result, finder, element, frame)


__all__ = ["ClickTypeActions"]
