"""Page tools for browser control."""

import json
from datetime import datetime
from pathlib import Path
from typing import Literal

from mcp.server.fastmcp import FastMCP

from ..browser import browser_manager


def register(mcp: FastMCP) -> None:
    """Register page tools with the MCP server."""

    @mcp.tool()
    async def browser_evaluate(
        function: str,
        element: str | None = None,
        ref: str | None = None,
    ) -> str:
        """Evaluate JavaScript expression on page or element.

        Args:
            function: JavaScript function to execute. Format:
                     '() => { /* code */ }' or
                     '(element) => { /* code */ }' when element is provided
            element: Human-readable element description (optional)
            ref: Exact target element reference for element-scoped evaluation (optional)

        Returns:
            Result of the JavaScript evaluation
        """
        page = await browser_manager.get_page()

        try:
            if ref:
                # Evaluate on specific element
                from .interaction import _parse_ref

                selector = _parse_ref(ref)
                element_handle = await page.query_selector(selector)
                if element_handle is None:
                    return f"Element not found: {ref}"
                result = await element_handle.evaluate(function)
            else:
                # Evaluate on page
                result = await page.evaluate(function)

            # Format result
            if result is None:
                return "Evaluation completed (returned undefined)"
            elif isinstance(result, (dict, list)):
                return json.dumps(result, indent=2)
            else:
                return str(result)
        except Exception as e:
            return f"Evaluation failed: {e}"

    @mcp.tool()
    async def browser_console_messages(
        level: Literal["error", "warning", "info", "debug"] = "info",
    ) -> str:
        """Returns all console messages.

        Args:
            level: Minimum level of messages to return. Each level includes
                   messages of more severe levels. Defaults to "info".

        Returns:
            Formatted console messages
        """
        messages = browser_manager.get_console_messages(level)

        if not messages:
            return f"No console messages at level '{level}' or above"

        lines = []
        for msg in messages:
            location = f" ({msg.location})" if msg.location else ""
            lines.append(f"[{msg.type.upper()}]{location} {msg.text}")

        return "\n".join(lines)

    @mcp.tool()
    async def browser_network_requests(include_static: bool = False) -> str:
        """Returns all network requests since loading the page.

        Args:
            include_static: Whether to include static resources like images,
                           fonts, scripts, etc. Defaults to false.

        Returns:
            Formatted network requests
        """
        requests = browser_manager.get_network_requests(include_static)

        if not requests:
            return "No network requests recorded"

        lines = []
        for req in requests:
            status = req.status if req.status else "pending"
            lines.append(f"[{req.method}] {req.url} - {status} ({req.resource_type})")

        return "\n".join(lines)

    @mcp.tool()
    async def browser_take_screenshot(
        full_page: bool = False,
        filename: str | None = None,
        element: str | None = None,
        ref: str | None = None,
        type: Literal["png", "jpeg"] = "png",
    ) -> str:
        """Take a screenshot of the current page or element.

        Args:
            full_page: When true, takes a screenshot of the full scrollable page.
                      Cannot be used with element screenshots.
            filename: File name to save the screenshot to. Defaults to
                     'page-{timestamp}.{png|jpeg}' if not specified.
            element: Human-readable element description (optional)
            ref: Exact target element reference for element screenshot (optional)
            type: Image format for the screenshot (png or jpeg). Defaults to png.

        Returns:
            Path to the saved screenshot
        """
        page = await browser_manager.get_page()

        try:
            # Generate filename if not provided
            if not filename:
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                filename = f"page-{timestamp}.{type}"

            # Ensure path is absolute
            path = Path(filename)
            if not path.is_absolute():
                path = Path.cwd() / "screenshots" / filename
                path.parent.mkdir(parents=True, exist_ok=True)

            if ref:
                # Element screenshot
                from .interaction import _parse_ref

                selector = _parse_ref(ref)
                element_handle = await page.query_selector(selector)
                if element_handle is None:
                    return f"Element not found: {ref}"
                await element_handle.screenshot(path=str(path), type=type)
                return f"Screenshot of {element} saved to: {path}"
            else:
                # Page screenshot
                await page.screenshot(path=str(path), full_page=full_page, type=type)
                return f"Screenshot saved to: {path}"
        except Exception as e:
            return f"Screenshot failed: {e}"
