import asyncio
import logging
import time
from datetime import datetime
from typing import Optional, Dict

import aiohttp
from aiogram import Bot, Dispatcher, Router, types, F
from aiogram.exceptions import TelegramBadRequest, TelegramAPIError
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.utils.keyboard import InlineKeyboardBuilder

from .data import (
    get_user_api_key,
    set_user_api_key,
    delete_user_api_key
)
from .api import SmsHubAPI  # Убедитесь, что путь импорта корректен

EXCHANGE_RATE_API_URL = "https://api.exchangerate-api.com/v4/latest/USD"
USD_TO_RUB_RATE_TTL = 3600  # Кэшируем курс на 1 час

router = Router()
logger = logging.getLogger(__name__)

# Переменные для кэширования курса
_cached_usd_to_rub_rate = None
_cached_usd_to_rub_rate_time = 0

# Словарь для хранения активных активаций пользователей: {user_id: {activation_id: ActivationData}}
user_activations: Dict[int, Dict[str, Dict]] = {}


async def get_usd_to_rub_rate() -> Optional[float]:
    """Получить текущий курс USD к RUB с кэшированием."""
    global _cached_usd_to_rub_rate, _cached_usd_to_rub_rate_time
    now = time.time()
    if _cached_usd_to_rub_rate and (now - _cached_usd_to_rub_rate_time < USD_TO_RUB_RATE_TTL):
        return _cached_usd_to_rub_rate
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(EXCHANGE_RATE_API_URL) as response:
                data = await response.json()
                rate = data.get('rates', {}).get('RUB')
                if rate:
                    _cached_usd_to_rub_rate = rate
                    _cached_usd_to_rub_rate_time = now
                    return rate
                else:
                    logger.error("Курс RUB не найден в ответе.")
                    return None
    except Exception as e:
        logger.error(f"Ошибка при запросе курса валют: {e}")
        return None


class UserSettings(StatesGroup):
    entering_api_key = State()


class SmsOrderState(StatesGroup):
    waiting_for_service = State()
    waiting_for_max_price = State()


# Хелпер-функция для безопасного редактирования сообщения
async def safe_edit_message(message: types.Message, new_text: str, reply_markup=None, parse_mode=None):
    try:
        await message.edit_text(new_text, reply_markup=reply_markup, parse_mode=parse_mode)
    except Exception as e:
        logger.error(f"Failed to edit message: {e}")
        try:
            await message.answer(new_text, reply_markup=reply_markup, parse_mode=parse_mode)
        except Exception as e2:
            logger.error(f"Failed to send answer: {e2}")
            # Если не удалось ответить, попробуем отправить сообщение напрямую
            try:
                await message.bot.send_message(chat_id=message.chat.id, text=new_text, reply_markup=reply_markup, parse_mode=parse_mode)
            except Exception as e3:
                logger.error(f"Failed to send message directly: {e3}")


@router.message(Command('start'))
async def start_handler(message: types.Message):
    logger.info(f"Пользователь {message.from_user.id} запустил бота.")
    await send_main_menu(message.bot, message.chat.id)


async def send_main_menu(bot: Bot, chat_id: int):
    logger.info(f"Пользователь {chat_id} вернулся в главное меню.")
    keyboard = InlineKeyboardBuilder()
    keyboard.button(text="💰 Проверить баланс", callback_data="check_balance")
    keyboard.button(text="📲 Получить SMS", callback_data="get_sms")
    keyboard.button(text="📋 Текущие активации", callback_data="current_activations")
    keyboard.button(text="⚙️ Настройки", callback_data="settings")
    keyboard.adjust(1)

    await bot.send_message(
        chat_id=chat_id,
        text="Добро пожаловать! Выберите действие:",
        reply_markup=keyboard.as_markup()
    )


async def show_settings_menu(bot: Bot, chat_id: int, state: FSMContext, user_id: int):
    user_api_key = await get_user_api_key(user_id)
    keyboard = InlineKeyboardBuilder()

    if user_api_key:
        keyboard.button(text="✏️ Изменить API ключ", callback_data="edit_api_key")
        keyboard.button(text="❌ Удалить API ключ", callback_data="delete_api_key")
    else:
        keyboard.button(text="➕ Добавить API ключ", callback_data="add_api_key")

    keyboard.button(text="🔙 Назад", callback_data="back_to_main_menu")
    keyboard.adjust(1)

    message_text = (
        f"Ваш текущий API ключ: `{user_api_key}`" if user_api_key else "API ключ не настроен."
    )

    await bot.send_message(
        chat_id=chat_id,
        text=message_text,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )
    await state.clear()


@router.callback_query(F.data == "settings")
async def settings_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await callback_query.answer()
    await show_settings_menu(callback_query.message.bot, callback_query.from_user.id, state, callback_query.from_user.id)


@router.callback_query(F.data.in_({"edit_api_key", "add_api_key"}))
async def input_api_key_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await callback_query.answer()
    keyboard = InlineKeyboardBuilder()
    keyboard.button(text="❌ Отмена", callback_data="cancel_settings")
    keyboard.adjust(1)

    await callback_query.message.answer(
        "Введите ваш API ключ для работы с сервисом:",
        reply_markup=keyboard.as_markup()
    )
    await state.set_state(UserSettings.entering_api_key)


@router.callback_query(F.data == "delete_api_key")
async def delete_api_key_handler(callback_query: types.CallbackQuery):
    await callback_query.answer()
    keyboard = InlineKeyboardBuilder()
    keyboard.button(text="✅ Да", callback_data="confirm_delete_api_key:yes")
    keyboard.button(text="❌ Нет", callback_data="confirm_delete_api_key:no")
    keyboard.adjust(2)

    await callback_query.message.answer(
        "Вы уверены, что хотите удалить ваш API ключ?",
        reply_markup=keyboard.as_markup()
    )


@router.callback_query(F.data.startswith("confirm_delete_api_key"))
async def confirm_delete_api_key_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await callback_query.answer()
    choice = callback_query.data.split(":")[1]
    if choice == "yes":
        await delete_user_api_key(callback_query.from_user.id)
        await callback_query.message.answer(
            "API ключ успешно удалён."
        )
        await send_main_menu(callback_query.message.bot, callback_query.from_user.id)
    else:
        # Возвращаемся в настройки
        await show_settings_menu(callback_query.message.bot, callback_query.from_user.id, state, callback_query.from_user.id)


@router.callback_query(F.data == "back_to_main_menu")
async def back_to_main_menu_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await callback_query.answer()
    await state.clear()
    await send_main_menu(callback_query.message.bot, callback_query.from_user.id)


@router.callback_query(F.data == "cancel_settings")
async def cancel_settings_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await callback_query.answer()
    await state.clear()
    # Возвращаем пользователя в меню настроек
    await show_settings_menu(callback_query.message.bot, callback_query.from_user.id, state, callback_query.from_user.id)


@router.message(UserSettings.entering_api_key)
async def set_user_api_key_handler(message: types.Message, state: FSMContext):
    user_api_key = message.text.strip()
    logger.info(f"Пользователь {message.from_user.id} ввёл API ключ.")
    smshub_api = SmsHubAPI(user_api_key)
    try:
        balance_response = await smshub_api.get_balance()
        if balance_response and balance_response.startswith("ACCESS_BALANCE:"):
            balance = balance_response.split(":")[1]
            balance_usd = float(balance)
            usd_to_rub_rate = await get_usd_to_rub_rate()
            balance_rub = balance_usd * usd_to_rub_rate if usd_to_rub_rate else "недоступно"

            await set_user_api_key(message.from_user.id, user_api_key)

            # Проверяем, что ключ действительно сохранен
            saved_api_key = await get_user_api_key(message.from_user.id)
            if saved_api_key == user_api_key:
                await message.answer(
                    f"Ваш API ключ успешно сохранён и проверен!\nБаланс: ${balance_usd:.4f} (приблизительно ₽{balance_rub:.2f})"
                )
            else:
                await message.answer("Произошла ошибка при сохранении API ключа. Пожалуйста, попробуйте снова.")
                return

            await state.clear()
            # Остаемся в меню настроек
            await show_settings_menu(message.bot, message.from_user.id, state, message.from_user.id)
        else:
            keyboard = InlineKeyboardBuilder()
            keyboard.button(text="❌ Отмена", callback_data="cancel_settings")
            keyboard.adjust(1)
            await message.answer(
                "Неверный API ключ. Пожалуйста, попробуйте снова или отмените операцию.",
                reply_markup=keyboard.as_markup()
            )
    except Exception as e:
        logger.error(f"Ошибка при проверке API ключа: {e}")
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="❌ Отмена", callback_data="cancel_settings")
        keyboard.adjust(1)
        await message.answer(
            "Произошла ошибка при проверке ключа. Пожалуйста, попробуйте снова.",
            reply_markup=keyboard.as_markup()
        )


@router.callback_query(F.data == "check_balance")
async def balance_handler(callback_query: types.CallbackQuery):
    await callback_query.answer()
    user_api_key = await get_user_api_key(callback_query.from_user.id)
    if not user_api_key:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="⚙️ Настройки", callback_data="settings")
        keyboard.button(text="🔙 Назад", callback_data="back_to_main_menu")
        keyboard.adjust(1)

        await callback_query.message.answer(
            "Пожалуйста, сначала настройте ваш API ключ в разделе 'Настройки'.",
            reply_markup=keyboard.as_markup()
        )
        return

    smshub_api = SmsHubAPI(user_api_key)
    logger.info(f"Пользователь {callback_query.from_user.id} запросил баланс.")

    balance_response = await smshub_api.get_balance()
    usd_to_rub_rate = await get_usd_to_rub_rate()

    if balance_response and balance_response.startswith("ACCESS_BALANCE:"):
        balance_usd = float(balance_response.split(":")[1])
        balance_rub = balance_usd * usd_to_rub_rate if usd_to_rub_rate else "недоступно"
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        message_text = (
            f"Ваш баланс: ${balance_usd:.4f} (приблизительно ₽{balance_rub:.2f}) на {current_time}"
        )
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="🔄 Обновить баланс", callback_data="check_balance")
        keyboard.button(text="🔙 Вернуться в меню", callback_data="back_to_main_menu")
        keyboard.adjust(1)
        await callback_query.message.answer(
            message_text,
            reply_markup=keyboard.as_markup()
        )
    else:
        logger.error(f"Не удалось получить баланс. Ответ: {balance_response}")
        await callback_query.message.answer(
            "Не удалось получить баланс. Попробуйте снова.",
            reply_markup=callback_query.message.reply_markup
        )


@router.callback_query(F.data == "get_sms")
async def get_sms_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await callback_query.answer()
    user_api_key = await get_user_api_key(callback_query.from_user.id)
    if not user_api_key:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="⚙️ Настройки", callback_data="settings")
        keyboard.button(text="🔙 Назад", callback_data="back_to_main_menu")
        keyboard.adjust(1)

        await callback_query.message.answer(
            "Пожалуйста, сначала настройте ваш API ключ в разделе 'Настройки'.",
            reply_markup=keyboard.as_markup()
        )
        return

    logger.info(f"Пользователь {callback_query.from_user.id} начал процесс получения номера.")
    keyboard = InlineKeyboardBuilder()
    keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
    keyboard.button(text="📋 Сервисы", url="https://teletype.in/@diagzone/NQd96Y8cPQe")
    keyboard.adjust(2)

    await callback_query.message.answer(
        "Введите сервис для получения номера (например, wa для WhatsApp):",
        reply_markup=keyboard.as_markup()
    )
    await state.set_state(SmsOrderState.waiting_for_service)


@router.callback_query(F.data == "cancel_operation")
async def cancel_operation_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await callback_query.answer()
    logger.info(f"Пользователь {callback_query.from_user.id} отменил операцию.")
    await state.clear()
    await send_main_menu(callback_query.message.bot, callback_query.from_user.id)


@router.message(SmsOrderState.waiting_for_service)
async def service_handler(message: types.Message, state: FSMContext):
    service = message.text.strip().lower()
    logger.info(f"Пользователь {message.from_user.id} выбрал сервис: {service}")

    user_api_key = await get_user_api_key(message.from_user.id)
    smshub_api = SmsHubAPI(user_api_key)
    country_code = "0"
    usd_to_rub_rate = await get_usd_to_rub_rate()

    try:
        price_info = await smshub_api.get_price_for_service(service, country=country_code)
        if not price_info:
            await message.answer("Сервис недоступен или введён неверно. Пожалуйста, попробуйте снова.")
            await state.clear()
            await send_main_menu(message.bot, message.from_user.id)
            return

        prices = [float(price) for price in price_info.keys()]
        min_price_usd = min(prices)
        max_price_usd = max(prices)
        min_price_rub = min_price_usd * usd_to_rub_rate if usd_to_rub_rate else 0
        max_price_rub = max_price_usd * usd_to_rub_rate if usd_to_rub_rate else 0

        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
        keyboard.adjust(1)

        await message.answer(
            f"Текущие цены для сервиса {service}: от ${min_price_usd:.4f} (₽{min_price_rub:.2f}) "
            f"до ${max_price_usd:.4f} (₽{max_price_rub:.2f}). Введите максимальную стоимость в $ "
            f"(например, 10):",
            reply_markup=keyboard.as_markup()
        )
        await state.update_data(service=service, min_price=min_price_usd)
        await state.set_state(SmsOrderState.waiting_for_max_price)
    except Exception as e:
        logger.error(f"Ошибка при получении цен для сервиса '{service}': {e}")
        await message.answer("Произошла ошибка при получении цен. Попробуйте снова.")
        await state.clear()
        await send_main_menu(message.bot, message.from_user.id)


@router.message(SmsOrderState.waiting_for_max_price)
async def max_price_handler(message: types.Message, state: FSMContext):
    max_price_input = message.text.strip()
    logger.info(f"Пользователь {message.from_user.id} указал максимальную стоимость: {max_price_input}")

    try:
        max_price = float(max_price_input)
    except ValueError:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
        keyboard.adjust(1)
        await message.answer(
            "Пожалуйста, введите корректное число для максимальной стоимости.",
            reply_markup=keyboard.as_markup()
        )
        return

    user_data = await state.get_data()
    service = user_data['service']
    min_price = user_data['min_price']
    user_api_key = await get_user_api_key(message.from_user.id)
    smshub_api = SmsHubAPI(user_api_key)
    country_code = "0"

    if max_price < min_price:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
        keyboard.adjust(1)
        await message.answer(
            f"Максимальная стоимость должна быть не менее {min_price:.4f} $.",
            reply_markup=keyboard.as_markup()
        )
        return

    result = await smshub_api.get_number(service, country=country_code, max_price=max_price)
    if result and result.startswith("ACCESS_NUMBER"):
        _, activation_id, number = result.split(":")
        logger.info(f"Пользователь {message.from_user.id} получил номер: {number}, активация ID: {activation_id}")

        if message.from_user.id not in user_activations:
            user_activations[message.from_user.id] = {}
        user_activations[message.from_user.id][activation_id] = {
            'number': number,
            'service': service,
            'status': 'Ожидание SMS',
            'task': None,
            'last_update': time.time()
        }

        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="📋 Управлять активацией", callback_data=f"manage_activation:{activation_id}")
        keyboard.button(text="🔙 Главное меню", callback_data="back_to_main_menu")
        keyboard.adjust(1)

        await message.answer(
            f"Получен номер: `{number}`. Ожидание SMS...\nВы можете управлять активацией или вернуться в главное меню.",
            reply_markup=keyboard.as_markup(),
            parse_mode="Markdown"
        )
        await state.clear()

        task = asyncio.create_task(poll_for_sms(
            bot=message.bot,
            user_id=message.from_user.id,
            chat_id=message.chat.id,
            activation_id=activation_id,
            smshub_api=smshub_api
        ))
        user_activations[message.from_user.id][activation_id]['task'] = task
    else:
        logger.error(f"Не удалось получить номер. Ответ: {result}")
        await message.answer("Не удалось получить номер. Попробуйте снова.")
        await state.clear()
        await send_main_menu(message.bot, message.from_user.id)


@router.callback_query(F.data == "current_activations")
async def current_activations_handler(callback_query: types.CallbackQuery):
    await callback_query.answer()
    user_id = callback_query.from_user.id
    activations = user_activations.get(user_id, {})
    if not activations:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="🔙 Назад", callback_data="back_to_main_menu")
        keyboard.adjust(1)
        await callback_query.message.answer(
            "У вас нет активных активаций.",
            reply_markup=keyboard.as_markup()
        )
        return

    keyboard = InlineKeyboardBuilder()
    for activation_id, data in activations.items():
        keyboard.button(
            text=f"{data['service']} ({data['number']}) - {data['status']}",
            callback_data=f"manage_activation:{activation_id}"
        )
    keyboard.button(text="🔙 Назад", callback_data="back_to_main_menu")
    keyboard.adjust(1)
    await callback_query.message.answer(
        "Ваши текущие активации:",
        reply_markup=keyboard.as_markup()
    )


@router.callback_query(F.data.startswith("manage_activation"))
async def manage_activation_handler(callback_query: types.CallbackQuery):
    await callback_query.answer()
    user_id = callback_query.from_user.id
    activation_id = callback_query.data.split(":")[1]
    activations = user_activations.get(user_id, {})
    activation = activations.get(activation_id)

    if not activation:
        await callback_query.message.answer(
            "Активация не найдена.",
            reply_markup=callback_query.message.reply_markup
        )
        return

    keyboard = InlineKeyboardBuilder()

    # Формируем клавиатуру в зависимости от статуса активации
    if activation['status'] == 'Ожидание SMS':
        # Только отменить активацию
        keyboard.button(text="❌ Отменить активацию", callback_data=f"cancel_activation:{activation_id}")
    elif activation['status'].startswith('Код получен'):
        # Запросить еще SMS или завершить активацию
        keyboard.button(text="🔄 Запросить еще SMS", callback_data=f"request_another_sms:{activation_id}")
        keyboard.button(text="✅ Завершить активацию", callback_data=f"complete_activation:{activation_id}")
    elif activation['status'].startswith('Ожидание повторного SMS'):
        # Завершить или отменить активацию
        keyboard.button(text="✅ Завершить активацию", callback_data=f"complete_activation:{activation_id}")
        keyboard.button(text="❌ Отменить активацию", callback_data=f"cancel_activation:{activation_id}")
    else:
        # Другие статусы
        keyboard.button(text="✅ Завершить активацию", callback_data=f"complete_activation:{activation_id}")
        keyboard.button(text="❌ Отменить активацию", callback_data=f"cancel_activation:{activation_id}")

    keyboard.button(text="🔙 Назад", callback_data="current_activations")
    keyboard.adjust(1)

    await callback_query.message.answer(
        f"Активация {activation_id}:\nСервис: {activation['service']}\nНомер: `{activation['number']}`\nСтатус: {activation['status']}",
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )


@router.callback_query(F.data.startswith("cancel_activation"))
async def cancel_activation_handler(callback_query: types.CallbackQuery):
    await callback_query.answer()
    user_id = callback_query.from_user.id
    activation_id = callback_query.data.split(":")[1]
    user_api_key = await get_user_api_key(user_id)
    smshub_api = SmsHubAPI(user_api_key)

    activations = user_activations.get(user_id, {})
    activation = activations.get(activation_id)

    if activation:
        # Отменяем задачу, если она есть
        task = activation.get('task')
        if task:
            task.cancel()

        # Отменяем активацию на стороне API
        result = await smshub_api.cancel_activation(activation_id)
        logger.info(f"Активация {activation_id} отменена на стороне API: {result}")

        # Удаляем активацию из списка
        del activations[activation_id]

        # Создаём новую клавиатуру с кнопкой "🔙 Назад"
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="🔙 Назад", callback_data="current_activations")
        keyboard.adjust(1)

        await callback_query.message.answer(
            "Активация успешно отменена.",
            reply_markup=keyboard.as_markup()
        )
    else:
        await callback_query.message.answer(
            "Активация не найдена.",
            reply_markup=callback_query.message.reply_markup
        )


@router.callback_query(F.data.startswith("request_another_sms"))
async def request_another_sms_handler(callback_query: types.CallbackQuery):
    await callback_query.answer()
    user_id = callback_query.from_user.id
    activation_id = callback_query.data.split(":")[1]
    user_api_key = await get_user_api_key(user_id)
    smshub_api = SmsHubAPI(user_api_key)
    activations = user_activations.get(user_id, {})
    activation = activations.get(activation_id)

    if not activation:
        await callback_query.message.answer(
            "Активация не найдена.",
            reply_markup=callback_query.message.reply_markup
        )
        return

    result = await smshub_api.set_status(activation_id, status="3")
    if result == "ACCESS_RETRY_GET":
        # Отменяем предыдущую задачу, если она есть
        task = activation.get('task')
        if task:
            task.cancel()

        # Запускаем новую задачу
        task = asyncio.create_task(poll_for_sms(
            bot=callback_query.message.bot,
            user_id=user_id,
            chat_id=callback_query.from_user.id,
            activation_id=activation_id,
            smshub_api=smshub_api
        ))
        activation['task'] = task
        activation['status'] = 'Ожидание повторного SMS'

        await callback_query.message.answer(
            "Запрошен повторный SMS. Ожидание SMS...",
            reply_markup=callback_query.message.reply_markup
        )
    else:
        logger.error(f"Не удалось запросить повторное SMS. Ответ: {result}")
        await callback_query.message.answer(
            "Не удалось запросить повторный SMS. Попробуйте снова.",
            reply_markup=callback_query.message.reply_markup
        )


@router.callback_query(F.data.startswith("complete_activation"))
async def complete_activation_handler(callback_query: types.CallbackQuery):
    await callback_query.answer()
    user_id = callback_query.from_user.id
    activation_id = callback_query.data.split(":")[1]
    user_api_key = await get_user_api_key(user_id)
    smshub_api = SmsHubAPI(user_api_key)
    activations = user_activations.get(user_id, {})
    activation = activations.get(activation_id)

    if not activation:
        await callback_query.message.answer(
            "Активация не найдена.",
            reply_markup=callback_query.message.reply_markup
        )
        return

    result = await smshub_api.set_status(activation_id, status="6")
    if result == "ACCESS_ACTIVATION":
        # Отменяем задачу, если она есть
        task = activation.get('task')
        if task:
            task.cancel()

        # Удаляем активацию из списка
        del activations[activation_id]

        # Создаём новую клавиатуру с кнопкой "🔙 Назад"
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="🔙 Назад", callback_data="current_activations")
        keyboard.adjust(1)

        await callback_query.message.answer(
            "Активация успешно завершена.",
            reply_markup=keyboard.as_markup()
        )
    else:
        logger.error(f"Не удалось завершить активацию. Ответ: {result}")
        await callback_query.message.answer(
            "Не удалось завершить активацию. Попробуйте снова.",
            reply_markup=callback_query.message.reply_markup
        )


async def poll_for_sms(bot: Bot, user_id: int, chat_id: int, activation_id: str, smshub_api: SmsHubAPI):
    activations = user_activations.get(user_id, {})
    activation = activations.get(activation_id)

    if not activation:
        logger.error(f"Активация {activation_id} не найдена для пользователя {user_id}.")
        return

    try:
        max_wait_time = 300  # Максимальное время ожидания в секундах
        poll_interval = 3     # Интервал опроса в секундах
        elapsed_time = 0

        while elapsed_time < max_wait_time:
            await asyncio.sleep(poll_interval)
            elapsed_time += poll_interval

            status_response = await smshub_api.get_status(activation_id)
            if not status_response:
                logger.error("Нет ответа при запросе статуса активации.")
                await bot.send_message(chat_id, "Не удалось получить статус активации. Попробуйте позже.")
                return

            status_parts = status_response.split(":", 1)
            status = status_parts[0]

            if status == "STATUS_WAIT_CODE":
                logger.debug(f"Ожидание SMS кода для активации {activation_id}.")
                activation['last_update'] = time.time()
                continue
            elif status.startswith("STATUS_WAIT_RETRY"):
                last_code = status_parts[1] if len(status_parts) > 1 else "нет предыдущего кода"
                logger.info(f"Ожидание повторного SMS кода, последний код: {last_code}")
                activation['status'] = f'Ожидание повторного SMS (последний код: {last_code})'
                activation['last_update'] = time.time()
                continue
            elif status == "STATUS_CANCEL":
                await bot.send_message(chat_id, "Активация была отменена.")
                activation['status'] = 'Активация отменена'
                return
            elif status == "STATUS_OK":
                code = status_parts[1] if len(status_parts) > 1 else "Код не получен"
                logger.info(f"Получен код активации для {activation_id}: {code}")
                activation['status'] = f'Код получен: {code}'
                activation['last_update'] = time.time()

                await bot.send_message(
                    chat_id,
                    f"Код активации для номера `{activation['number']}`: `{code}`",
                    parse_mode="Markdown"
                )
                return
            else:
                logger.error(f"Непредвиденный статус активации: {status_response}")
                activation['status'] = f'Неизвестный статус: {status}'
                await bot.send_message(chat_id, f"Неизвестный статус активации: {status}")
                return
        # Если время ожидания истекло, функция завершается без изменения статуса активации
    except asyncio.CancelledError:
        logger.info(f"Задача poll_for_sms для активации {activation_id} была отменена.")
    except Exception as e:
        logger.error(f"Ошибка в poll_for_sms: {e}")
        activation['status'] = 'Ошибка при получении SMS'
        await bot.send_message(chat_id, "Произошла ошибка при получении SMS.")


# Фоновая задача для периодической проверки статусов активаций
async def check_activations_status():
    while True:
        await asyncio.sleep(300)  # Проверяем каждые 5 минут
        logger.info("Проверка статусов активных активаций...")
        for user_id, activations in user_activations.copy().items():
            for activation_id, activation in activations.copy().items():
                try:
                    user_api_key = await get_user_api_key(user_id)
                    if not user_api_key:
                        continue
                    smshub_api = SmsHubAPI(user_api_key)
                    status_response = await smshub_api.get_status(activation_id)
                    if not status_response:
                        continue

                    status_parts = status_response.split(":", 1)
                    status = status_parts[0]

                    if status == "STATUS_CANCEL":
                        # Удаляем активацию
                        logger.info(f"Активация {activation_id} была отменена на стороне сервиса.")
                        task = activation.get('task')
                        if task:
                            task.cancel()
                        del activations[activation_id]
                    elif activation['status'].startswith("Код получен"):
                        # Проверяем, прошло ли достаточно времени
                        elapsed_since_update = time.time() - activation.get('last_update', 0)
                        if elapsed_since_update > 1800:  # 30 минут
                            logger.info(f"Активация {activation_id} завершена по истечении времени.")
                            task = activation.get('task')
                            if task:
                                task.cancel()
                            del activations[activation_id]
                except Exception as e:
                    logger.error(f"Ошибка при проверке активации {activation_id}: {e}")


# Функция для запуска фоновых задач при старте бота
async def on_startup(dispatcher: Dispatcher):
    asyncio.create_task(check_activations_status())


# Добавляем глобальный обработчик ошибок
@router.errors()
async def errors_handler(update: types.Update, exception):
    logger.exception(f"Exception in update handler: {exception}")
    return True


# Убираем bot = Bot(token='ВАШ_ТОКЕН_БОТА'), как вы и просили
# Предполагается, что инициализация бота и диспетчера осуществляется в другом месте вашего проекта


так, смотри. в  этом коде у меня все отлично за исключением сообщения о подтверждении удаления ключа апи из настроек.  если я нажимаю удалить ключ и далее жму "да" в следующем окне, то у меня все зависает, ошибок в логах нет. либо исправь это как-то и пришли мне готовый исправленный код, либо вообще убери подтвержление на удаление ключа, в обещм сделай так, как будет правильннее и рабочее чтобы было решение