"""Browser tab tool — interact with web pages via the Flowly Chrome extension.

The extension connects to the gateway via WebSocket. This tool sends
action requests to the extension and waits for results. All actions
execute in the user's REAL browser — they see everything in real-time.
"""

from __future__ import annotations

import asyncio
import base64
import json
import uuid
from datetime import datetime
from pathlib import Path
from typing import Any

from loguru import logger

from flowly.agent.tools.base import Tool

_SCREENSHOTS_DIR = Path.home() / ".flowly" / "screenshots"


class BrowserTabTool(Tool):
    """Interact with web pages in the user's real browser via Chrome extension."""

    def __init__(self, gateway_server: Any = None):
        self._gateway = gateway_server

    @property
    def name(self) -> str:
        return "browser_tab"

    @property
    def description(self) -> str:
        return (
            "Interact with web pages in the user's REAL browser (via Flowly Chrome extension). "
            "The user can see every action in real-time.\n\n"
            "Actions:\n"
            "- read_page: Get element map with ref IDs (text, NOT a screenshot). "
            "Returns interactive elements like buttons, links, inputs with unique refs.\n"
            "- click: Click by ref ID (ref='ref_3'), CSS selector (selector='[data-testid=\"tweetButton\"]'), "
            "or visible text (text='Post'). Selector and text are most reliable for known elements.\n"
            "- type: Type text into element (ref='ref_5', text='hello')\n"
            "- form_input: Set form field value (ref='ref_7', value='test@email.com')\n"
            "- find: Search for elements by description (query='Post button', 'search input'). "
            "Use when you can't find an element with read_page.\n"
            "- navigate: Go to URL (url='https://youtube.com')\n"
            "- get_page_text: Get page text content\n"
            "- screenshot: Capture tab screenshot (ONLY when user explicitly asks. Use read_page instead for automation)\n"
            "- scroll: Scroll page (direction=down/up, amount=3)\n"
            "- key: Press keyboard key or combo (key='Enter', key='Ctrl+a')\n"
            "- tabs_list: List tabs in the Flowly tab group\n"
            "- tabs_create: Open new tab (url='https://...')\n\n"
            "Workflow: tabs_list → navigate → read_page → click by ref → type → read_page (verify).\n"
            "Prefer read_page + ref IDs over screenshot + coordinates."
        )

    @property
    def parameters(self) -> dict[str, Any]:
        return {
            "type": "object",
            "properties": {
                "action": {
                    "type": "string",
                    "description": "The browser action to perform",
                    "enum": [
                        "read_page", "click", "type", "form_input", "find",
                        "navigate", "get_page_text", "screenshot",
                        "scroll", "key", "tabs_list", "tabs_create",
                    ],
                },
                "ref": {
                    "type": "string",
                    "description": "Element ref ID from read_page output (e.g. 'ref_3')",
                },
                "selector": {
                    "type": "string",
                    "description": "CSS selector to target element directly (e.g. '[data-testid=\"tweetButton\"]', 'button.submit'). More reliable than ref for known elements.",
                },
                "text": {
                    "type": "string",
                    "description": "Text to type, OR visible text to click (for click action: finds button/link by text like 'Post', 'Submit')",
                },
                "value": {
                    "type": "string",
                    "description": "Form field value to set",
                },
                "url": {
                    "type": "string",
                    "description": "URL to navigate to or open in new tab",
                },
                "direction": {
                    "type": "string",
                    "enum": ["up", "down", "left", "right"],
                    "description": "Scroll direction",
                },
                "amount": {
                    "type": "integer",
                    "description": "Scroll amount (default: 3)",
                },
                "submit": {
                    "type": "boolean",
                    "description": "Press Enter after typing (default: false)",
                },
                "clear": {
                    "type": "boolean",
                    "description": "Clear field before typing (default: false)",
                },
                "query": {
                    "type": "string",
                    "description": "Search query for find action (e.g. 'Post button', 'search input')",
                },
                "key": {
                    "type": "string",
                    "description": "Key to press (e.g. 'Enter', 'Tab', 'Ctrl+a')",
                },
                "interactive": {
                    "type": "boolean",
                    "description": "Filter read_page to interactive elements only (default: true)",
                },
                "tabId": {
                    "type": "integer",
                    "description": "Target tab ID (from tabs_list). Uses active group tab if omitted.",
                },
            },
            "required": ["action"],
        }

    async def execute(self, action: str = "", **kwargs: Any) -> str:
        if not self._gateway:
            return json.dumps({"error": "Gateway not available"})

        # Check if extension is connected
        if not self._gateway.has_extension_client():
            return json.dumps({
                "error": "Flowly Chrome extension not connected. "
                "Install the extension and open the side panel to connect."
            })

        request_id = str(uuid.uuid4())
        params = {k: v for k, v in kwargs.items() if v is not None}

        # Action-specific timeouts (Fix #8: generous timeouts prevent false timeout-after-action)
        action_timeouts = {
            "read_page": 20.0, "find": 20.0, "screenshot": 15.0,
            "navigate": 20.0, "get_page_text": 15.0,
            "click": 10.0, "type": 10.0, "form_input": 10.0,
            "scroll": 8.0, "key": 8.0,
            "tabs_list": 8.0, "tabs_create": 10.0,
        }
        timeout = action_timeouts.get(action, 15.0)

        try:
            result = await asyncio.wait_for(
                self._gateway.send_extension_tool_request(request_id, action, params),
                timeout=timeout,
            )

            # Screenshot: save base64 to file, return path (same as screenshot tool)
            if action == "screenshot" and isinstance(result, dict) and result.get("screenshot"):
                result = self._save_screenshot_to_file(result)

            return json.dumps(result) if isinstance(result, dict) else str(result)
        except asyncio.TimeoutError:
            return json.dumps({
                "error": f"Extension did not respond in {timeout}s ({action}). "
                "The action may have succeeded in the browser — verify with read_page before retrying.",
            })
        except Exception as e:
            logger.error("browser_tab {} error: {}", action, e)
            return json.dumps({"error": str(e)})

    @staticmethod
    def _save_screenshot_to_file(result: dict) -> dict:
        """Save base64 screenshot to file, return path instead of data.

        This follows the same pattern as the screenshot tool so the agent
        can use message(media_paths=[path]) to deliver the image to the
        user via relay → S3 → iOS/Desktop.
        """
        data_url = result.get("screenshot", "")
        if not data_url or not data_url.startswith("data:image/"):
            return result

        try:
            _SCREENSHOTS_DIR.mkdir(parents=True, exist_ok=True)

            # Parse data URL: "data:image/jpeg;base64,/9j/..."
            header, b64data = data_url.split(",", 1)
            ext = "jpg" if "jpeg" in header else "png"

            timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
            suffix = uuid.uuid4().hex[:6]
            filename = f"browser-{timestamp}-{suffix}.{ext}"
            output_path = _SCREENSHOTS_DIR / filename

            output_path.write_bytes(base64.b64decode(b64data))
            size_kb = output_path.stat().st_size / 1024

            logger.info(f"Browser screenshot saved: {output_path} ({size_kb:.1f}KB)")

            return {
                "success": True,
                "path": str(output_path),
                "sizeKB": round(size_kb),
                "message": (
                    f"Screenshot saved to {output_path}\n"
                    f"To send to user: message(content=\"Here is the screenshot\", "
                    f"media_paths=[\"{output_path}\"])"
                ),
            }
        except Exception as e:
            logger.error(f"Failed to save browser screenshot: {e}")
            return {"error": f"Screenshot save failed: {e}"}
