"""
tools/browser_tool.py — Playwright headless browser tool.

For JS-heavy pages that httpx can't render. Enforces the same Tier 1/2
web whitelist as WebTool. Browser instance is lazy-initialized and shared
across calls.

Requires: playwright package + `playwright install chromium`
"""
from __future__ import annotations

import asyncio
import logging
from typing import ClassVar

from ..context_vars import current_task_id, web_tier2_enabled
from ..security import assert_domain_tier1, sanitize_external_content
from .base import BaseTool, ToolResult

logger = logging.getLogger(__name__)

_MAX_TEXT_CHARS = 25_000
_TIMEOUT_MS = 30_000


class BrowserTool(BaseTool):
    name = "browser"
    description = (
        "Fetch web pages using a real headless browser (Chromium). "
        "Use this for JS-heavy pages or single-page apps that the regular 'web' tool cannot read. "
        "Operations: fetch_page (extract text content), screenshot (base64 PNG). "
        "Follows the same domain whitelist rules as the web tool."
    )
    input_schema = {
        "type": "object",
        "properties": {
            "operation": {
                "type": "string",
                "enum": ["fetch_page", "screenshot"],
                "description": "fetch_page extracts text; screenshot returns a base64 PNG.",
            },
            "url": {
                "type": "string",
                "description": "URL to navigate to.",
            },
            "wait_for": {
                "type": "string",
                "description": "CSS selector to wait for before extracting content (optional).",
            },
            "extract_selector": {
                "type": "string",
                "description": "CSS selector to extract text from (optional; defaults to full page).",
            },
        },
        "required": ["operation", "url"],
    }
    requires_confirmation = False
    allowed_in_scheduled_tasks = False  # Too resource-heavy for scheduled agents

    # Module-level shared browser/playwright (lazy-init, reused)
    _playwright = None
    _browser = None
    _lock: ClassVar[asyncio.Lock] = asyncio.Lock()

    async def execute(self, operation: str, url: str = "", wait_for: str = "", extract_selector: str = "", **_) -> ToolResult:
        if not url:
            return ToolResult(success=False, error="'url' is required")

        # Whitelist check (same Tier 1/2 rules as WebTool)
        denied = await self._check_tier(url)
        if denied:
            return denied

        try:
            from playwright.async_api import async_playwright
        except ImportError:
            return ToolResult(
                success=False,
                error="Playwright is not installed. Run: pip install playwright && playwright install chromium",
            )

        try:
            browser = await self._get_browser()
            context = await browser.new_context(
                user_agent=(
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
                    "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
                )
            )
            page = await context.new_page()
            try:
                await page.goto(url, timeout=_TIMEOUT_MS, wait_until="domcontentloaded")

                if wait_for:
                    try:
                        await page.wait_for_selector(wait_for, timeout=10_000)
                    except Exception:
                        pass  # continue even if selector doesn't appear

                if operation == "screenshot":
                    data = await page.screenshot(type="png")
                    import base64
                    return ToolResult(success=True, data={"screenshot_base64": base64.b64encode(data).decode()})

                # fetch_page
                if extract_selector:
                    elements = await page.query_selector_all(extract_selector)
                    text_parts = [await el.inner_text() for el in elements]
                    text = "\n".join(text_parts)
                else:
                    text = await page.inner_text("body")

                text = text[:_MAX_TEXT_CHARS]
                text = await sanitize_external_content(text, source="browser")
                return ToolResult(success=True, data={"url": url, "text": text, "length": len(text)})
            finally:
                await context.close()
        except Exception as e:
            return ToolResult(success=False, error=f"Browser error: {e}")

    async def _get_browser(self):
        async with BrowserTool._lock:
            if BrowserTool._browser is None or not BrowserTool._browser.is_connected():
                from playwright.async_api import async_playwright
                BrowserTool._playwright = await async_playwright().start()
                BrowserTool._browser = await BrowserTool._playwright.chromium.launch(
                    args=["--no-sandbox", "--disable-dev-shm-usage"],
                )
                logger.info("[browser] Chromium launched")
            return BrowserTool._browser

    async def _check_tier(self, url: str) -> ToolResult | None:
        """Returns ToolResult(success=False) if denied, None if allowed."""
        from urllib.parse import urlparse
        if await assert_domain_tier1(url):
            return None
        task_id = current_task_id.get()
        if task_id is not None:
            return None
        if web_tier2_enabled.get():
            return None
        parsed = urlparse(url)
        return ToolResult(
            success=False,
            error=(
                f"Domain '{parsed.hostname}' is not in the Tier 1 whitelist. "
                "Ask me to fetch a specific external page to enable Tier 2 access."
            ),
        )
