from __future__ import annotations

import asyncio
import logging

from aiogram import Bot, Dispatcher
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from aiogram.fsm.storage.memory import MemoryStorage
from sqlalchemy import select

from app.db import get_session
from app.handlers.reseller_bot import (
    ResellerSubscriptionMiddleware,
    build_reseller_router,
)
from app.models import ResellerBot

logger = logging.getLogger(__name__)

_tasks: dict[int, asyncio.Task] = {}


async def start_reseller_bot(reseller_id: int) -> bool:
    if reseller_id in _tasks and not _tasks[reseller_id].done():
        return True

    async with get_session() as session:
        reseller = await session.get(ResellerBot, reseller_id)
        if reseller is None or not reseller.is_active or not reseller.bot_token:
            return False
        token = reseller.bot_token

    bot = Bot(
        token=token,
        default=DefaultBotProperties(parse_mode=ParseMode.HTML),
    )
    dp = Dispatcher(storage=MemoryStorage())
    dp.update.outer_middleware(ResellerSubscriptionMiddleware(reseller_id))
    dp.include_router(build_reseller_router(reseller_id))

    async def _runner() -> None:
        try:
            await bot.delete_webhook(drop_pending_updates=True)
            await dp.start_polling(bot)
        except asyncio.CancelledError:
            raise
        except Exception:
            logger.exception("Reseller bot %s stopped with an error", reseller_id)
        finally:
            await bot.session.close()

    _tasks[reseller_id] = asyncio.create_task(_runner())
    logger.info("Reseller bot %s started", reseller_id)
    return True


async def start_all_reseller_bots() -> None:
    async with get_session() as session:
        ids = [
            row[0]
            for row in (
                await session.execute(
                    select(ResellerBot.id).where(ResellerBot.is_active.is_(True))
                )
            ).all()
        ]
    for reseller_id in ids:
        await start_reseller_bot(reseller_id)


def reseller_tasks() -> list[asyncio.Task]:
    return list(_tasks.values())
