"""
main.py
--------
نقطه ورود اصلی پروژه.
اجرای این فایل ربات را روشن می‌کند.
"""

from __future__ import annotations

import asyncio
import logging
from logging.handlers import RotatingFileHandler

from aiogram import Bot, Dispatcher, F
from aiogram.client.default import DefaultBotProperties
from aiogram.client.session.aiohttp import AiohttpSession
from aiogram.enums import ParseMode
from aiogram.fsm.context import FSMContext
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.types import CallbackQuery

import config

from database.database import init_db
from bot.middlewares.db_middleware import DatabaseMiddleware

from bot.keyboards.common import BACK_TO_MAIN_MENU
from bot.keyboards.main_menu import (
    MAIN_MENU_TEXT,
    main_menu_keyboard,
)


# ============================================================
# Handlerهای کاربر
# ============================================================

from bot.handlers import start as start_handler
from bot.handlers import services as services_handler
from bot.handlers import plans as plans_handler
from bot.handlers import payment as payment_handler
from bot.handlers import test as test_handler
from bot.handlers import referral as referral_handler
from bot.handlers import tutorials as tutorials_handler
from bot.handlers import support as support_handler


# ============================================================
# Handlerهای ادمین
# ============================================================

from bot.handlers.admin import plans as admin_plans_handler
from bot.handlers.admin import config as admin_config_handler
from bot.handlers.admin import users as admin_users_handler
from bot.handlers.admin import support as admin_support_handler


# ============================================================
# Logging
# ============================================================

def setup_logging() -> None:

    config.LOG_DIR.mkdir(
        parents=True,
        exist_ok=True,
    )

    log_file = config.LOG_DIR / "bot.log"

    formatter = logging.Formatter(
        "%(asctime)s | %(levelname)s | %(name)s | %(message)s"
    )

    file_handler = RotatingFileHandler(
        log_file,
        maxBytes=5 * 1024 * 1024,
        backupCount=3,
        encoding="utf-8",
    )

    file_handler.setFormatter(formatter)

    console_handler = logging.StreamHandler()
    console_handler.setFormatter(formatter)

    root_logger = logging.getLogger()
    root_logger.setLevel(logging.INFO)

    if not root_logger.handlers:

        root_logger.addHandler(
            file_handler
        )

        root_logger.addHandler(
            console_handler
        )

    logging.getLogger("aiogram").setLevel(
        logging.INFO
    )

    logging.getLogger("sqlalchemy.engine").setLevel(
        logging.WARNING
    )


# ============================================================
# Navigation
# ============================================================
#
# این Handler مستقیماً در main.py ثبت می‌شود تا دکمه
# «🏠 منوی اصلی» مستقل از navigation.py کار کند.
#
# callback_data:
#     main_menu
#
# ============================================================

async def handle_back_to_main_menu(
    callback: CallbackQuery,
    state: FSMContext,
) -> None:

    try:

        # پاک کردن تمام FSMهای فعال
        await state.clear()

        # نمایش مجدد منوی اصلی
        await callback.message.edit_text(
            MAIN_MENU_TEXT,
            reply_markup=main_menu_keyboard(),
        )

        await callback.answer()

    except Exception:

        logging.getLogger(__name__).exception(
            "خطا هنگام بازگشت به منوی اصلی"
        )

        # اگر edit_text به هر دلیلی شکست خورد،
        # پیام جدید ارسال می‌کنیم.
        try:

            await callback.message.answer(
                MAIN_MENU_TEXT,
                reply_markup=main_menu_keyboard(),
            )

            await callback.answer()

        except Exception:

            logging.getLogger(__name__).exception(
                "خطا هنگام ارسال منوی اصلی"
            )

            await callback.answer(
                "❌ خطا هنگام باز کردن منوی اصلی.",
                show_alert=True,
            )


# ============================================================
# Main
# ============================================================

async def main() -> None:

    setup_logging()

    logger = logging.getLogger(__name__)

    logger.info(
        "========================================"
    )

    logger.info(
        "در حال راه‌اندازی ربات..."
    )

    logger.info(
        "========================================"
    )

    # ========================================================
    # Database
    # ========================================================

    logger.info(
        "در حال مقداردهی اولیه دیتابیس..."
    )

    await init_db()

    logger.info(
        "دیتابیس آماده است."
    )

    # ========================================================
    # Telegram Connection
    # ========================================================

    logger.info(
        "در حال اتصال مستقیم به Telegram..."
    )

    session = AiohttpSession()

    # ========================================================
    # Bot
    # ========================================================

    bot = Bot(
        token=config.BOT_TOKEN,
        session=session,
        default=DefaultBotProperties(
            parse_mode=ParseMode.HTML
        ),
    )

    # ========================================================
    # Dispatcher
    # ========================================================

    storage = MemoryStorage()

    dp = Dispatcher(
        storage=storage
    )

    # ========================================================
    # Database Middleware
    # ========================================================

    db_middleware = DatabaseMiddleware()

    dp.message.middleware(
        db_middleware
    )

    dp.callback_query.middleware(
        db_middleware
    )

    # ========================================================
    # Navigation مستقیم
    # ========================================================
    #
    # این Handler عمداً قبل از Routerهای دیگر ثبت می‌شود.
    # چون callback آن فقط main_menu است، با Callbackهای
    # اختصاصی تداخل ندارد.
    #
    # ========================================================

    dp.callback_query.register(
        handle_back_to_main_menu,
        F.data == BACK_TO_MAIN_MENU,
    )

    logger.info(
        "Navigation handler ثبت شد. callback=%s",
        BACK_TO_MAIN_MENU,
    )

    # ========================================================
    # Admin Routers
    # ========================================================

    dp.include_router(
        admin_plans_handler.router
    )

    dp.include_router(
        admin_config_handler.router
    )

    dp.include_router(
        admin_users_handler.router
    )

    dp.include_router(
        admin_support_handler.router
    )

    # ========================================================
    # User Routers
    # ========================================================

    dp.include_router(
        start_handler.router
    )

    # ========================================================
    # Services
    # ========================================================

    dp.include_router(
        services_handler.router
    )

    # ========================================================
    # Test Account
    # ========================================================

    dp.include_router(
        test_handler.router
    )

    # ========================================================
    # Referral
    # ========================================================

    dp.include_router(
        referral_handler.router
    )

    # ========================================================
    # Tutorials
    # ========================================================

    dp.include_router(
        tutorials_handler.router
    )

    # ========================================================
    # Support
    # ========================================================

    dp.include_router(
        support_handler.router
    )

    # ========================================================
    # Payment
    # ========================================================

    dp.include_router(
        payment_handler.router
    )

    # ========================================================
    # Plans
    # ========================================================

    dp.include_router(
        plans_handler.router
    )

    logger.info(
        "Routerهای کاربر و ادمین ثبت شدند."
    )

    # ========================================================
    # Ready
    # ========================================================

    logger.info(
        "========================================"
    )

    logger.info(
        "ربات با موفقیت آماده شد."
    )

    logger.info(
        "ربات در حال اجراست..."
    )

    logger.info(
        "========================================"
    )

    # ========================================================
    # Delete old webhook
    # ========================================================

    try:

        await bot.delete_webhook(
            drop_pending_updates=True
        )

        logger.info(
            "Webhook قبلی حذف شد."
        )

    except Exception:

        logger.exception(
            "خطا هنگام حذف Webhook"
        )

    # ========================================================
    # Polling
    # ========================================================

    try:

        await dp.start_polling(
            bot
        )

    except Exception:

        logger.exception(
            "خطا هنگام اجرای Polling"
        )

        raise

    finally:

        try:

            await bot.session.close()

            logger.info(
                "Bot session بسته شد."
            )

        except Exception:

            logger.exception(
                "خطا هنگام بستن Bot Session"
            )

        try:

            await storage.close()

            logger.info(
                "FSM storage بسته شد."
            )

        except Exception:

            logger.exception(
                "خطا هنگام بستن FSM Storage"
            )

        logger.info(
            "اتصال ربات بسته شد."
        )


# ============================================================
# Entry Point
# ============================================================

if __name__ == "__main__":

    try:

        asyncio.run(
            main()
        )

    except KeyboardInterrupt:

        print(
            "ربات متوقف شد."
        )

    except SystemExit:

        print(
            "ربات متوقف شد."
        )