# main.py
import asyncio
import logging
from typing import Callable, Any, Awaitable, Optional, Union

from aiogram import Bot, Dispatcher, BaseMiddleware
from aiogram.client.default import DefaultBotProperties
from aiogram.types import Message, CallbackQuery
from aiogram.fsm.context import FSMContext
from aiogram.filters import Command

# ─────────────────────── SENTRY ───────────────────────
import sentry_sdk
from sentry_sdk.integrations.logging import LoggingIntegration

sentry_logging = LoggingIntegration(
    level=logging.INFO,
    event_level=logging.ERROR,
)

sentry_sdk.init(
    dsn="https://6d9f68d79bd05d99111a9ec70be7ef87@o4510425745391616.ingest.de.sentry.io/4510439231258704",
    integrations=[sentry_logging],
    traces_sample_rate=1.0,
)

class SentryUserMiddleware(BaseMiddleware):
    async def __call__(self, handler, event, data):
        if hasattr(event, "from_user") and event.from_user:
            sentry_sdk.set_user({"id": event.from_user.id})
        return await handler(event, data)


# ──────────────────────── PROJECT IMPORTS ────────────────────────
from constants import telegram_token
from src.bot.utils.commands import setup_bot_commands
from src.database.session import SessionLocal, dispose_engine
from src.database.db_methods.users import is_user_registered
from src.bot.states.survey import SurveyFSM, SettingsFSM
from src.bot.handlers.state_handlers.survey_refactored import router as survey_router
from src.bot.handlers.daily import router as daily_router
from src.bot.handlers.user_commands import router as dev_tools_router
from src.bot.handlers.content import router as content_router
from src.bot.handlers.settings_handlers import router as settings_router
from src.bot.middleware.idempotency import IdempotencyMiddleware


# ──────────────────────── BOT + LOGGING ────────────────────────
bot = Bot(token=telegram_token, default=DefaultBotProperties(parse_mode='HTML'))

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
)
logger = logging.getLogger("bot")


# ───────────────────────── AUTH GATE ─────────────────────────
class AuthGateMiddleware(BaseMiddleware):
    async def __call__(
            self,
            handler: Callable[[Union[Message, CallbackQuery], dict[str, Any]], Awaitable[Any]],
            event: Union[Message, CallbackQuery],
            data: dict[str, Any],
    ) -> Any:
        # Allow /start and /settings immediately
        if isinstance(event, Message) and any(
                f for f in event.entities or [] if f.type == "bot_command" and event.text and (
                        event.text.startswith("/start") or event.text.startswith("/settings")
                )
        ):
            return await handler(event, data)

        fsm: Optional[FSMContext] = data.get("state")
        current_state: Optional[str] = None
        if fsm:
            current_state = await fsm.get_state()

        # Allow survey and settings flow messages/callbacks
        if current_state and (
                current_state.startswith(SurveyFSM.__name__) or
                current_state.startswith(SettingsFSM.__name__)
        ):
            return await handler(event, data)

        # Extract Telegram user id
        if isinstance(event, Message):
            tg_id = str(event.from_user.id)
        elif isinstance(event, CallbackQuery):
            tg_id = str(event.from_user.id)
        else:
            return

        async with SessionLocal() as session:
            registered = await is_user_registered(session, tg_id)

        if registered:
            return await handler(event, data)

        if isinstance(event, Message):
            await event.answer("Доступ ограничен: пройди анкету командой /start.")
        elif isinstance(event, CallbackQuery):
            await event.answer("Доступ ограничен: пройди анкету командой /start.", show_alert=True)
        return


# ───────────────────────── LIFESPAN ─────────────────────────
async def on_startup() -> None:
    logger.info("Bot startup complete.")


async def on_shutdown() -> None:
    try:
        await dispose_engine()
    finally:
        logger.info("Bot shutdown complete.")


def _validate_config() -> None:
    if not telegram_token:
        raise RuntimeError("TG_BOT_TOKEN is not set in environment (see src/constants.py).")


# ─────────────────────────── MAIN ───────────────────────────
async def main() -> None:
    _validate_config()

    dp = Dispatcher()

    # Sentry user context
    dp.message.middleware(SentryUserMiddleware())
    dp.callback_query.middleware(SentryUserMiddleware())

    # Security middlewares
    dp.message.middleware(AuthGateMiddleware())
    dp.callback_query.middleware(AuthGateMiddleware())
    dp.callback_query.middleware(IdempotencyMiddleware())

    # Routers
    dp.include_router(survey_router)
    dp.include_router(settings_router)
    dp.include_router(daily_router)
    dp.include_router(dev_tools_router)
    dp.include_router(content_router)

    @dp.message(Command("export"))
    async def test_export(message: Message):
        logger.info(f"🔍 EXPORT COMMAND RECEIVED from user {message.from_user.id}")
        try:
            await message.answer("✅ Команда export работает из main.py!")
        except Exception as e:
            logger.error(f"❌ Error sending response: {e}")
            raise

    await setup_bot_commands(bot)
    dp.startup.register(on_startup)
    dp.shutdown.register(on_shutdown)

    await dp.start_polling(bot)


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except (KeyboardInterrupt, SystemExit):
        logger.info("Bot stopped by user.")
