import asyncio
import logging
import sys
from pathlib import Path

sys.path.append(str(Path(__file__).resolve().parents[1]))

from aiogram import Bot, Dispatcher  # noqa: E402
from aiogram.client.default import DefaultBotProperties  # noqa: E402
from aiogram.enums import ParseMode  # noqa: E402
from aiogram.fsm.storage.memory import MemoryStorage  # noqa: E402

from bot.config import settings  # noqa: E402
from bot.handlers import account, payment, purchase, start  # noqa: E402
from bot.middlewares.throttling import ThrottlingMiddleware  # noqa: E402
from bot.services.api import api  # noqa: E402
from bot.services.texts import texts  # noqa: E402

logger = logging.getLogger("bot")


def build_dispatcher() -> Dispatcher:
    dispatcher = Dispatcher(storage=MemoryStorage())
    dispatcher.message.middleware(ThrottlingMiddleware())
    dispatcher.callback_query.middleware(ThrottlingMiddleware())

    dispatcher.include_router(start.router)
    dispatcher.include_router(purchase.router)
    dispatcher.include_router(payment.router)
    dispatcher.include_router(account.router)
    return dispatcher


def build_bot() -> Bot:
    return Bot(
        token=settings.bot_token,
        default=DefaultBotProperties(parse_mode=ParseMode.HTML),
    )


async def run_polling() -> None:
    bot = build_bot()
    dispatcher = build_dispatcher()
    await texts.refresh(force=True)
    await bot.delete_webhook(drop_pending_updates=True)
    logger.info("bot started in polling mode")
    try:
        await dispatcher.start_polling(bot)
    finally:
        await api.close()
        await bot.session.close()


async def run_webhook() -> None:
    from aiohttp import web
    from aiogram.webhook.aiohttp_server import SimpleRequestHandler, setup_application

    bot = build_bot()
    dispatcher = build_dispatcher()
    await texts.refresh(force=True)
    await bot.set_webhook(
        f"{settings.webhook_url.rstrip('/')}{settings.webhook_path}",
        secret_token=settings.telegram_webhook_secret or None,
        drop_pending_updates=True,
    )

    app = web.Application()
    SimpleRequestHandler(
        dispatcher=dispatcher, bot=bot, secret_token=settings.telegram_webhook_secret or None
    ).register(app, path=settings.webhook_path)
    setup_application(app, dispatcher, bot=bot)

    runner = web.AppRunner(app)
    await runner.setup()
    site = web.TCPSite(runner, settings.webhook_host, settings.webhook_port)
    logger.info("bot started in webhook mode on %s", settings.webhook_port)
    await site.start()
    try:
        await asyncio.Event().wait()
    finally:
        await runner.cleanup()
        await api.close()
        await bot.session.close()


def main() -> None:
    logging.basicConfig(
        level=settings.log_level.upper(),
        format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
    )
    if settings.bot_mode == "webhook" and settings.webhook_url:
        asyncio.run(run_webhook())
    else:
        asyncio.run(run_polling())


if __name__ == "__main__":
    main()
