#!/usr/bin/env python3
"""
Browser Primitives Mixin - Low-level browser operations

Provides atomic browser actions like navigation, clicking, typing, scrolling.
Used as a mixin for BrowserNavigator to keep code organized.
"""

import asyncio
import time
from typing import Optional, Dict, Any
import base64

from lib.page_management import ManagedPage
from lib.primitive.click_element import ClickElement
from lib.primitive.type_text import TypeText
from lib.primitive.press_enter import PressEnter
from lib.primitive.press_tab import PressTab
from lib.primitive.paste_text import PasteText
from lib.primitive.scroll_page import ScrollPage
from lib.primitive.zoom_page import ZoomPage


class PrimitiveBrowserOps:
    """
    Mixin providing primitive browser operations.
    
    Requires parent to have:
    - _get_page_to_use(page_id) method
    - slowmo attribute
    """
    
    async def navigate(self, url: str, page_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Navigate to a URL using an available page.
        """
        managed_page = await self._get_page_to_use(page_id)

        request_id = f"nav_{int(time.time() * 1000) % 10000}"
        print(f"🧭 [{request_id}] Starting navigation to: {url}")        
    
        # CRITICAL: Set page as busy BEFORE starting operation
        await managed_page.set_busy(f"navigate_{request_id}")
        
        try:
            print(f"🧭 [{request_id}] Navigating to: {url} using page {managed_page.page_id}")
            
            # Navigate to URL
            response = await managed_page.page.goto(url, wait_until="domcontentloaded")
            
            # Wait a bit for page to stabilize
            await asyncio.sleep(self.slowmo / 1000)
            
            result = {
                "success": True,
                "url": url,
                "page_id": managed_page.page_id,
                "status_code": response.status if response else None,
                "final_url": managed_page.page.url
            }
            
            print(f"✅ [{request_id}] Navigation successful to: {result['final_url']}")
            return result
            
        except Exception as e:
            error_result = {
                "success": False,
                "url": url,
                "page_id": managed_page.page_id,
                "error": str(e)
            }
            print(f"❌ [{request_id}] Navigation failed: {e}")
            return error_result
        finally:
            # Set page back to idle state
            print(f"🧭 [{request_id}] Setting page {managed_page.page_id} back to idle")
            await managed_page.set_idle()
    
    async def extract_content(self, page_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Extract content from a page.
        
        Args:
            page_id (str, optional): Specific page ID to extract from, or None for any available page
            
        Returns:
            Dict containing extracted content and page information
        """
        managed_page = await self._get_page_to_use(page_id)
        
        try:
            print(f"📄 Extracting content from page {managed_page.page_id}")
            
            # Extract basic content
            title = await managed_page.page.title()
            content = await managed_page.page.content()
            url = managed_page.page.url
            
            result = {
                "success": True,
                "page_id": managed_page.page_id,
                "url": url,
                "title": title,
                "content": content,
                "content_length": len(content)
            }
            
            print(f"✅ Content extracted: {len(content)} characters")
            return result
            
        except Exception as e:
            error_result = {
                "success": False,
                "page_id": managed_page.page_id,
                "error": str(e)
            }
            print(f"❌ Content extraction failed: {e}")
            return error_result
        finally:
            # Set page back to idle state
            await managed_page.set_idle()  

    async def click_element(self, selector: str, page_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Click an element on a page.

        Args:
            selector (str): CSS selector of element to click
            page_id (str, optional): Specific page ID to use, or None for any available page

        Returns:
            Dict containing click result and element information
        """
        managed_page = await self._get_page_to_use(page_id)

        try:
            print(f"👆 Clicking element '{selector}' on page {managed_page.page_id}")

            # Use primitive operation
            clicker = ClickElement()
            result = await clicker.click_selector(managed_page.page, selector, self.slowmo)

            # Add page_id to result
            result["page_id"] = managed_page.page_id

            return result

        except Exception as e:
            error_result = {
                "success": False,
                "page_id": managed_page.page_id,
                "selector": selector,
                "error": str(e)
            }
            print(f"❌ Element click failed: {e}")
            return error_result
        finally:
            # Set page back to idle state
            await managed_page.set_idle()

    async def click_position(self, x: float, y: float, page_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Click at specific (x, y) coordinates on a page.

        Args:
            x (float): X coordinate to click
            y (float): Y coordinate to click
            page_id (str, optional): Specific page ID to use, or None for any available page

        Returns:
            Dict containing click result and position information
        """
        managed_page = await self._get_page_to_use(page_id)

        try:
            print(f"👆 Clicking position ({x}, {y}) on page {managed_page.page_id}")

            # Use primitive operation
            clicker = ClickElement()
            result = await clicker.click_position(managed_page, x, y, self.slowmo)

            # Add page_id to result
            result["page_id"] = managed_page.page_id

            return result

        except Exception as e:
            error_result = {
                "success": False,
                "page_id": managed_page.page_id,
                "position": {"x": x, "y": y},
                "error": str(e)
            }
            print(f"❌ Position click failed: {e}")
            return error_result
        finally:
            # Set page back to idle state
            await managed_page.set_idle()

    async def scroll_page(self, distance: int = 1000, page_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Scroll the page vertically by a specified distance.

        Args:
            distance (int): Distance in pixels to scroll down (default: 1000)
            page_id (str, optional): Specific page ID to use, or None for any available page

        Returns:
            Dict containing scroll result and page information
        """
        managed_page = await self._get_page_to_use(page_id)

        try:
            print(f"🖱️ Scrolling page {managed_page.page_id} by {distance} pixels")

            # Use primitive operation
            scroller = ScrollPage()
            result = await scroller.scroll(managed_page.page, distance, self.slowmo)

            # Add page_id to result
            result["page_id"] = managed_page.page_id

            return result

        except Exception as e:
            error_result = {
                "success": False,
                "page_id": managed_page.page_id,
                "error": str(e)
            }
            print(f"❌ Page scroll failed: {e}")
            return error_result
        finally:
            # Set page back to idle state
            await managed_page.set_idle()

    async def screenshot(self, page_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Take a screenshot of the current page.
        
        Args:
            page_id (str, optional): Specific page ID to use, or None for any available page
            
        Returns:
            Dict containing screenshot result and page information
        """
        managed_page: ManagedPage = await self._get_page_to_use(page_id)
        
        try:
            print(f"📸 Taking screenshot of page {managed_page.page_id}")
            
            # Take screenshot and get bytes
            screenshot_bytes = await managed_page.page.screenshot()
            screenshot_base64 = base64.b64encode(screenshot_bytes).decode("utf-8")

            full_screenshot_bytes = await managed_page.page.screenshot(full_page=True)
            full_screenshot_base64 = base64.b64encode(full_screenshot_bytes).decode("utf-8")
            
            result = {
                "success": True,
                "page_id": managed_page.page_id,
                "screenshot": screenshot_base64,
                "full_screenshot": full_screenshot_base64,
                "url": managed_page.page.url
            }
            
            print(f"✅ Screenshot saved")
            return result
            
        except Exception as e:
            error_result = {
                "success": False,
                "page_id": managed_page.page_id,
                "error": str(e)
            }
            print(f"❌ Screenshot failed: {e}")
            return error_result
        finally:
            # Set page back to idle state
            await managed_page.set_idle()

    async def type_text(self, text: str, page_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Type text at the currently focused element on a page.

        IMPORTANT: An element should already be clicked/focused before calling this method.
        This operation will type at whatever element currently has focus.

        Args:
            text (str): Text to type
            page_id (str, optional): Specific page ID to use, or None for any available page

        Returns:
            Dict containing typing result and text information
        """
        managed_page = await self._get_page_to_use(page_id)

        try:
            print(f"⌨️ Typing text on page {managed_page.page_id}")

            # Use primitive operation (types at currently focused element)
            typer = TypeText()
            result = await typer.type(managed_page.page, text, self.slowmo // 10)

            # Add page_id to result
            result["page_id"] = managed_page.page_id

            return result

        except Exception as e:
            error_result = {
                "success": False,
                "page_id": managed_page.page_id,
                "error": str(e)
            }
            print(f"❌ Text typing failed: {e}")
            return error_result
        finally:
            # Set page back to idle state
            await managed_page.set_idle()

    async def press_enter(self, page_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Press the Enter key at the currently focused element on a page.

        IMPORTANT: An element should already be clicked/focused before calling this method.
        This operation will press Enter at whatever element currently has focus.

        Args:
            page_id (str, optional): Specific page ID to use, or None for any available page

        Returns:
            Dict containing press result and timing information
        """
        managed_page = await self._get_page_to_use(page_id)

        try:
            print(f"⏎ Pressing Enter on page {managed_page.page_id}")

            # Use primitive operation
            presser = PressEnter()
            result = await presser.press(managed_page.page, self.slowmo)

            # Add page_id to result
            result["page_id"] = managed_page.page_id

            return result

        except Exception as e:
            error_result = {
                "success": False,
                "page_id": managed_page.page_id,
                "error": str(e)
            }
            print(f"❌ Press Enter failed: {e}")
            return error_result
        finally:
            # Set page back to idle state
            await managed_page.set_idle()
            
    async def press_tab(self, with_shift: bool = False, page_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Press the Tab key to move focus to the next element on a page.

        IMPORTANT: The page should be in a state where Tab navigation is expected.
        This operation will move focus to the next focusable element.

        Args:
            with_shift (bool): If True, press Shift+Tab to move focus backwards (default: False)
            page_id (str, optional): Specific page ID to use, or None for any available page

        Returns:
            Dict containing press result and timing information
        """
        managed_page = await self._get_page_to_use(page_id)

        try:
            key_combo = "Shift+Tab" if with_shift else "Tab"
            print(f"⇥ Pressing {key_combo} on page {managed_page.page_id}")

            # Use primitive operation
            presser = PressTab()
            result = await presser.press(managed_page.page, with_shift, self.slowmo)

            # Add page_id to result
            result["page_id"] = managed_page.page_id

            return result

        except Exception as e:
            error_result = {
                "success": False,
                "page_id": managed_page.page_id,
                "error": str(e)
            }
            print(f"❌ Press Tab failed: {e}")
            return error_result
        finally:
            # Set page back to idle state
            await managed_page.set_idle()
            
    async def paste_text(self, text: str, page_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Paste text at the currently focused element on a page using clipboard.

        IMPORTANT: An element should already be clicked/focused before calling this method.
        This operation will paste at whatever element currently has focus.
        Use this for longer text content where typing would be too slow.

        Args:
            text (str): Text to paste
            page_id (str, optional): Specific page ID to use, or None for any available page

        Returns:
            Dict containing paste result and text information
        """
        managed_page = await self._get_page_to_use(page_id)

        try:
            print(f"📋 Pasting text on page {managed_page.page_id}")

            # Use primitive operation (pastes at currently focused element)
            paster = PasteText()
            result = await paster.paste(managed_page.page, text)

            # Add page_id to result
            result["page_id"] = managed_page.page_id

            return result

        except Exception as e:
            error_result = {
                "success": False,
                "page_id": managed_page.page_id,
                "error": str(e)
            }
            print(f"❌ Text pasting failed: {e}")
            return error_result
        finally:
            # Set page back to idle state
            await managed_page.set_idle()

    async def zoom_page(self, x: float, y: float, zoom_level: int = 1, page_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Zoom the page at specified coordinates.

        Args:
            x (float): X coordinate for zoom center
            y (float): Y coordinate for zoom center
            zoom_level (int): Number of zoom ticks (default: 1)
            page_id (str, optional): Specific page ID to use, or None for any available page

        Returns:
            Dict containing zoom result and information
        """
        managed_page = await self._get_page_to_use(page_id)

        try:
            print(f"🔍 Zooming page {managed_page.page_id} at ({x}, {y}) level {zoom_level}")

            # Use primitive operation
            zoomer = ZoomPage()
            result = await zoomer.zoom(managed_page, x, y, zoom_level, self.slowmo)

            # Add page_id to result
            result["page_id"] = managed_page.page_id

            return result

        except Exception as e:
            error_result = {
                "success": False,
                "page_id": managed_page.page_id,
                "error": str(e)
            }
            print(f"❌ Page zoom failed: {e}")
            return error_result
        finally:
            # Set page back to idle state
            await managed_page.set_idle()

    async def reset_zoom(self, page_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Reset page zoom to default level (100%).

        Args:
            page_id (str, optional): Specific page ID to use, or None for any available page

        Returns:
            Dict containing reset result and information
        """
        managed_page = await self._get_page_to_use(page_id)

        try:
            print(f"🔍 Resetting zoom on page {managed_page.page_id}")

            # Use primitive operation
            zoomer = ZoomPage()
            result = await zoomer.reset(managed_page, self.slowmo)

            # Add page_id to result
            result["page_id"] = managed_page.page_id

            return result

        except Exception as e:
            error_result = {
                "success": False,
                "page_id": managed_page.page_id,
                "error": str(e)
            }
            print(f"❌ Zoom reset failed: {e}")
            return error_result
        finally:
            # Set page back to idle state
            await managed_page.set_idle()
