"""
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 backend.utils.page_objects import ElementFinder, ClickableElementPage, FormPage, DialogPage


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


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


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 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 finalize_action_result(result, finder, element, frame)
