"""Tests for the plugin base class."""

from __future__ import annotations

from typing import Any

import pytest

from agent_scout.plugins.base import (
    Plugin,
    PluginConfig,
    PluginParam,
    PluginStatus,
    ToolSpec,
)

# --- Concrete test plugin ---


class EchoPlugin(Plugin):
    """Simple test plugin that echoes input."""

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

    @property
    def description(self) -> str:
        return "Echoes input back"

    def get_tools(self) -> list[ToolSpec]:
        return [
            ToolSpec(
                name="echo",
                description="Echo a message",
                parameters=[
                    PluginParam(name="message", description="Message to echo", required=True),
                ],
            ),
        ]

    async def execute(self, tool_name: str, tool_input: dict[str, Any]) -> str:
        if tool_name == "echo":
            return tool_input.get("message", "")
        return f"Unknown tool: {tool_name}"


class LifecyclePlugin(Plugin):
    """Plugin that tracks lifecycle calls."""

    def __init__(self, config: PluginConfig | None = None) -> None:
        super().__init__(config)
        self.lifecycle: list[str] = []

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

    @property
    def description(self) -> str:
        return "Tracks lifecycle"

    @property
    def dependencies(self) -> list[str]:
        return ["echo"]

    def get_tools(self) -> list[ToolSpec]:
        return []

    async def execute(self, tool_name: str, tool_input: dict[str, Any]) -> str:
        return ""

    async def on_load(self) -> None:
        self.lifecycle.append("on_load")

    async def on_unload(self) -> None:
        self.lifecycle.append("on_unload")

    async def on_config_change(self, new_config: PluginConfig) -> None:
        self.lifecycle.append("on_config_change")
        await super().on_config_change(new_config)


# --- Tests ---


async def test_plugin_initial_state():
    plugin = EchoPlugin()
    assert plugin.status == PluginStatus.UNLOADED
    assert plugin.name == "echo"
    assert plugin.description == "Echoes input back"
    assert plugin.version == "0.1.0"
    assert plugin.enabled is False  # not yet enabled


async def test_plugin_lifecycle():
    plugin = EchoPlugin()
    assert plugin.status == PluginStatus.UNLOADED

    await plugin.load()
    assert plugin.status == PluginStatus.LOADED

    await plugin.enable()
    assert plugin.status == PluginStatus.ENABLED
    assert plugin.enabled is True

    await plugin.disable()
    assert plugin.status == PluginStatus.DISABLED
    assert plugin.enabled is False

    await plugin.unload()
    assert plugin.status == PluginStatus.UNLOADED


async def test_plugin_execute():
    plugin = EchoPlugin()
    await plugin.load()
    await plugin.enable()

    result = await plugin.execute("echo", {"message": "hello"})
    assert result == "hello"


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


async def test_plugin_get_tools():
    plugin = EchoPlugin()
    tools = plugin.get_tools()
    assert len(tools) == 1
    assert tools[0].name == "echo"
    assert tools[0].parameters[0].name == "message"
    assert tools[0].parameters[0].required is True


async def test_tool_spec_to_dict():
    spec = ToolSpec(
        name="search",
        description="Search the web",
        parameters=[
            PluginParam(name="query", description="Search query", required=True),
            PluginParam(name="limit", description="Max results", param_type="number", default=10),
        ],
    )
    d = spec.to_dict()
    assert d["name"] == "search"
    assert d["description"] == "Search the web"
    assert d["parameters"]["required"] == ["query"]
    assert d["parameters"]["properties"]["query"]["type"] == "string"
    assert d["parameters"]["properties"]["limit"]["default"] == 10


async def test_plugin_get_tool_metadata():
    plugin = EchoPlugin()
    meta = plugin.get_tool_metadata()
    assert len(meta) == 1
    assert meta[0]["name"] == "echo"
    assert "parameters" in meta[0]


async def test_plugin_health_check():
    plugin = EchoPlugin()
    # Not enabled yet — health check should return False
    assert await plugin.health_check() is False

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


async def test_lifecycle_hooks():
    plugin = LifecyclePlugin()
    await plugin.load()
    assert plugin.lifecycle == ["on_load"]

    await plugin.enable()

    await plugin.on_config_change(PluginConfig(settings={"key": "val"}))
    assert "on_config_change" in plugin.lifecycle
    assert plugin.config.settings == {"key": "val"}

    await plugin.unload()
    assert "on_unload" in plugin.lifecycle


async def test_plugin_dependencies():
    plugin = LifecyclePlugin()
    assert plugin.dependencies == ["echo"]


async def test_enable_from_wrong_state():
    plugin = EchoPlugin()
    # Cannot enable from UNLOADED state
    with pytest.raises(RuntimeError, match="Cannot enable"):
        await plugin.enable()


async def test_plugin_config():
    config = PluginConfig(enabled=True, settings={"api_key": "test123"})
    plugin = EchoPlugin(config=config)
    assert plugin.config.settings["api_key"] == "test123"
