"""Tests for the Notification plugin."""

from __future__ import annotations

from agent_scout.plugins.notifier import (
    NotificationChannel,
    NotifierPlugin,
    TerminalChannel,
    Throttle,
)

# --- Mock channels ---


class MockChannel(NotificationChannel):
    name = "mock"

    def __init__(self, succeed: bool = True) -> None:
        self._succeed = succeed
        self.sent: list[tuple[str, str]] = []

    async def send(self, title: str, message: str) -> bool:
        self.sent.append((title, message))
        return self._succeed

    def is_configured(self) -> bool:
        return True


class UnconfiguredChannel(NotificationChannel):
    name = "unconfigured"

    async def send(self, title: str, message: str) -> bool:
        return True

    def is_configured(self) -> bool:
        return False


# --- Tests ---


async def test_send_notification():
    plugin = NotifierPlugin()
    await plugin.load()
    await plugin.enable()

    ch = MockChannel()
    plugin.set_channels([ch])

    result = await plugin.execute("notify", {"title": "Test", "message": "Hello"})
    assert "sent to 1" in result
    assert ch.sent == [("Test", "Hello")]


async def test_send_to_multiple_channels():
    plugin = NotifierPlugin()
    await plugin.load()
    await plugin.enable()

    ch1 = MockChannel()
    ch1.name = "ch1"
    ch2 = MockChannel()
    ch2.name = "ch2"
    plugin.set_channels([ch1, ch2])

    result = await plugin.execute("notify", {"title": "Test", "message": "Hello"})
    assert "sent to 2" in result


async def test_channel_filter():
    plugin = NotifierPlugin()
    await plugin.load()
    await plugin.enable()

    ch1 = MockChannel()
    ch1.name = "slack"
    ch2 = MockChannel()
    ch2.name = "email"
    plugin.set_channels([ch1, ch2])

    result = await plugin.execute(
        "notify", {"title": "Test", "message": "Hello", "channels": "slack"}
    )
    assert "sent to 1" in result
    assert len(ch1.sent) == 1
    assert len(ch2.sent) == 0


async def test_missing_title_or_message():
    plugin = NotifierPlugin()
    await plugin.load()
    await plugin.enable()
    plugin.set_channels([MockChannel()])

    result = await plugin.execute("notify", {"title": "", "message": "Hello"})
    assert "Error" in result

    result = await plugin.execute("notify", {"title": "Test", "message": ""})
    assert "Error" in result


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


async def test_throttle():
    plugin = NotifierPlugin()
    await plugin.load()
    await plugin.enable()
    plugin.set_channels([MockChannel()])
    plugin._throttle = Throttle(max_per_period=2, period_seconds=60)

    await plugin.execute("notify", {"title": "1", "message": "a"})
    await plugin.execute("notify", {"title": "2", "message": "b"})
    result = await plugin.execute("notify", {"title": "3", "message": "c"})
    assert "throttled" in result


async def test_all_channels_fail():
    plugin = NotifierPlugin()
    await plugin.load()
    await plugin.enable()

    failing = MockChannel(succeed=False)
    plugin.set_channels([failing])

    result = await plugin.execute("notify", {"title": "Test", "message": "Hello"})
    assert "Failed" in result


async def test_partial_failure():
    plugin = NotifierPlugin()
    await plugin.load()
    await plugin.enable()

    ok = MockChannel(succeed=True)
    ok.name = "ok"
    fail = MockChannel(succeed=False)
    fail.name = "fail"
    plugin.set_channels([ok, fail])

    result = await plugin.execute("notify", {"title": "Test", "message": "Hello"})
    assert "1 channel(s)" in result
    assert "1 failed" in result


async def test_unconfigured_channels_skipped():
    plugin = NotifierPlugin()
    await plugin.load()
    await plugin.enable()

    plugin.set_channels([UnconfiguredChannel()])

    result = await plugin.execute("notify", {"title": "Test", "message": "Hello"})
    # No configured channels sent, so 0 results
    assert "Failed" in result or "No notification" in result or "0" in result


async def test_get_tools():
    plugin = NotifierPlugin()
    tools = plugin.get_tools()
    assert len(tools) == 1
    assert tools[0].name == "notify"


def test_throttle_class():
    t = Throttle(max_per_period=3, period_seconds=60)
    assert t.allow() is True
    assert t.allow() is True
    assert t.allow() is True
    assert t.allow() is False


async def test_terminal_channel():
    ch = TerminalChannel()
    assert ch.is_configured() is True
    assert await ch.send("Title", "Message") is True


async def test_on_load_builds_channels():
    from agent_scout.plugins.base import PluginConfig

    config = PluginConfig(
        settings={
            "slack_webhook_url": "https://hooks.slack.com/test",
            "discord_webhook_url": "https://discord.com/api/webhooks/test",
        }
    )
    plugin = NotifierPlugin(config=config)
    await plugin.load()

    # terminal + dashboard + slack + discord = 4
    assert len(plugin._channels) == 4
    names = {c.name for c in plugin._channels}
    assert "terminal" in names
    assert "dashboard" in names
    assert "slack" in names
    assert "discord" in names
