import pytest
from unittest.mock import AsyncMock, MagicMock
from services.subscription import check_subscriptions
from config import Speaker

SPEAKERS = [
    Speaker(name="Спикер 1", channel="@chan1"),
    Speaker(name="Спикер 2", channel="@chan2"),
]


def _make_member(status: str):
    m = MagicMock()
    m.status = status
    return m


@pytest.mark.asyncio
async def test_all_subscribed_returns_empty():
    bot = AsyncMock()
    bot.get_chat_member.return_value = _make_member("member")
    result = await check_subscriptions(bot, user_id=1, speakers=SPEAKERS)
    assert result == []


@pytest.mark.asyncio
async def test_left_channel_returned():
    bot = AsyncMock()
    bot.get_chat_member.side_effect = [
        _make_member("member"),
        _make_member("left"),
    ]
    result = await check_subscriptions(bot, user_id=1, speakers=SPEAKERS)
    assert result == ["@chan2"]


@pytest.mark.asyncio
async def test_kicked_channel_returned():
    bot = AsyncMock()
    bot.get_chat_member.return_value = _make_member("kicked")
    result = await check_subscriptions(bot, user_id=1, speakers=SPEAKERS)
    assert "@chan1" in result and "@chan2" in result


@pytest.mark.asyncio
async def test_api_error_treated_as_not_subscribed():
    bot = AsyncMock()
    bot.get_chat_member.side_effect = Exception("Bot not in channel")
    result = await check_subscriptions(bot, user_id=1, speakers=SPEAKERS)
    assert result == ["@chan1", "@chan2"]


from services.subscription import is_subscribed
from aiogram.exceptions import TelegramRetryAfter, TelegramForbiddenError


@pytest.mark.asyncio
async def test_is_subscribed_member_true():
    bot = AsyncMock()
    bot.get_chat_member.return_value = _make_member("member")
    assert await is_subscribed(bot, user_id=1, channel="@chan") is True


@pytest.mark.asyncio
async def test_is_subscribed_left_false():
    bot = AsyncMock()
    bot.get_chat_member.return_value = _make_member("left")
    assert await is_subscribed(bot, user_id=1, channel="@chan") is False


@pytest.mark.asyncio
async def test_is_subscribed_api_error_none():
    bot = AsyncMock()
    bot.get_chat_member.side_effect = TelegramForbiddenError(method=None, message="bot not admin")
    assert await is_subscribed(bot, user_id=1, channel="@chan") is None


@pytest.mark.asyncio
async def test_is_subscribed_rate_limit_none_not_raised():
    bot = AsyncMock()
    bot.get_chat_member.side_effect = TelegramRetryAfter(method=None, message="flood", retry_after=5)
    # Must NOT raise — collapses to None.
    assert await is_subscribed(bot, user_id=1, channel="@chan") is None


@pytest.mark.asyncio
async def test_is_subscribed_network_error_none():
    bot = AsyncMock()
    bot.get_chat_member.side_effect = Exception("network down")
    assert await is_subscribed(bot, user_id=1, channel="@chan") is None
