from __future__ import annotations
import logging
from typing import Optional
from aiogram import Bot
from aiogram.exceptions import TelegramAPIError, TelegramRetryAfter
from config import Speaker

logger = logging.getLogger(__name__)

SUBSCRIBED_STATUSES = {"creator", "administrator", "member", "restricted"}


async def check_subscriptions(bot: Bot, user_id: int, speakers: list[Speaker]) -> list[str]:
    """
    Returns list of channels user is NOT subscribed to.
    Raises TelegramRetryAfter if rate limited (caller should back off).
    Treats bot-not-in-channel errors as "not subscribed" (fail-safe for setup issues).
    """
    not_subscribed = []
    for speaker in speakers:
        try:
            member = await bot.get_chat_member(chat_id=speaker.channel, user_id=user_id)
            if member.status not in SUBSCRIBED_STATUSES:
                not_subscribed.append(speaker.channel)
        except TelegramRetryAfter:
            # Re-raise — caller (broadcast.py) handles rate limiting
            raise
        except TelegramAPIError as e:
            # Bot not in channel, channel not found, etc. → treat as not subscribed
            logger.warning("getChatMember API error for user=%d channel=%s: %s", user_id, speaker.channel, e)
            not_subscribed.append(speaker.channel)
        except Exception as exc:
            # Network error, timeout, etc. → log and treat as not subscribed (fail-safe)
            logger.warning("getChatMember unexpected error for user=%d channel=%s: %s", user_id, speaker.channel, exc)
            not_subscribed.append(speaker.channel)
    return not_subscribed


async def is_subscribed(bot: Bot, user_id: int, channel: str) -> Optional[bool]:
    """Tristate single-channel subscription check.

    True  — member (status in SUBSCRIBED_STATUSES).
    False — API answered, status is not a member status (genuinely not subscribed).
    None  — could not verify: any API/network error, rate limit, or bot-not-admin.

    Unlike check_subscriptions, TelegramRetryAfter is NOT re-raised here — it
    collapses to None, so a subscribed user never gets a false "subscribe" prompt
    on a transient error.
    """
    try:
        member = await bot.get_chat_member(chat_id=channel, user_id=user_id)
    except TelegramRetryAfter as e:
        logger.warning("Rate limit checking subscription user=%d channel=%s: %ds", user_id, channel, e.retry_after)
        return None
    except TelegramAPIError as e:
        logger.warning("getChatMember API error user=%d channel=%s: %s", user_id, channel, e)
        return None
    except Exception as exc:
        logger.warning("getChatMember unexpected error user=%d channel=%s: %s", user_id, channel, exc)
        return None
    return member.status in SUBSCRIBED_STATUSES
