import logging

from aiogram import F, Router
from aiogram.filters import Command, CommandObject, CommandStart
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, ErrorEvent, Message

from bot.keyboards.common import main_menu
from bot.services.api import ApiError, api
from bot.services.checkout import render
from bot.services.texts import money, texts

logger = logging.getLogger("bot.start")
router = Router(name="start")


async def _open_main_menu(event: Message | CallbackQuery, referral_code: str | None = None) -> None:
    user = event.from_user
    if not user:
        return

    payload = {
        "telegram_id": user.id,
        "username": user.username,
        "first_name": user.first_name,
        "last_name": user.last_name,
        "language": user.language_code or "fa",
        "referral_code": referral_code,
    }
    data = await api.start(payload)
    text = await texts.text(
        "welcome", name=user.first_name or "", balance=money(data.get("balance", 0))
    )
    await render(event, text, await main_menu(data.get("menu", [])))


@router.message(CommandStart())
async def cmd_start(message: Message, command: CommandObject, state: FSMContext) -> None:
    await state.clear()
    await texts.refresh(force=True)
    referral_code = (command.args or "").strip() or None
    await _open_main_menu(message, referral_code)


@router.message(Command("menu"))
async def cmd_menu(message: Message, state: FSMContext) -> None:
    await state.clear()
    await _open_main_menu(message)


@router.callback_query(F.data == "menu:main")
async def back_to_main(callback: CallbackQuery, state: FSMContext) -> None:
    await state.clear()
    await _open_main_menu(callback)
    await callback.answer()


@router.errors()
async def handle_errors(event: ErrorEvent) -> bool:
    """Log unexpected failures and keep the user on a working screen."""
    exception = event.exception
    logger.exception("unhandled bot error: %s", exception)

    message = event.update.message
    callback = event.update.callback_query

    text = (
        await texts.error(exception.code)
        if isinstance(exception, ApiError)
        else await texts.error("generic")
    )
    try:
        if callback:
            await callback.answer(text, show_alert=True)
        elif message:
            await message.answer(text)
    except Exception:  # noqa: BLE001 - never raise from the error handler
        logger.warning("could not deliver error message to user")
    return True
