from unittest.mock import AsyncMock, MagicMock

import pytest

from ui_router.aiogram.filters import ABGroupFilter, BotExcludeFilter, BotIncludeFilter


def make_event(bot_id: int = 1, user_id: int = 100) -> MagicMock:
    event = MagicMock()
    event.bot = MagicMock()
    event.bot.id = bot_id
    event.from_user = MagicMock()
    event.from_user.id = user_id
    return event


class TestBotIncludeFilter:
    async def test_matching_bot_id_returns_true(self):
        f = BotIncludeFilter(bot_id=1)
        event = make_event(bot_id=1)
        assert await f(event) is True

    async def test_non_matching_bot_id_returns_false(self):
        f = BotIncludeFilter(bot_id=1)
        event = make_event(bot_id=2)
        assert await f(event) is False


class TestBotExcludeFilter:
    async def test_empty_set_allows_all(self):
        f = BotExcludeFilter(blocked_bot_ids=set())
        event = make_event(bot_id=1)
        assert await f(event) is True

    async def test_none_creates_empty_set_allows_all(self):
        f = BotExcludeFilter(blocked_bot_ids=None)
        event = make_event(bot_id=1)
        assert await f(event) is True

    async def test_bot_id_in_blocked_returns_false(self):
        f = BotExcludeFilter(blocked_bot_ids={1, 2, 3})
        event = make_event(bot_id=2)
        assert await f(event) is False

    async def test_bot_id_not_in_blocked_returns_true(self):
        f = BotExcludeFilter(blocked_bot_ids={2, 3})
        event = make_event(bot_id=1)
        assert await f(event) is True

    async def test_mutable_set_adding_bot_id_after_creation_blocks_it(self):
        blocked: set[int] = set()
        f = BotExcludeFilter(blocked_bot_ids=blocked)
        event = make_event(bot_id=5)

        assert await f(event) is True

        blocked.add(5)
        assert await f(event) is False


class TestABGroupFilter:
    async def test_resolver_returns_matching_group(self):
        resolver = AsyncMock(return_value="group_a")
        f = ABGroupFilter(group_name="group_a", resolver=resolver)
        event = make_event(bot_id=10, user_id=200)

        assert await f(event) is True
        resolver.assert_awaited_once_with(10, 200)

    async def test_resolver_returns_different_group(self):
        resolver = AsyncMock(return_value="group_b")
        f = ABGroupFilter(group_name="group_a", resolver=resolver)
        event = make_event(bot_id=10, user_id=200)

        assert await f(event) is False

    async def test_from_user_is_none_returns_false(self):
        resolver = AsyncMock(return_value="group_a")
        f = ABGroupFilter(group_name="group_a", resolver=resolver)
        event = make_event(bot_id=10, user_id=200)
        event.from_user = None

        assert await f(event) is False
        resolver.assert_not_awaited()
