import os
from states.user import UserState
from utils.db import (add_subscription, add_subscription_links, create_order, create_payment, extend_subscription, get_or_create_user,
                       get_payment, get_plan, get_subscription, update_payment_status, set_invoice_id,
                       add_balance)
from aiogram import Router
from aiogram.filters import CommandStart, CommandObject
from aiogram.types import Message, CallbackQuery
from aiogram.utils.deep_linking import decode_payload
from aiogram.fsm.context import FSMContext
from aiogram import F
from keyboards.user import (get_main_menu_keyboard, get_buy_vpn_keyboard, get_payment_keyboard, get_providers_keyboard, 
                            get_my_subscriptions_keyboard, get_subscription_keyboard, get_countries_keyboard, get_profile_keyboard,
                            back_keyboard, get_confirm_buy_keyboard)
from keyboards.user_buttons import *
from utils.texts import get_subscription_info, profile_info, referal_info
from vpns.marz import marzban_service
from utils.media_cache import get_cached_media, update_file_id_cache
from utils.pay_providers import providers
import logging

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

@router.message(CommandStart())
async def cmd_start(message: Message, state: FSMContext, command: CommandObject):
    # Get ref_id from deep link if it exists
    args = command.args
    ref_id = None
    if args:
        ref_id = decode_payload(args)
    # Create or get user (already cached in db utils)
    await get_or_create_user(message.from_user, ref_id)

    # Send welcome message
    photo_path = "./media/ГлавноеМеню.png"
    photo = get_cached_media(photo_path)

    welcome_text = (
        f"👋 <b>Добро пожаловать в {os.getenv('name_service')}!</b>"+"\n\n"
        "🔐 <i>Безопасный и быстрый VPN сервис</i>\n"
        "⚡️ <i>Высокая скорость соединения</i>"
    )
    if photo:
        sent_msg = await message.answer_photo(photo, welcome_text, reply_markup=get_main_menu_keyboard(), parse_mode="HTML")
        update_file_id_cache(photo_path, sent_msg)
    else:
        sent_msg = await message.answer(welcome_text, reply_markup=get_main_menu_keyboard(), parse_mode="HTML")
    await state.clear()

@router.message(F.text == support)
async def support(message: Message):
    photo_path = "./media/Поддержка.png"
    photo = get_cached_media(photo_path)
    text = f"<b>Помощь</b>\n\n"
    text += f"<i>Инструкции по подключению:</i>\n"
    text += f"<a href='https://sharks-vpn-infrastructure.gitbook.io/sharks-infrastructure-docs/getting-started/quickstart'>Как подключиться на IOS, MAC</a>\n"
    text += f"<a href='https://sharks-vpn-infrastructure.gitbook.io/sharks-infrastructure-docs/getting-started/quickstart-1'>Как подключиться на Android, Windows</a>\n\n"
    text += f"💬 <i>В случае возникновения проблем обращайтесь в нашу поддержку:</i>\n"
    text += f"👤 <i>{os.getenv('support_username')}</i>\n"

    if photo:
        sent_msg = await message.answer_photo(photo, text, parse_mode="HTML")
        update_file_id_cache(photo_path, sent_msg)
    else:
        sent_msg = await message.answer(text, parse_mode="HTML")

@router.message(F.text == profile_button)
async def profile(message: Message, state: FSMContext):
    photo_path = "./media/Профиль.png"
    photo = get_cached_media(photo_path)
    keyboard = get_profile_keyboard()
    # Profile info is already cached in the function
    if photo:
        sent_msg = await message.answer_photo(photo, await profile_info(message.from_user), reply_markup=keyboard, parse_mode="HTML")
        update_file_id_cache(photo_path, sent_msg)
    else:
        sent_msg = await message.answer(await profile_info(message.from_user), reply_markup=keyboard, parse_mode="HTML")
    await state.set_state(UserState.profile)

@router.callback_query(F.data == "add_balance")
async def add_balance_handler(callback: CallbackQuery):
    # TODO: transfer payment from buying to add balance
    text = f"<b>💳 Выберите способ оплаты:</b>"
    if callback.message.photo:
        await callback.message.edit_caption(
            caption=text,
            reply_markup=get_providers_keyboard(),
            parse_mode="HTML"
        )
    else:
        await callback.message.edit_text(
            text=text,
            reply_markup=get_providers_keyboard(),
            parse_mode="HTML"
        )

@router.callback_query(F.data == "referal_system")
async def referal_system(callback: CallbackQuery):
    text = await referal_info(callback.from_user, callback.bot)
    if callback.message.photo:
        await callback.message.edit_caption(caption=text, reply_markup=back_keyboard(), parse_mode="HTML")
    else:
        await callback.message.edit_text(text=text, reply_markup=back_keyboard(), parse_mode="HTML")

# MY SUBSCRIPTIONS
@router.message(F.text == my_subscriptions)
async def my_subscriptions(message: Message):
    photo_path = "./media/МоиПодписки.png"
    photo = get_cached_media(photo_path)

    keyboard = await get_my_subscriptions_keyboard(message.from_user.id)
    if len(keyboard.inline_keyboard) > 0:
        text = f"<b>📱 Мои подписки:</b>\n\n"
    else:
        text = f"<b>📱 У вас ещё нет подписок</b>"
    # Keyboard generation uses subscription data
    if photo:
        sent_msg = await message.answer_photo(photo, text, 
                             reply_markup=keyboard, 
                             parse_mode="HTML")
        update_file_id_cache(photo_path, sent_msg)
    else:
        sent_msg = await message.answer(text, reply_markup=keyboard, parse_mode="HTML")

@router.callback_query(F.data.startswith("subs_page_"))
async def subscription_page_callback(callback: CallbackQuery):
    """Handle pagination for subscriptions keyboard"""
    page = int(callback.data.split("_")[-1])
    await callback.answer()
    # Keyboard generation uses cached subscription data
    await callback.message.edit_reply_markup(
        reply_markup=await get_my_subscriptions_keyboard(callback.from_user.id, page=page)
    )

@router.callback_query(F.data.startswith("subscription_"))
async def subscription_callback(callback: CallbackQuery, state: FSMContext):
    """Show subscription info and keyboard"""
    sub_id = callback.data.split("_")[1]
    sub = await get_subscription(sub_id)
    
    await state.set_state(UserState.info_about_subscription)
    await state.update_data(subscription_id=sub_id)
    
    if callback.message.photo:
        await callback.message.edit_caption(
            caption=await get_subscription_info(sub), 
            reply_markup=get_subscription_keyboard(sub_id), 
            parse_mode="HTML"
        )
    else:
        await callback.message.edit_text(
            text=await get_subscription_info(sub), 
            reply_markup=get_subscription_keyboard(sub_id), 
            parse_mode="HTML"
        )
    await callback.answer()

@router.callback_query(F.data.startswith("extend_subscription_"))
async def extend_subscription_callback(callback: CallbackQuery, state: FSMContext):
    """Extend subscription info and keyboard"""
    sub_id = callback.data.split("_")[-1]
    sub = await get_subscription(sub_id)
    user = await get_or_create_user(callback.from_user)
    keyboard = None

    # Prepare text
    if user.balance >= sub.plan.price:
        text = f"<b>💳 Выберите способ оплаты:</b>\n\n"
        text += f"💰 Стоимость продления: {sub.plan.price} руб.\n"
        keyboard = get_confirm_buy_keyboard(sub.plan.price)
    else:
        text = f"<b>💳 Недостаточно средств</b>\n\n"
        text += f"💰 Ваш баланс: {user.balance} руб.\n"
    
    if callback.message.photo:
        await callback.message.edit_caption(
            caption=text,
            reply_markup=keyboard,
            parse_mode="HTML"
        )
    else:
        await callback.message.edit_text(
            text=text,
            reply_markup=keyboard,
            parse_mode="HTML"
        )
    await state.set_state(UserState.extend_subscription)
    await state.update_data(sub=sub)

@router.callback_query(F.data == "back")
async def back(callback: CallbackQuery, state: FSMContext):
    """Back to previous state"""
    state_ = await state.get_state()
    if state_ == UserState.info_about_subscription:
        text = "<b>📱 Мои подписки:</b>"
        if callback.message.photo:
            await callback.message.edit_caption(
                caption=text,
                reply_markup=await get_my_subscriptions_keyboard(callback.from_user.id),
                parse_mode="HTML"
            )
        else:
            await callback.message.edit_text(
                text=text,
                reply_markup=await get_my_subscriptions_keyboard(callback.from_user.id),
                parse_mode="HTML"
            )
        await state.clear()
    elif state_ == UserState.waiting_for_payment:
        text = "🌍 Выберите страну для подключения:"
        if callback.message.photo:
            await callback.message.edit_caption(
                caption=text,
                reply_markup=get_countries_keyboard()
            )
        else:
            await callback.message.edit_text(
                text=text,
                reply_markup=get_countries_keyboard()
            )
        await state.set_state(UserState.waiting_for_country)
    elif state_ == UserState.waiting_for_country:
        text = f"<b>🛒 Купить VPN:</b>"
        if callback.message.photo:
            await callback.message.edit_caption(
                caption=text,
                reply_markup=await get_buy_vpn_keyboard(),
                parse_mode="HTML"
            )
        else:
            await callback.message.edit_text(
                text=text,
                reply_markup=await get_buy_vpn_keyboard(),
                parse_mode="HTML"
            )
        await state.clear()
    elif state_ == UserState.profile:
        if callback.message.photo:
            await callback.message.edit_caption(caption=await profile_info(callback.from_user), reply_markup=get_profile_keyboard(), parse_mode="HTML")
        else:
            await callback.message.edit_text(text=await profile_info(callback.from_user), reply_markup=get_profile_keyboard(), parse_mode="HTML")
        await state.clear()
        
    await callback.answer()


#  BUY VPN
@router.message(F.text == buy_vpn)
async def buy_vpn(message: Message):
    photo_path = "./media/КупитьВПН.png"
    photo = get_cached_media(photo_path)
    text = f"<b>🛒 Купить VPN:</b>"
    if photo:
        sent_msg = await message.answer_photo(
            photo,
            text,
            reply_markup=await get_buy_vpn_keyboard(),
            parse_mode="HTML"
        )
        update_file_id_cache(photo_path, sent_msg)
    else:
        sent_msg = await message.answer(
            text,
            reply_markup=await get_buy_vpn_keyboard(),
            parse_mode="HTML"
        )


@router.callback_query(F.data.startswith("buy_"))
async def buy_vpn_callback(callback: CallbackQuery, state: FSMContext):
    plan_id = callback.data.split("_")[1]
    plan = await get_plan(plan_id)
    text = "🌍 Выберите страну для подключения:"
    await callback.answer()

    if callback.message.photo:
        await callback.message.edit_caption(
            text,
            reply_markup=get_countries_keyboard()
        )
    else:
        await callback.message.edit_text(
            text,
            reply_markup=get_countries_keyboard()
        )

    await state.set_state(UserState.waiting_for_country)
    await state.update_data(plan=plan)

@router.callback_query(F.data.startswith("countries_page:"))
async def handle_countries_pagination(callback: CallbackQuery, state: FSMContext):
    """Handle pagination for countries keyboard"""
    if await state.get_state() == UserState.waiting_for_country:
        page = int(callback.data.split(":")[1])
        text = "🌍 Выберите страну для подключения:"
        if callback.message.photo:
            await callback.message.edit_caption(
                text,
                reply_markup=get_countries_keyboard(page=page)
            )
        else:
            await callback.message.edit_text(
                text,
                reply_markup=get_countries_keyboard(page=page)
            )

@router.callback_query(F.data.startswith("select_country:"))
async def handle_country_selection(callback: CallbackQuery, state: FSMContext):
    """Handle country selection"""
    country = callback.data.split(":")[1]
    data = await state.get_data()
    countries = marzban_service.countries
    keyboard = None
    text = ""

    if country not in countries:
        await callback.answer("❌ Страна недоступна", show_alert=True)
        return
    
    # Get balance
    user = await get_or_create_user(callback.from_user)
    balance = user.balance
    if balance >= int(data["plan"].price):
        keyboard = get_confirm_buy_keyboard(data["plan"].price)
        text = (f"<b>💳 Подтвердите покупку:</b>\n\n"
                f"💰 Ваш баланс: {balance} руб.\n"
                f"💰 Цена: {data['plan'].price} руб.\n"
                f"📦 Тариф: <i>{data['plan'].name}</i>\n"
                f"🌍 Выбрана страна: {country}"
                )
    else:
        text = (f"<b>💳 Недостаточно средств</b>\n\n"
                f"💰 Ваш баланс: {balance} руб.\n"
                f"💰 Цена: {data['plan'].price} руб.\n"
                f"📦 Тариф: <i>{data['plan'].name}</i>\n"
                f"🌍 Выбрана страна: {country}\n\n"
                f"🔄 <i>Пополните баланс. Сделать это можно нажав на кнопку {profile_button} и выбрав пункт Пополнить баланс</i>")

    if callback.message.photo:
        await callback.message.edit_caption(
            caption=text,
            reply_markup=keyboard,
            parse_mode="HTML"
        )
    else:
        await callback.message.edit_text(
            text=text,
            reply_markup=keyboard,
            parse_mode="HTML"
        )
    
    await state.update_data(country=country)
    await state.set_state(UserState.waiting_for_confirm_buy)


@router.callback_query(F.data.startswith("confirm_buy:"))
async def confirm_buy(callback: CallbackQuery, state: FSMContext):
    amount = callback.data.split(":")[-1]
    data = await state.get_data()
    order = None


    if state.get_state() == UserState.waiting_for_confirm_buy:
        try:
            order = create_order(callback.from_user.id, amount)
        except Exception as e:
            await callback.answer(f"❌ Ошибка: {e}")
            return
        if order:
            # Create  subscription
            sub = await add_subscription(callback.from_user.id, data["plan"].id)
            sub_data = await marzban_service.create_subscription(callback.from_user.id, data["plan"].duration_days, sub.id, data["country"])
            if os.getenv("use_domain") == "true":
                await add_subscription_links(sub.id, sub_data.subscription_url)
            else:
                await add_subscription_links(sub.id, sub_data.links)

            # Get updated subscription
            sub = await get_subscription(sub.id)
            # Create text
            text = f"✅ Подписка успешно создана!\n\n"
            text += f"{await get_subscription_info(sub)}"
            await callback.answer()

            if callback.message.photo:
                await callback.message.edit_caption(caption=text, parse_mode="HTML")
            else:
                await callback.message.edit_text(text=text, parse_mode="HTML")
            
            # Send referal part
            user = await get_or_create_user(callback.from_user)
            ref_part = amount * (os.getenv("referal_percent") / 100)
            if user.ref_id:
                referal_user = await get_or_create_user(user.ref_id)
                referal_order = create_order(referal_user.id, ref_part, "referal_payment", {"plan": data["plan"].name, "country": data["country"], "id_order": order.id})
                # Send notify to referal user
                await callback.bot.send_message(referal_user.id, f"<b>💰 Вы получили {ref_part} руб. за покупку VPN тарифа {data['plan'].name} в стране {data['country']}</b>", 
                                                parse_mode="HTML")
            
            await state.clear()
        else:
            await callback.answer("❌ Оплата не прошла. Попробуйте еще раз.")
    elif await state.get_state() == UserState.extend_subscription:
        try:
            order = create_order(callback.from_user.id, amount, "extend_subscription", {"sub_id": data["sub"].id})
        except Exception as e:
            await callback.answer(f"❌ Ошибка: {e}")
            return
        if order:
            # Extend subscription
            sub = await extend_subscription(data["sub"].id)
            sub_data = await marzban_service.extend_subscription(callback.from_user.id, sub.id, int(sub.end_date.timestamp()))
            if callback.message.photo:
                await callback.message.edit_caption(caption=f"✅ Подписка {sub.id} успешно продлена!", parse_mode="HTML")
            else:
                await callback.message.edit_text(caption=f"✅ Подписка {sub.id} успешно продлена!", parse_mode="HTML")
            await state.clear()
        else:
            await callback.answer("❌ Оплата не прошла. Попробуйте еще раз.")
    

@router.callback_query(F.data.startswith("pay:"))
async def pay(callback: CallbackQuery, state: FSMContext):
    global providers

    data = await state.get_data()
    provider = callback.data.split(":")[-1]
    provider_obj = providers[provider]
    text = "<b>Введите сумму пополнения:</b>\n\n"
    text += f"💳 Выбранный способ оплаты: {provider_obj.name}\n"
    text += f"💰 Минимальная сумма пополнения: {provider_obj.min_amount} руб.\n"

    if callback.message.photo:
        await callback.message.edit_caption(caption=text, parse_mode="HTML")
    else:
        await callback.message.edit_text(text=text, parse_mode="HTML")
    await state.set_state(UserState.waiting_amount)
    await state.update_data(provider=provider)

# Func for process message text. Registered in router.message() in end of file
async def waiting_amount(message: Message, state: FSMContext):
    # Validate amount
    amount = message.text
    if not amount.isdigit():
        await message.answer("❌ Сумма должна быть числом")
        return
    amount = int(amount)

    global providers
    # Проверяем, не выполняется ли уже создание платежа
    current_state_data = await state.get_data()
    if current_state_data.get("payment_in_progress"):
        return
        
    if not providers:
        await message.answer("❌ Сервис временно недоступен")
        return
    
    # Устанавливаем флаг, что платеж в процессе создания
    await state.update_data(payment_in_progress=True)
    
    data = await state.get_data()
    provider = data["provider"]
    provider_obj = providers[provider]
    msg_text = ""
    description = f'Пополнение баланса'

    if amount < provider_obj.min_amount:
        await message.answer(f"❌ Минимальная сумма пополнения для {provider_obj.name}: {provider_obj.min_amount} руб.")
        await state.update_data(payment_in_progress=False)
        return
    else:
        # Prepare data
        msg_text = (f"<b>Оплата через {provider_obj.name}:</b>\n\n"
                    f"💰 Сумма: {amount} руб.\n\n"
                    f"{provider_obj.description}")

    try:
        # Add to DB payment
        payment = await create_payment(message.from_user.id, amount, provider)
        
        # Отправляем сообщение о загрузке
        temporary_message = await message.answer("⏳ Создание платежа...")
        
        # Create invoice 
        invoice = await provider_obj.create_invoice(amount, payment.id, description)
        # Set invoice id
        await set_invoice_id(payment.id, invoice.invoice_id)

        # Send payment keyboard
        await message.answer(text=msg_text, 
                             reply_markup=get_payment_keyboard(invoice.url, payment.id, provider), 
                             parse_mode="HTML")
        await temporary_message.delete()
        await state.set_state(UserState.waiting_for_payment)
    except Exception as e:
        error_msg = (f"❌ <b>Извините, сервис {provider_obj.name} временно недоступен</b>\n\n"
                    f"Пожалуйста, выберите другой способ оплаты или попробуйте позже.")
        await message.answer(text=error_msg, 
                             reply_markup=get_providers_keyboard(),
                             parse_mode="HTML")
        logger.error(f"Error creating invoice: {e}")
    
    # В любом случае сбрасываем флаг создания платежа
    await state.update_data(payment_in_progress=False)


@router.callback_query(F.data.startswith("check_payment:"))
async def check_payment(callback: CallbackQuery, state: FSMContext):
    payment_id = callback.data.split(":")[-1]
    provider = callback.data.split(":")[-2]
    data = await state.get_data()
    provider_obj = providers[provider]

    # Get payment
    payment = await get_payment(payment_id)
    invoice_id = payment.payment_id

    # Check status
    paid = await provider_obj.check_invoice(invoice_id, payment_id)
    if paid:
        await update_payment_status(payment_id, "completed")

    if await state.get_state() == UserState.waiting_for_payment:
        if paid:
            # Try to add balance
            try:
                await add_balance(callback.from_user.id, payment.amount)  # Add payment amount to balance
            except ValueError as e:
                # Handle user not found error
                logger.error(f"ValueError: {e}")
                await callback.answer("❌ Ошибка: пользователь не найден в базе")
                return
            except TimeoutError as e:
                # Handle locking/timeout errors
                logger.error(f"TimeoutError: {e}")
                await callback.answer("❌ Ошибка: время ожидания истекло. Попробуйте позже.")
                return
            except Exception as e:
                # Handle other unexpected errors
                logger.error(f"Error: {e}")
                await callback.answer("❌ Ошибка при изменении баланса")
                return

            if callback.message.photo:
                await callback.message.edit_caption(caption=
                    f"✅ Баланс успешно пополнен!\n\n"
                    , parse_mode="HTML")
            else:
                await callback.message.edit_text(text=
                    f"✅ Баланс успешно пополнен!\n\n"
                    , parse_mode="HTML")
            await state.clear()
        else:
            await callback.answer("❌ Оплата не прошла. Попробуйте еще раз.")

@router.callback_query(F.data == "cancel")
async def cancel(callback: CallbackQuery):
    await callback.answer()
    if callback.message.photo:
        await callback.message.edit_caption(caption="❌ Оплата отменена.")
    else:
        await callback.message.edit_text(text="❌ Оплата отменена.")


@router.message()
async def send_main_keyboard(message: Message, state: FSMContext):
    if await state.get_state() == UserState.waiting_amount:
        await waiting_amount(message, state)
    else:
        text = "❌ <b>Неверная команда</b>\n\n"
        await message.answer(text, reply_markup=get_main_menu_keyboard(), parse_mode="HTML")
