"""Tests for the Browser plugin."""

from __future__ import annotations

from typing import Any
from unittest.mock import patch

from agent_scout.plugins.browser import (
    BrowserPlugin,
    _extract_links,
    _extract_text,
)

# --- Mock browser engine ---


class MockBrowserEngine:
    """Mock browser engine for testing without Playwright."""

    def __init__(self, page_content: dict[str, Any] | None = None, fail: bool = False) -> None:
        self._page_content = page_content or {
            "url": "https://example.com",
            "title": "Example Page",
            "text": "Hello world. This is an example page.",
            "links": [{"url": "https://example.com/about", "text": "About"}],
            "html_length": 500,
        }
        self._fail = fail
        self._screenshot_path: str | None = None

    async def start(self) -> None:
        pass

    async def stop(self) -> None:
        pass

    async def get_page_content(self, url: str, timeout_ms: int = 15000) -> dict[str, Any]:
        if self._fail:
            raise ConnectionError("Browser navigation failed")
        content = dict(self._page_content)
        content["url"] = url
        return content

    async def take_screenshot(self, url: str, path: str, timeout_ms: int = 15000) -> str:
        if self._fail:
            raise ConnectionError("Screenshot failed")
        self._screenshot_path = path
        return path


# --- Tests ---


async def test_browse_returns_content():
    plugin = BrowserPlugin()
    await plugin.load()
    plugin._status = plugin.status  # keep status
    plugin.set_engine(MockBrowserEngine())
    # Manually enable since we replaced the engine
    await plugin.enable()

    result = await plugin.execute("browse", {"url": "https://example.com"})
    assert "Example Page" in result
    assert "Hello world" in result


async def test_browse_empty_url():
    plugin = BrowserPlugin()
    await plugin.load()
    plugin.set_engine(MockBrowserEngine())
    await plugin.enable()

    result = await plugin.execute("browse", {"url": ""})
    assert "Error" in result


async def test_browse_no_engine():
    plugin = BrowserPlugin()
    await plugin.load()
    plugin.set_engine(None)
    await plugin.enable()

    # Patch robots check to allow
    with patch("agent_scout.plugins.browser._check_robots_txt", return_value=True):
        result = await plugin.execute("browse", {"url": "https://example.com"})
    assert "not available" in result


async def test_browse_engine_failure():
    plugin = BrowserPlugin()
    await plugin.load()
    plugin.set_engine(MockBrowserEngine(fail=True))
    await plugin.enable()

    result = await plugin.execute("browse", {"url": "https://example.com"})
    assert "Error browsing" in result


async def test_screenshot():
    plugin = BrowserPlugin()
    await plugin.load()
    engine = MockBrowserEngine()
    plugin.set_engine(engine)
    await plugin.enable()

    result = await plugin.execute(
        "screenshot", {"url": "https://example.com", "save_path": "/tmp/test.png"}
    )
    assert "Screenshot saved" in result
    assert engine._screenshot_path == "/tmp/test.png"


async def test_screenshot_failure():
    plugin = BrowserPlugin()
    await plugin.load()
    plugin.set_engine(MockBrowserEngine(fail=True))
    await plugin.enable()

    result = await plugin.execute("screenshot", {"url": "https://example.com"})
    assert "Error taking screenshot" in result


async def test_unknown_tool():
    plugin = BrowserPlugin()
    result = await plugin.execute("unknown", {})
    assert "Unknown tool" in result


async def test_get_tools():
    plugin = BrowserPlugin()
    tools = plugin.get_tools()
    names = {t.name for t in tools}
    assert "browse" in names
    assert "screenshot" in names


async def test_robots_txt_blocked():
    """Browsing is blocked when robots.txt disallows."""
    plugin = BrowserPlugin()
    await plugin.load()
    plugin.set_engine(MockBrowserEngine())
    await plugin.enable()

    with patch("agent_scout.plugins.browser._check_robots_txt", return_value=False):
        result = await plugin.execute("browse", {"url": "https://blocked.com/secret"})
    assert "Blocked by robots.txt" in result


async def test_health_check():
    plugin = BrowserPlugin()
    assert await plugin.health_check() is False

    await plugin.load()
    plugin.set_engine(MockBrowserEngine())
    await plugin.enable()
    assert await plugin.health_check() is True


def test_extract_text():
    html = "<html><head><style>body{}</style></head><body><p>Hello <b>world</b></p></body></html>"
    text = _extract_text(html)
    assert "Hello world" in text
    assert "<" not in text


def test_extract_text_strips_scripts():
    html = '<script>alert("xss")</script><p>Safe content</p>'
    text = _extract_text(html)
    assert "alert" not in text
    assert "Safe content" in text


def test_extract_links():
    html = '<a href="/about">About Us</a><a href="https://external.com">External</a>'
    links = _extract_links(html, "https://example.com")
    assert len(links) == 2
    assert links[0]["url"] == "https://example.com/about"
    assert links[0]["text"] == "About Us"
    assert links[1]["url"] == "https://external.com"


async def test_long_content_truncated():
    long_text = "x" * 10000
    plugin = BrowserPlugin()
    await plugin.load()
    plugin.set_engine(
        MockBrowserEngine(
            page_content={
                "url": "https://example.com",
                "title": "Long Page",
                "text": long_text,
                "links": [],
                "html_length": 20000,
            }
        )
    )
    await plugin.enable()

    result = await plugin.execute("browse", {"url": "https://example.com"})
    assert "[truncated]" in result
