"""
Action builders for Family Safety Agent.

This module provides builders for different action types, encapsulating the logic
for handling keyboard input, delays, toggles, and other specialized actions.
"""

import asyncio
from typing import Dict, Any, Optional
from playwright.async_api import Page, Frame, ElementHandle
from backend.core.logging_config import log_info, log_debug, log_warning
from backend.utils.page_objects import (
    TogglePage, ClickableElementPage, NavigationPage, ScrollPage, 
    FormPage, ElementFinder
)


class KeyboardActionBuilder:
    """Handles keyboard input actions (press)."""
    
    def __init__(self, page: Page):
        self.page = page
    
    async def execute(self, action: Dict[str, Any]) -> Dict[str, Any]:
        """
        Execute keyboard press action.
        
        Args:
            action: Dictionary with 'value' (key to press) and 'count' (repetitions)
        
        Returns:
            Result dictionary
        """
        result = {
            "success": False,
            "action": action,
            "timestamp": None,
            "error": None,
            "details": {}
        }
        
        try:
            count = int(action.get("count", 1) or 1)
            count = max(1, count)
            
            key = str(action["value"])
            
            for _ in range(count):
                await self.page.keyboard.press(key)
            
            result["success"] = True
            result["details"]["action_performed"] = f"press:{key} x{count}"
            return result
        
        except Exception as e:
            result["error"] = f"Keyboard press failed: {e}"
            return result


class WaitActionBuilder:
    """Handles wait/delay actions."""
    
    def __init__(self, page: Page):
        self.page = page
    
    async def execute(self, action: Dict[str, Any]) -> Dict[str, Any]:
        """
        Execute wait action.
        
        Args:
            action: Dictionary with 'value' (duration) or 'seconds'/'duration' keys
        
        Returns:
            Result dictionary
        """
        result = {
            "success": False,
            "action": action,
            "timestamp": None,
            "error": None,
            "details": {}
        }
        
        try:
            secs = None
            
            try:
                secs = float(action["value"])
            except Exception:
                try:
                    secs = float(action.get("seconds", action.get("duration", 0)))
                except Exception:
                    secs = 0
            
            secs = max(0.0, float(secs or 0))
            
            await self.page.wait_for_timeout(int(secs * 1000))
            
            result["success"] = True
            result["details"]["action_performed"] = f"wait:{secs}s"
            return result
        
        except Exception as e:
            result["error"] = f"Wait failed: {e}"
            return result


class NavigationActionBuilder:
    """Handles navigation actions (navigate, back)."""
    
    def __init__(self, page: Page):
        self.page = page
    
    async def execute_navigate(self, action: Dict[str, Any]) -> Dict[str, Any]:
        """Navigate to URL."""
        result = {
            "success": False,
            "action": action,
            "timestamp": None,
            "error": None,
            "details": {}
        }
        
        try:
            url = str(action["value"])
            nav_page = NavigationPage(self.page)
            
            if await nav_page.navigate_to_url(url):
                result["success"] = True
                result["details"]["action_performed"] = f"navigate:{url}"
            else:
                result["error"] = "Navigation failed"
            
            return result
        
        except Exception as e:
            result["error"] = f"Navigation failed: {e}"
            return result
    
    async def execute_back(self, action: Dict[str, Any]) -> Dict[str, Any]:
        """Go back in history."""
        result = {
            "success": False,
            "action": action,
            "timestamp": None,
            "error": None,
            "details": {}
        }
        
        try:
            nav_page = NavigationPage(self.page)
            
            if await nav_page.go_back():
                result["success"] = True
                result["details"]["action_performed"] = "go_back"
            else:
                result["error"] = "Go back failed"
            
            return result
        
        except Exception as e:
            result["error"] = f"Go back failed: {e}"
            return result


class EnsureToggleActionBuilder:
    """Handles ensure_toggle actions with bounce verification."""
    
    def __init__(self, page: Page):
        self.page = page
    
    async def execute(self, action: Dict[str, Any]) -> Dict[str, Any]:
        """
        Execute ensure_toggle action.
        
        Args:
            action: Dictionary with 'value' (label) and 'desired_on' (bool)
        
        Returns:
            Result dictionary
        """
        result = {
            "success": False,
            "action": action,
            "timestamp": None,
            "error": None,
            "details": {}
        }
        
        try:
            label_text = str(action["value"])
            desired_on = bool(action.get("desired_on", True))
            
            toggle_page = TogglePage(self.page)
            finder = ElementFinder(self.page)
            
            # Find toggle by label
            toggle_el = await self._find_toggle_by_label(label_text, finder)
            if not toggle_el:
                result["error"] = f"Toggle not found for label '{label_text}'"
                return result
            
            # Check current state
            current_state = await toggle_page.is_toggle_on(toggle_el)
            
            if current_state is None:
                # Unknown state - try one click to probe
                clicker = ClickableElementPage(self.page)
                await clicker.click(toggle_el)
                await asyncio.sleep(0.2)
                current_state = await toggle_page.is_toggle_on(toggle_el)
            
            # Perform toggle action
            if current_state == desired_on:
                # Already in desired state - bounce it
                success = await self._bounce_toggle(toggle_el, desired_on, toggle_page)
            else:
                # Different state - toggle to it
                clicker = ClickableElementPage(self.page)
                success = await clicker.click(toggle_el)
            
            if success:
                result["success"] = True
                result["details"]["action_performed"] = f"ensure_toggle:{'on' if desired_on else 'off'}"
            else:
                result["error"] = "Toggle action failed"
            
            return result
        
        except Exception as e:
            result["error"] = f"Ensure toggle failed: {e}"
            return result
    
    async def _find_toggle_by_label(self, label: str, finder: ElementFinder) -> Optional[ElementHandle]:
        """Find toggle element by its label."""
        # Try role=switch with aria-label
        el, frame = await finder.find_in_frames("aria-label", label)
        if el:
            return el
        
        # Try text matching
        el, frame = await finder.find_in_frames("text", label)
        if el:
            return el
        
        return None
    
    async def _bounce_toggle(self, element: ElementHandle, desired_on: bool, 
                           toggle_page: TogglePage) -> bool:
        """Bounce toggle OFF then ON (or vice versa) to verify state."""
        try:
            clicker = ClickableElementPage(self.page)
            
            if desired_on:
                # Click OFF then back ON
                await clicker.click(element)
                await asyncio.sleep(0.3)
                await clicker.click(element)
            else:
                # Click ON then back OFF
                await clicker.click(element)
                await asyncio.sleep(0.3)
                await clicker.click(element)
            
            # Verify final state
            final_state = await toggle_page.is_toggle_on(element)
            return final_state == desired_on or final_state is None
        
        except Exception as e:
            log_debug(f"Toggle bounce failed: {e}")
            return False


class ClickActionBuilder:
    """Handles click actions with special cases."""
    
    def __init__(self, page: Page):
        self.page = page
    
    async def execute(self, action: Dict[str, Any], element: ElementHandle, 
                     frame: Frame, scope: ElementHandle = None) -> Dict[str, Any]:
        """Execute click action."""
        result = {
            "success": False,
            "action": action,
            "timestamp": None,
            "error": None,
            "details": {}
        }
        
        try:
            clicker = ClickableElementPage(self.page, frame, scope)
            
            if await clicker.click(element):
                result["success"] = True
                result["details"]["action_performed"] = "click"
            else:
                result["error"] = "Click failed"
            
            return result
        
        except Exception as e:
            result["error"] = f"Click action failed: {e}"
            return result


class TypeActionBuilder:
    """Handles type actions with special cases."""
    
    def __init__(self, page: Page):
        self.page = page
    
    async def execute(self, action: Dict[str, Any], element: ElementHandle,
                     frame: Frame, scope: ElementHandle = None) -> Dict[str, Any]:
        """Execute type action."""
        result = {
            "success": False,
            "action": action,
            "timestamp": None,
            "error": None,
            "details": {}
        }
        
        try:
            input_text = str(action.get("input_text", ""))
            
            form_page = FormPage(self.page, frame, scope)
            
            if await form_page.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 result
        
        except Exception as e:
            result["error"] = f"Type action failed: {e}"
            return result


class HoverActionBuilder:
    """Handles hover actions."""
    
    def __init__(self, page: Page):
        self.page = page
    
    async def execute(self, action: Dict[str, Any], element: ElementHandle,
                     frame: Frame, scope: ElementHandle = None) -> Dict[str, Any]:
        """Execute hover action."""
        result = {
            "success": False,
            "action": action,
            "timestamp": None,
            "error": None,
            "details": {}
        }
        
        try:
            await element.hover()
            result["success"] = True
            result["details"]["action_performed"] = "hover"
            return result
        
        except Exception as e:
            result["error"] = f"Hover failed: {e}"
            return result


class ScrollActionBuilder:
    """Handles scroll actions."""
    
    def __init__(self, page: Page):
        self.page = page
    
    async def execute(self, action: Dict[str, Any], element: ElementHandle = None,
                     frame: Frame = None, scope: ElementHandle = None) -> Dict[str, Any]:
        """Execute scroll action."""
        result = {
            "success": False,
            "action": action,
            "timestamp": None,
            "error": None,
            "details": {}
        }
        
        try:
            scroll_page = ScrollPage(self.page, frame, scope)
            
            if element:
                await scroll_page.scroll_to_element(element)
            else:
                await scroll_page.scroll_to_bottom()
            
            result["success"] = True
            result["details"]["action_performed"] = "scroll"
            return result
        
        except Exception as e:
            result["error"] = f"Scroll failed: {e}"
            return result


class ActionBuilderFactory:
    """Factory for creating action builders."""
    
    @staticmethod
    def get_simple_action_builder(page: Page, action_type: str):
        """Get builder for simple actions (keyboard, wait, nav)."""
        builders = {
            "press": KeyboardActionBuilder,
            "wait": WaitActionBuilder,
            "navigate": NavigationActionBuilder,
            "goto": NavigationActionBuilder,
            "back": NavigationActionBuilder,
            "go_back": NavigationActionBuilder,
            "navigate_back": NavigationActionBuilder,
            "ensure_toggle": EnsureToggleActionBuilder,
            "hover": HoverActionBuilder,
            "scroll": ScrollActionBuilder,
        }
        
        builder_class = builders.get(action_type)
        if builder_class:
            return builder_class(page)
        
        return None
