"""Web view tool — open a URL in a real browser and extract readable content."""

import base64
import re

from playwright.async_api import async_playwright

from .base import Tool, ToolResult

_TIMEOUT = 30_000        # ms for page load
_MAX_TEXT = 20_000       # chars — cap huge pages


def _clean(text: str) -> str:
    """Collapse excessive blank lines and strip trailing whitespace."""
    lines = [line.rstrip() for line in text.splitlines()]
    result: list[str] = []
    blank_run = 0
    for line in lines:
        if line == "":
            blank_run += 1
            if blank_run <= 2:
                result.append("")
        else:
            blank_run = 0
            result.append(line)
    return "\n".join(result).strip()


class WebViewTool(Tool):
    name = "web_view"
    description = (
        "Open a URL in a real headless browser and return clean readable text. "
        "Use this to browse web pages — it executes JavaScript, waits for the page "
        "to finish loading, and strips HTML/scripts so you get the actual content. "
        "Optionally takes a screenshot so you can see the page visually. "
        "Use http_request instead when working with REST APIs, JSON endpoints, "
        "or services that need custom headers/auth."
    )
    parameters = {
        "type": "object",
        "properties": {
            "url": {
                "type": "string",
                "description": "Full URL to open (must start with http:// or https://)",
            },
            "screenshot": {
                "type": "boolean",
                "description": "If true, also capture a screenshot of the page (default: false)",
            },
            "wait_until": {
                "type": "string",
                "enum": ["load", "domcontentloaded", "networkidle"],
                "description": (
                    "When to consider the page loaded. "
                    "'networkidle' (default) waits for no network activity — best for SPAs. "
                    "'load' is faster but may miss dynamic content."
                ),
            },
        },
        "required": ["url"],
    }

    async def execute(self, params: dict) -> ToolResult:
        url: str = params["url"].strip()
        take_screenshot: bool = params.get("screenshot", False)
        wait_until: str = params.get("wait_until", "networkidle")

        if not url.startswith(("http://", "https://")):
            return ToolResult(success=False, output="URL must start with http:// or https://",
                              error="invalid url")

        try:
            async with async_playwright() as pw:
                browser = await pw.chromium.launch(headless=True)
                context = await browser.new_context(
                    viewport={"width": 1280, "height": 800},
                    user_agent=(
                        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
                        "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
                    ),
                )
                page = await context.new_page()

                try:
                    await page.goto(url, wait_until=wait_until, timeout=_TIMEOUT)
                except Exception:
                    # Timeout waiting for networkidle is often fine — page may still be usable
                    pass

                title = await page.title()
                final_url = page.url

                # Extract readable text: hide noise, grab visible text
                text = await page.evaluate("""() => {
                    const kill = ['script','style','noscript','iframe',
                                  'nav','header','footer','aside',
                                  '[role="navigation"]','[role="banner"]',
                                  '[role="contentinfo"]'];
                    const clone = document.body.cloneNode(true);
                    kill.forEach(sel => {
                        clone.querySelectorAll(sel).forEach(el => el.remove());
                    });
                    return clone.innerText || clone.textContent || '';
                }""")

                text = _clean(text)
                if len(text) > _MAX_TEXT:
                    text = text[:_MAX_TEXT] + f"\n\n[… truncated at {_MAX_TEXT} chars]"

                output_parts = []
                if title:
                    output_parts.append(f"Title: {title}")
                if final_url != url:
                    output_parts.append(f"Final URL: {final_url}")
                output_parts.append("")
                output_parts.append(text)
                output = "\n".join(output_parts)

                # Screenshot
                screenshot_b64: str | None = None
                if take_screenshot:
                    png = await page.screenshot(full_page=False)
                    screenshot_b64 = base64.b64encode(png).decode()

                await context.close()
                await browser.close()

            metadata: dict = {}
            if screenshot_b64:
                metadata = {"base64": screenshot_b64, "mime": "image/png", "is_image": True}

            return ToolResult(success=True, output=output, metadata=metadata or None)

        except Exception as e:
            return ToolResult(success=False, output=f"Browser error: {e}", error=str(e))
