from aiogram import F, Router
from aiogram.filters import CommandObject, CommandStart
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import (
    CallbackQuery,
    InlineKeyboardButton,
    InlineKeyboardMarkup,
    Message,
)

from .api import (
    PlatformaAPIError,
    get_telegram_status,
    leave_support_chat,
    link_telegram,
    send_ai_message,
    update_notification_settings,
)
from .config import BotSettings

router = Router(name='platforma')


class LinkTelegram(StatesGroup):
    waiting_for_code = State()


class AIChat(StatesGroup):
    active = State()


NOTIFICATION_LABELS = {
    'lesson_reminders': 'Напоминания об уроках',
    'tips_and_recommendations': 'Советы и рекомендации',
    'news_and_updates': 'Новости и обновления',
    'special_offers': 'Акции и специальные предложения',
}


def menu_button():
    return InlineKeyboardButton(text='Меню', callback_data='main_menu')


def welcome_keyboard():
    return InlineKeyboardMarkup(
        inline_keyboard=[
            [
                InlineKeyboardButton(
                    text='Привязать Telegram',
                    callback_data='link_telegram',
                )
            ],
        ]
    )


def cancel_keyboard():
    return InlineKeyboardMarkup(
        inline_keyboard=[
            [InlineKeyboardButton(text='Отмена', callback_data='cancel_link')],
        ]
    )


def menu_keyboard():
    return InlineKeyboardMarkup(inline_keyboard=[[menu_button()]])


def main_menu_keyboard():
    return InlineKeyboardMarkup(
        inline_keyboard=[
            [InlineKeyboardButton(text='ИИ-ассистент', callback_data='ai_assistant')],
            [InlineKeyboardButton(text='Уведомления', callback_data='notifications')],
        ]
    )


def notifications_keyboard(settings):
    rows = []
    for field, label in NOTIFICATION_LABELS.items():
        enabled = bool(settings.get(field, False))
        action = 'Выключить' if enabled else 'Включить'
        rows.append([
            InlineKeyboardButton(
                text=f'{action}: {label}',
                callback_data=f'notification:{field}:{int(not enabled)}',
            )
        ])
    rows.append([InlineKeyboardButton(text='Назад', callback_data='main_menu')])
    return InlineKeyboardMarkup(inline_keyboard=rows)


def leave_chat_keyboard():
    return InlineKeyboardMarkup(
        inline_keyboard=[
            [InlineKeyboardButton(text='Покинуть чат', callback_data='leave_ai_chat')]
        ]
    )


async def edit_menu_message(message: Message, text: str, reply_markup):
    if message.photo:
        await message.edit_caption(caption=text, reply_markup=reply_markup)
    else:
        await message.edit_text(text=text, reply_markup=reply_markup)


async def send_welcome(
    message: Message,
    bot_settings: BotSettings,
    telegram_user_id: int | None = None,
):
    try:
        status = await get_telegram_status(
            bot_settings,
            telegram_user_id=telegram_user_id or message.from_user.id,
        )
    except Exception:
        status = {'linked': False}
    if status['linked']:
        await message.answer(
            f'Привет, {status["display_name"]}! Telegram уже привязан к вашему '
            'профилю RWL.',
            reply_markup=menu_keyboard(),
        )
        return
    await message.answer(
        'Привет! Я бот RWL для изучения юридического английского. '
        'Я помогу получать напоминания, советы и новости об обучении.',
        reply_markup=welcome_keyboard(),
    )


@router.message(CommandStart())
async def start(
    message: Message,
    state: FSMContext,
    bot_settings: BotSettings,
    command: CommandObject,
) -> None:
    await state.clear()
    code = (command.args or '').strip().upper()
    if code:
        if len(code) != 8 or not code.isalnum():
            await message.answer(
                'Ссылка для привязки некорректна или повреждена. '
                'Откройте профиль RWL и нажмите «Привязать Telegram» ещё раз.',
                reply_markup=welcome_keyboard(),
            )
            return
        try:
            status = await get_telegram_status(
                bot_settings,
                telegram_user_id=message.from_user.id,
            )
            if status['linked']:
                await send_welcome(message, bot_settings)
                return
            result = await link_telegram(
                bot_settings,
                code=code,
                telegram_user_id=message.from_user.id,
                telegram_username=message.from_user.username or '',
            )
        except PlatformaAPIError as error:
            await message.answer(
                f'{error} Откройте профиль RWL и создайте новую ссылку.',
                reply_markup=welcome_keyboard(),
            )
            return
        except Exception:
            await message.answer(
                'Не удалось связаться с RWL. Попробуйте открыть ссылку ещё раз позже.',
                reply_markup=welcome_keyboard(),
            )
            return
        await message.answer(
            f'Готово, {result["display_name"]}! Telegram автоматически привязан '
            'к профилю RWL.',
            reply_markup=menu_keyboard(),
        )
        return
    await send_welcome(message, bot_settings)


@router.callback_query(F.data == 'link_telegram')
async def start_linking(
    callback: CallbackQuery,
    state: FSMContext,
    bot_settings: BotSettings,
) -> None:
    try:
        status = await get_telegram_status(
            bot_settings,
            telegram_user_id=callback.from_user.id,
        )
    except Exception:
        status = {'linked': False}
    if status['linked']:
        await state.clear()
        await callback.answer('Telegram уже привязан')
        await callback.message.answer(
            f'{status["display_name"]}, Telegram уже привязан к профилю RWL.',
            reply_markup=menu_keyboard(),
        )
        return
    await state.set_state(LinkTelegram.waiting_for_code)
    await callback.answer()
    await callback.message.answer(
        'Введите одноразовый код из блока «Уведомления» в профиле RWL. '
        'Код действует 10 минут.',
        reply_markup=cancel_keyboard(),
    )


@router.callback_query(F.data == 'cancel_link')
async def cancel_linking(
    callback: CallbackQuery,
    state: FSMContext,
    bot_settings: BotSettings,
) -> None:
    await state.clear()
    await callback.answer('Привязка отменена')
    await callback.message.answer(
        'Привязка Telegram отменена.',
        reply_markup=welcome_keyboard(),
    )
    await send_welcome(
        callback.message,
        bot_settings,
        telegram_user_id=callback.from_user.id,
    )


@router.message(LinkTelegram.waiting_for_code)
async def receive_link_code(
    message: Message,
    state: FSMContext,
    bot_settings: BotSettings,
) -> None:
    code = (message.text or '').strip().upper()
    if len(code) != 8 or not code.isalnum():
        await message.answer(
            'Код должен состоять из 8 букв и цифр. Проверьте код и попробуйте ещё раз.',
            reply_markup=cancel_keyboard(),
        )
        return
    try:
        result = await link_telegram(
            bot_settings,
            code=code,
            telegram_user_id=message.from_user.id,
            telegram_username=message.from_user.username or '',
        )
    except PlatformaAPIError as error:
        await message.answer(str(error), reply_markup=cancel_keyboard())
        return
    except Exception:
        await message.answer(
            'Не удалось связаться с RWL. Попробуйте ещё раз позже.',
            reply_markup=cancel_keyboard(),
        )
        return

    await state.clear()
    await message.answer(
        f'Готово, {result["display_name"]}! Telegram успешно привязан к профилю. '
        'Сейчас все четыре настройки уведомлений выключены. '
        'Включить нужные уведомления можно в меню бота или профиле RWL.',
        reply_markup=menu_keyboard(),
    )


@router.callback_query(F.data == 'main_menu')
async def show_main_menu(
    callback: CallbackQuery,
    state: FSMContext,
    bot_settings: BotSettings,
) -> None:
    await state.clear()
    try:
        status = await get_telegram_status(
            bot_settings,
            telegram_user_id=callback.from_user.id,
        )
    except Exception:
        await callback.answer('Не удалось загрузить меню', show_alert=True)
        return
    if not status['linked']:
        await callback.answer('Сначала привяжите Telegram', show_alert=True)
        return
    await callback.answer()
    await edit_menu_message(
        callback.message,
        'Главное меню RWL. Выберите нужный раздел.',
        main_menu_keyboard(),
    )


@router.callback_query(F.data == 'notifications')
async def show_notifications(
    callback: CallbackQuery,
    bot_settings: BotSettings,
) -> None:
    try:
        status = await get_telegram_status(
            bot_settings,
            telegram_user_id=callback.from_user.id,
        )
    except Exception:
        await callback.answer('Не удалось загрузить настройки', show_alert=True)
        return
    if not status['linked']:
        await callback.answer('Сначала привяжите Telegram', show_alert=True)
        return
    await callback.answer()
    await edit_menu_message(
        callback.message,
        'Здесь вы можете настроить уведомления RWL. Нажмите на нужный пункт, '
        'чтобы включить или выключить его.',
        notifications_keyboard(status.get('settings') or {}),
    )


@router.callback_query(F.data.startswith('notification:'))
async def toggle_notification(
    callback: CallbackQuery,
    bot_settings: BotSettings,
) -> None:
    try:
        _, field, raw_enabled = callback.data.split(':', 2)
        if field not in NOTIFICATION_LABELS or raw_enabled not in ('0', '1'):
            raise ValueError
    except ValueError:
        await callback.answer('Некорректная настройка', show_alert=True)
        return
    try:
        result = await update_notification_settings(
            bot_settings,
            telegram_user_id=callback.from_user.id,
            field=field,
            enabled=raw_enabled == '1',
        )
    except PlatformaAPIError as error:
        await callback.answer(str(error), show_alert=True)
        return
    except Exception:
        await callback.answer('Не удалось сохранить настройку', show_alert=True)
        return
    await callback.answer('Настройка сохранена')
    await edit_menu_message(
        callback.message,
        'Здесь вы можете настроить уведомления RWL. Нажмите на нужный пункт, '
        'чтобы включить или выключить его.',
        notifications_keyboard(result.get('settings') or {}),
    )


@router.callback_query(F.data == 'ai_assistant')
async def enter_ai_chat(
    callback: CallbackQuery,
    state: FSMContext,
    bot_settings: BotSettings,
) -> None:
    try:
        telegram_status = await get_telegram_status(
            bot_settings,
            telegram_user_id=callback.from_user.id,
        )
    except Exception:
        await callback.answer()
        await callback.message.answer(
            'Не удалось связаться с RWL. Попробуйте ещё раз позже.',
            reply_markup=welcome_keyboard(),
        )
        return
    if not telegram_status['linked']:
        await callback.answer()
        await callback.message.answer(
            'Чтобы пользоваться ИИ-ассистентом, сначала привяжите Telegram к профилю RWL.',
            reply_markup=welcome_keyboard(),
        )
        return
    await state.set_state(AIChat.active)
    await callback.answer('Чат с ИИ открыт')
    await edit_menu_message(
        callback.message,
        'Вы в чате с ИИ-ассистентом RWL. Задайте вопрос о платформе или обучении.',
        leave_chat_keyboard(),
    )


@router.callback_query(F.data == 'leave_ai_chat')
async def leave_ai_chat(
    callback: CallbackQuery,
    state: FSMContext,
) -> None:
    await state.clear()
    await callback.answer('Чат закрыт')
    await edit_menu_message(
        callback.message,
        'Главное меню RWL. Выберите нужный раздел.',
        main_menu_keyboard(),
    )


@router.callback_query(F.data == 'leave_support_chat')
async def leave_admin_chat(
    callback: CallbackQuery,
    state: FSMContext,
    bot_settings: BotSettings,
) -> None:
    try:
        await leave_support_chat(
            bot_settings,
            telegram_user_id=callback.from_user.id,
        )
    except PlatformaAPIError as error:
        await callback.answer(str(error), show_alert=True)
        return
    except Exception:
        await callback.answer('Не удалось завершить чат', show_alert=True)
        return
    await state.clear()
    await callback.answer('Общение с поддержкой завершено')
    await edit_menu_message(
        callback.message,
        'Главное меню RWL. Выберите нужный раздел.',
        main_menu_keyboard(),
    )


@router.message(AIChat.active)
async def receive_ai_message(
    message: Message,
    bot_settings: BotSettings,
) -> None:
    text = (message.text or '').strip()
    if not text:
        await message.answer(
            'Отправьте вопрос текстовым сообщением.',
            reply_markup=leave_chat_keyboard(),
        )
        return
    await message.bot.send_chat_action(message.chat.id, 'typing')
    try:
        result = await send_ai_message(
            bot_settings,
            telegram_user_id=message.from_user.id,
            message=text,
        )
    except PlatformaAPIError as error:
        await message.answer(str(error), reply_markup=leave_chat_keyboard())
        return
    except Exception:
        await message.answer(
            'Не удалось связаться с ИИ-ассистентом. Попробуйте ещё раз позже.',
            reply_markup=leave_chat_keyboard(),
        )
        return

    answer = (result.get('answer') or '').strip()
    if not answer:
        answer = result.get('detail') or 'Сообщение отправлено специалисту поддержки.'
    chunks = [answer[index:index + 4000] for index in range(0, len(answer), 4000)]
    for chunk in chunks:
        await message.answer(
            chunk,
            reply_markup=leave_chat_keyboard(),
        )


@router.message()
async def greet_on_any_message(
    message: Message,
    state: FSMContext,
    bot_settings: BotSettings,
) -> None:
    await state.clear()
    await send_welcome(message, bot_settings)
