"""
bot/handlers/payment.py
-----------------------

سیستم پرداخت:

- دریافت اطلاعات خرید از plans.py
- دریافت کشور انتخاب‌شده
- دریافت نام اختصاصی سرویس قبل از پرداخت
- ثبت نام سرویس داخل Order
- نمایش قیمت
- ایجاد سفارش
- دریافت رسید
- تأیید / رد پرداخت توسط ادمین
- شروع ارسال کانفیگ توسط ادمین
"""

from __future__ import annotations

import html
import logging

import config

from aiogram import Router, F, Bot
from aiogram.fsm.context import FSMContext
from aiogram.types import (
    CallbackQuery,
    InlineKeyboardButton,
    InlineKeyboardMarkup,
    Message,
)

from sqlalchemy import select

from database.database import get_session

from database.crud import (
    create_order,
    get_order,
    get_user_by_telegram_id,
    get_referral_discount_percent,
    get_subscription,
)

from database.models import (
    Plan,
    OrderStatus,
)

from bot.handlers.admin.config import (
    start_config_delivery,
)

from bot.handlers.plans import (
    PLANS,
    COUNTRIES,
    format_price,
    plan_price_text,
)

from bot.states.states import (
    PurchaseStates,
    RenewalStates,
    PaymentStates,
)


# ============================================================
# Router
# ============================================================

router = Router(name="payment")

logger = logging.getLogger(__name__)


# ============================================================
# اطلاعات پرداخت
# ============================================================

CARD_NUMBER = "6219861431917714"

CARD_OWNER = "بلو علیرضا اناری"


# ============================================================
# بررسی ادمین
# ============================================================

def is_admin_user(user_id: int) -> bool:

    return config.is_admin(user_id)


# ============================================================
# لیست ادمین‌ها
# ============================================================

def get_admin_ids() -> list[int]:

    admin_ids = getattr(
        config,
        "ADMIN_IDS",
        None,
    )

    if not admin_ids:
        return []

    return [
        int(admin_id)
        for admin_id in admin_ids
    ]


# ============================================================
# ابزار کشور
# ============================================================

def get_country_label(
    region: str | None,
) -> str:

    if not region or region == "none":
        return "نامشخص"

    country = COUNTRIES.get(region)

    if not country:
        return region

    return (
        f"{country['flag']} "
        f"{country['name']}"
    )


def get_country_name(
    region: str | None,
) -> str:

    if not region or region == "none":
        return "نامشخص"

    country = COUNTRIES.get(region)

    if not country:
        return region

    return country["name"]


# ============================================================
# تشخیص حجم پلن
# ============================================================

def get_volume_gb(
    plan_id: str,
) -> int:

    try:

        if str(plan_id).isdigit():
            return int(plan_id)

    except (
        AttributeError,
        ValueError,
        TypeError,
    ):

        pass

    return 0


# ============================================================
# ساخت نام Plan
# ============================================================

def build_plan_name(
    service: dict,
    selected_plan: dict,
    region: str | None,
) -> str:

    service_title = service.get(
        "title",
        "سرویس نامشخص",
    )

    plan_display_name = selected_plan.get(
        "name",
        "پلن نامشخص",
    )

    country_name = get_country_name(
        region
    )

    return (
        f"{service_title} — "
        f"{country_name} — "
        f"{plan_display_name}"
    )


# ============================================================
# ساخت توضیحات Plan
# ============================================================

def build_plan_description(
    service: dict,
    selected_plan: dict,
    region: str | None,
) -> str:

    country_label = get_country_label(
        region
    )

    return (
        f"{service.get('title', 'سرویس نامشخص')}\n"
        f"کشور: {country_label}\n"
        f"پلن: {selected_plan.get('name', 'نامشخص')}\n"
        f"ارائه‌دهنده: {service.get('provider', 'نامشخص')}\n"
        f"نوع اتصال: {service.get('connection', 'نامشخص')}\n"
        f"مدت: یک ماه"
    )


# ============================================================
# کیبورد پرداخت
# ============================================================

def payment_keyboard(
    order_id: int,
) -> InlineKeyboardMarkup:

    return InlineKeyboardMarkup(
        inline_keyboard=[
            [
                InlineKeyboardButton(
                    text="📸 ارسال رسید پرداخت",
                    callback_data=(
                        f"send_receipt:{order_id}"
                    ),
                )
            ],
            [
                InlineKeyboardButton(
                    text="❌ لغو سفارش",
                    callback_data=(
                        f"cancel_order:{order_id}"
                    ),
                )
            ],
        ]
    )


# ============================================================
# کیبورد ادمین
# ============================================================

def admin_receipt_keyboard(
    order_id: int,
) -> InlineKeyboardMarkup:

    return InlineKeyboardMarkup(
        inline_keyboard=[
            [
                InlineKeyboardButton(
                    text="✅ تأیید پرداخت",
                    callback_data=(
                        f"admin_approve:{order_id}"
                    ),
                ),
                InlineKeyboardButton(
                    text="❌ رد پرداخت",
                    callback_data=(
                        f"admin_reject:{order_id}"
                    ),
                ),
            ]
        ]
    )


# ============================================================
# تجزیه Callback خرید
# ============================================================

def parse_confirm_callback(
    callback_data: str,
):

    if not callback_data:
        return None

    if not callback_data.startswith("confirm_"):
        return None

    parts = callback_data.split("_")

    if len(parts) < 4:
        return None

    region = parts[-1]

    plan_id = parts[-2]

    service_type = "_".join(
        parts[1:-2]
    )

    if not service_type:
        return None

    return (
        service_type,
        plan_id,
        region,
    )


# ============================================================
# اعتبارسنجی اطلاعات خرید
# ============================================================

def get_purchase_data(
    callback_data: str,
):

    parsed = parse_confirm_callback(
        callback_data
    )

    if not parsed:
        return None

    (
        service_type,
        plan_id,
        region,
    ) = parsed

    service = PLANS.get(
        service_type
    )

    if not service:
        return None

    allowed_locations = service.get(
        "locations",
        [],
    )

    if allowed_locations:

        if region not in allowed_locations:
            return None

    selected_plan = None

    for plan in service.get(
        "plans",
        [],
    ):

        if str(plan.get("id")) == str(plan_id):

            selected_plan = plan

            break

    if selected_plan is None:
        return None

    price = selected_plan.get(
        "price"
    )

    original_price = selected_plan.get(
        "original_price"
    )

    if price is None:
        return None

    country_label = get_country_label(
        region
    )

    country_name = get_country_name(
        region
    )

    plan_display_name = selected_plan.get(
        "name",
        "نامشخص",
    )

    service_title = service.get(
        "title",
        "سرویس نامشخص",
    )

    plan_name = build_plan_name(
        service=service,
        selected_plan=selected_plan,
        region=region,
    )

    volume_gb = get_volume_gb(
        plan_id
    )

    plan_description = build_plan_description(
        service=service,
        selected_plan=selected_plan,
        region=region,
    )

    return {
        "service_type": service_type,
        "plan_id": plan_id,
        "region": region,
        "service": service,
        "selected_plan": selected_plan,
        "price": price,
        "original_price": original_price,
        "country_label": country_label,
        "country_name": country_name,
        "plan_display_name": plan_display_name,
        "service_title": service_title,
        "plan_name": plan_name,
        "volume_gb": volume_gb,
        "plan_description": plan_description,
    }


# ============================================================
# بررسی سازگاری Plan تمدید
# ============================================================

def renewal_plans_match(
    current_plan: Plan | None,
    selected_plan: Plan,
) -> bool:

    if not current_plan:
        return False

    # --------------------------------------------------------
    # Planهای جدید
    # --------------------------------------------------------

    if (
        current_plan.service_type
        and selected_plan.service_type
    ):

        if (
            current_plan.service_type
            != selected_plan.service_type
        ):
            return False

        if (
            current_plan.region
            != selected_plan.region
        ):
            return False

        return True

    # --------------------------------------------------------
    # Planهای قدیمی
    # --------------------------------------------------------

    current_name = (
        current_plan.name
        or ""
    )

    selected_name = (
        selected_plan.name
        or ""
    )

    current_parts = [
        part.strip()
        for part in current_name.split("—")
    ]

    selected_parts = [
        part.strip()
        for part in selected_name.split("—")
    ]

    if (
        len(current_parts) < 2
        or len(selected_parts) < 2
    ):
        return False

    return (
        current_parts[0]
        == selected_parts[0]
        and
        current_parts[1]
        == selected_parts[1]
    )


# ============================================================
# دریافت Plan فعلی Subscription
# ============================================================

async def get_subscription_plan(
    session,
    subscription,
) -> Plan | None:

    if not subscription.plan_id:
        return None

    result = await session.execute(
        select(Plan).where(
            Plan.id == subscription.plan_id
        )
    )

    return result.scalar_one_or_none()


# ============================================================
# انتخاب Plan تمدید
# ============================================================

@router.callback_query(
    F.data.startswith("renewplan_")
)
async def select_renewal_plan(
    callback: CallbackQuery,
    state: FSMContext,
):

    try:

        parts = callback.data.split("_")

        if len(parts) != 3:
            raise ValueError

        subscription_id = int(
            parts[1]
        )

        plan_id = int(
            parts[2]
        )

    except (
        ValueError,
        TypeError,
    ):

        await callback.answer(
            "❌ اطلاعات تمدید نامعتبر است.",
            show_alert=True,
        )

        return

    async with get_session() as session:

        subscription = await get_subscription(
            session=session,
            subscription_id=subscription_id,
        )

        if not subscription:

            await callback.answer(
                "❌ سرویس پیدا نشد.",
                show_alert=True,
            )

            return

        # ----------------------------------------------------
        # مالکیت بدون استفاده از relationship
        # ----------------------------------------------------

        user = await get_user_by_telegram_id(
            session,
            callback.from_user.id,
        )

        if (
            not user
            or subscription.user_id != user.id
        ):

            await callback.answer(
                "❌ این سرویس متعلق به شما نیست.",
                show_alert=True,
            )

            return

        # ----------------------------------------------------
        # Plan انتخابی
        # ----------------------------------------------------

        result = await session.execute(
            select(Plan).where(
                Plan.id == plan_id,
                Plan.is_active.is_(True),
            )
        )

        selected_plan = (
            result.scalar_one_or_none()
        )

        if not selected_plan:

            await callback.answer(
                "❌ پلن انتخاب‌شده معتبر نیست.",
                show_alert=True,
            )

            return

        # ----------------------------------------------------
        # Plan فعلی
        # ----------------------------------------------------

        current_plan = await get_subscription_plan(
            session,
            subscription,
        )

        if not current_plan:

            await callback.answer(
                "❌ پلن فعلی سرویس پیدا نشد.",
                show_alert=True,
            )

            return

        # ----------------------------------------------------
        # سازگاری سرویس
        # ----------------------------------------------------

        if not renewal_plans_match(
            current_plan,
            selected_plan,
        ):

            await callback.answer(
                "❌ این پلن برای این سرویس قابل تمدید نیست.",
                show_alert=True,
            )

            return

        # ----------------------------------------------------
        # قیمت
        # ----------------------------------------------------

        price = selected_plan.price

        referral_discount_percent = (
            await get_referral_discount_percent(
                session=session,
                user_id=subscription.user_id,
            )
        )

        referral_discount_amount = int(
            round(
                price
                * referral_discount_percent
                / 100
            )
        )

        final_price = max(
            0,
            price - referral_discount_amount,
        )

        service_name = (
            subscription.service_name
            or f"سرویس #{subscription.id}"
        )

        plan_name = (
            selected_plan.name
            or "نامشخص"
        )

        duration_days = (
            selected_plan.duration_days
            or 30
        )

        # ----------------------------------------------------
        # ذخیره در FSM
        # ----------------------------------------------------

        await state.update_data(
            renewal_subscription_id=subscription.id,
            renewal_plan_id=selected_plan.id,
        )

    # ========================================================
    # PRICE DISPLAY
    # ========================================================

    if referral_discount_amount > 0:

        price_display = (
            f"💰 <b>مبلغ اصلی:</b> "
            f"{format_price(price)} تومان\n"

            f"🎁 <b>تخفیف زیرمجموعه‌گیری:</b> "
            f"{referral_discount_percent:g}٪ "
            f"({format_price(referral_discount_amount)} تومان)\n"

            f"💳 <b>مبلغ نهایی:</b> "
            f"{format_price(final_price)} تومان"
        )

    else:

        price_display = (
            f"💰 <b>مبلغ:</b> "
            f"{format_price(price)} تومان"
        )

    # ========================================================
    # CONFIRM KEYBOARD
    # ========================================================

    keyboard = InlineKeyboardMarkup(
        inline_keyboard=[
            [
                InlineKeyboardButton(
                    text="✅ ادامه و پرداخت",
                    callback_data="confirm_renewal",
                )
            ],
            [
                InlineKeyboardButton(
                    text="🔙 انتخاب پلن دیگر",
                    callback_data=(
                        f"renew_service_{subscription_id}"
                    ),
                )
            ],
            [
                InlineKeyboardButton(
                    text="🏠 منوی اصلی",
                    callback_data="back_to_main_menu",
                )
            ],
        ]
    )

    # ========================================================
    # MESSAGE
    # ========================================================

    text = (
        "🔄 <b>تأیید تمدید سرویس</b>\n\n"

        f"🏷 <b>نام سرویس:</b> "
        f"{html.escape(str(service_name))}\n"

        f"📦 <b>پلن انتخابی:</b> "
        f"{html.escape(str(plan_name))}\n"

        f"⏱ <b>مدت تمدید:</b> "
        f"{duration_days} روز\n\n"

        f"{price_display}\n\n"

        "━━━━━━━━━━━━━━━━━━\n\n"

        "اگر اطلاعات بالا صحیح است، "
        "روی «ادامه و پرداخت» بزن."
    )

    try:

        await callback.message.edit_text(
            text,
            reply_markup=keyboard,
        )

    except Exception:

        logger.exception(
            "Could not edit renewal plan confirmation message"
        )

        await callback.message.answer(
            text,
            reply_markup=keyboard,
        )

    await callback.answer()


# ============================================================
# تأیید تمدید
# ============================================================

@router.callback_query(
    F.data == "confirm_renewal"
)
async def confirm_renewal(
    callback: CallbackQuery,
    state: FSMContext,
):

    data = await state.get_data()

    subscription_id = data.get(
        "renewal_subscription_id"
    )

    plan_id = data.get(
        "renewal_plan_id"
    )

    if not subscription_id or not plan_id:

        await state.clear()

        await callback.answer(
            "❌ اطلاعات تمدید منقضی شده است.",
            show_alert=True,
        )

        return

    async with get_session() as session:

        subscription = await get_subscription(
            session=session,
            subscription_id=subscription_id,
        )

        if not subscription:

            await state.clear()

            await callback.answer(
                "❌ سرویس پیدا نشد.",
                show_alert=True,
            )

            return

        # ----------------------------------------------------
        # مالکیت بدون relationship
        # ----------------------------------------------------

        user = await get_user_by_telegram_id(
            session,
            callback.from_user.id,
        )

        if (
            not user
            or subscription.user_id != user.id
        ):

            await state.clear()

            await callback.answer(
                "❌ این سرویس متعلق به شما نیست.",
                show_alert=True,
            )

            return

        # ----------------------------------------------------
        # Plan انتخابی
        # ----------------------------------------------------

        result = await session.execute(
            select(Plan).where(
                Plan.id == plan_id,
                Plan.is_active.is_(True),
            )
        )

        plan = (
            result.scalar_one_or_none()
        )

        if not plan:

            await state.clear()

            await callback.answer(
                "❌ پلن تمدید معتبر نیست.",
                show_alert=True,
            )

            return

        # ----------------------------------------------------
        # Plan فعلی
        # ----------------------------------------------------

        current_plan = await get_subscription_plan(
            session,
            subscription,
        )

        if not current_plan:

            await state.clear()

            await callback.answer(
                "❌ پلن فعلی سرویس پیدا نشد.",
                show_alert=True,
            )

            return

        # ----------------------------------------------------
        # امنیت مضاعف
        # ----------------------------------------------------

        if not renewal_plans_match(
            current_plan,
            plan,
        ):

            await state.clear()

            await callback.answer(
                "❌ این پلن برای این سرویس قابل تمدید نیست.",
                show_alert=True,
            )

            return

        # ----------------------------------------------------
        # قیمت
        # ----------------------------------------------------

        price = plan.price

        referral_discount_percent = (
            await get_referral_discount_percent(
                session=session,
                user_id=subscription.user_id,
            )
        )

        referral_discount_amount = int(
            round(
                price
                * referral_discount_percent
                / 100
            )
        )

        final_price = max(
            0,
            price - referral_discount_amount,
        )

        # ----------------------------------------------------
        # ساخت سفارش تمدید
        # ----------------------------------------------------

        order = await create_order(
            session=session,
            user_id=subscription.user_id,
            plan_id=plan.id,
            amount=final_price,
            order_type="renew",
            subscription_id=subscription.id,
            service_name=subscription.service_name,
        )

        order_id = order.id

        service_name = (
            subscription.service_name
            or f"سرویس #{subscription.id}"
        )

        plan_name = (
            plan.name
            or "نامشخص"
        )

        duration_days = (
            plan.duration_days
            or 30
        )

    # ========================================================
    # PRICE DISPLAY
    # ========================================================

    if referral_discount_amount > 0:

        price_display = (
            f"💰 <b>مبلغ اصلی:</b> "
            f"{format_price(price)} تومان\n"

            f"🎁 <b>تخفیف زیرمجموعه‌گیری:</b> "
            f"{referral_discount_percent:g}٪ "
            f"({format_price(referral_discount_amount)} تومان)\n"

            f"💳 <b>مبلغ نهایی:</b> "
            f"{format_price(final_price)} تومان"
        )

    else:

        price_display = (
            f"💰 <b>مبلغ:</b> "
            f"{format_price(final_price)} تومان"
        )

    # ========================================================
    # PAYMENT MESSAGE
    # ========================================================

    text = (
        "🔄 <b>پرداخت تمدید سرویس</b>\n\n"

        f"🧾 <b>شماره سفارش:</b> "
        f"<code>#{order_id}</code>\n\n"

        f"🏷 <b>نام سرویس:</b> "
        f"{html.escape(str(service_name))}\n"

        f"📦 <b>پلن:</b> "
        f"{html.escape(str(plan_name))}\n"

        f"⏱ <b>مدت تمدید:</b> "
        f"{duration_days} روز\n\n"

        f"{price_display}\n\n"

        "━━━━━━━━━━━━━━━━━━\n\n"

        "💳 <b>شماره کارت:</b>\n"
        f"<code>{CARD_NUMBER}</code>\n\n"

        f"👤 <b>به نام:</b> "
        f"{html.escape(CARD_OWNER)}\n\n"

        "━━━━━━━━━━━━━━━━━━\n\n"

        "🔹 مبلغ دقیق را به کارت بالا واریز کنید.\n"
        "🔹 سپس رسید پرداخت را ارسال کنید.\n"
        "🔹 رسید باید واضح و خوانا باشد."
    )

    await callback.message.edit_text(
        text,
        reply_markup=payment_keyboard(
            order_id
        ),
    )

    await state.clear()

    logger.info(
        "Renewal order created | "
        "order_id=%s | "
        "user=%s | "
        "subscription_id=%s | "
        "plan=%s | "
        "base_amount=%s | "
        "referral_discount_percent=%s | "
        "final_amount=%s",
        order_id,
        callback.from_user.id,
        subscription_id,
        plan_name,
        price,
        referral_discount_percent,
        final_price,
    )

    await callback.answer()


# ============================================================
# تأیید اولیه خرید
# ============================================================

@router.callback_query(
    lambda callback: (
        callback.data
        and callback.data.startswith("confirm_")
        and callback.data != "confirm_renewal"
    )
)
async def confirm_purchase(
    callback: CallbackQuery,
    state: FSMContext,
):

    try:

        purchase_data = get_purchase_data(
            callback.data
        )

        if not purchase_data:

            await callback.answer(
                "❌ اطلاعات خرید نامعتبر است.",
                show_alert=True,
            )

            return

        await state.update_data(
            purchase_service_type=(
                purchase_data["service_type"]
            ),
            purchase_plan_id=(
                purchase_data["plan_id"]
            ),
            purchase_region=(
                purchase_data["region"]
            ),
        )

        await state.set_state(
            PurchaseStates.WAITING_FOR_SERVICE_NAME
        )

        service_title = html.escape(
            str(
                purchase_data["service_title"]
            )
        )

        plan_display_name = html.escape(
            str(
                purchase_data["plan_display_name"]
            )
        )

        country_label = html.escape(
            str(
                purchase_data["country_label"]
            )
        )

        price = purchase_data["price"]

        original_price = purchase_data[
            "original_price"
        ]

        if (
            original_price is not None
            and original_price > price
        ):

            price_display = plan_price_text(
                purchase_data["selected_plan"]
            )

        else:

            price_display = (
                f"{format_price(price)} تومان"
            )

        text = (
            "🏷 <b>نام سرویس</b>\n\n"

            "قبل از ادامه پرداخت، یک اسم برای این سرویس "
            "انتخاب کن تا بعداً راحت‌تر از بخش "
            "«سرویس‌های من» پیداش کنی.\n\n"

            "مثلاً:\n"
            "• گوشی من\n"
            "• لپ‌تاپ\n"
            "• گیمینگ\n"
            "• سرویس محل کار\n\n"

            "━━━━━━━━━━━━━━━━━━\n\n"

            f"🖥 <b>سرویس:</b> "
            f"{service_title}\n"

            f"🌍 <b>کشور:</b> "
            f"{country_label}\n"

            f"📦 <b>پلن:</b> "
            f"{plan_display_name}\n"

            f"💰 <b>مبلغ:</b> "
            f"{price_display}\n\n"

            "✏️ <b>اسم دلخواهت رو همینجا ارسال کن.</b>"
        )

        await callback.message.edit_text(
            text,
            reply_markup=InlineKeyboardMarkup(
                inline_keyboard=[
                    [
                        InlineKeyboardButton(
                            text="🔙 بازگشت به بسته‌ها",
                            callback_data=(
                                f"backplans_"
                                f"{purchase_data['service_type']}_"
                                f"{purchase_data['region']}"
                            ),
                        )
                    ]
                ]
            ),
        )

        await callback.answer()

    except Exception:

        logger.exception(
            "Error while preparing purchase"
        )

        await state.clear()

        await callback.answer(
            "❌ هنگام آماده‌سازی خرید خطایی رخ داد.",
            show_alert=True,
        )


# ============================================================
# دریافت نام سرویس
# ============================================================

@router.message(
    PurchaseStates.WAITING_FOR_SERVICE_NAME,
    F.text,
)
async def receive_service_name(
    message: Message,
    state: FSMContext,
):

    service_name = message.text.strip()

    if not service_name:

        await message.answer(
            "⚠️ اسم سرویس نمی‌تواند خالی باشد.\n\n"
            "مثلاً «گوشی من» را ارسال کن."
        )

        return

    if len(service_name) > 60:

        await message.answer(
            "⚠️ اسم سرویس خیلی طولانیه.\n\n"
            "لطفاً یک اسم حداکثر ۶۰ کاراکتری انتخاب کن."
        )

        return

    data = await state.get_data()

    service_type = data.get(
        "purchase_service_type"
    )

    plan_id = data.get(
        "purchase_plan_id"
    )

    region = data.get(
        "purchase_region"
    )

    if not service_type or not plan_id:

        await state.clear()

        await message.answer(
            "❌ اطلاعات خرید منقضی شده است.\n\n"
            "لطفاً دوباره از بخش «خرید اشتراک» اقدام کن."
        )

        return

    if region is None:
        region = "none"

    callback_data = (
        f"confirm_{service_type}_{plan_id}_{region}"
    )

    purchase_data = get_purchase_data(
        callback_data
    )

    if not purchase_data:

        await state.clear()

        await message.answer(
            "❌ اطلاعات این خرید دیگر معتبر نیست.\n\n"
            "لطفاً دوباره از بخش «خرید اشتراک» اقدام کن."
        )

        return

    async with get_session() as session:

        user = await get_user_by_telegram_id(
            session,
            message.from_user.id,
        )

        if not user:

            await state.clear()

            await message.answer(
                "❌ اطلاعات کاربر پیدا نشد.\n"
                "لطفاً دوباره /start را بزنید."
            )

            return

        price = purchase_data["price"]

        original_price = purchase_data[
            "original_price"
        ]

        referral_discount_percent = (
            await get_referral_discount_percent(
                session=session,
                user_id=user.id,
            )
        )

        referral_discount_amount = int(
            round(
                price
                * referral_discount_percent
                / 100
            )
        )

        final_price = max(
            0,
            price - referral_discount_amount,
        )

        plan_name = purchase_data[
            "plan_name"
        ]

        volume_gb = purchase_data[
            "volume_gb"
        ]

        plan_description = purchase_data[
            "plan_description"
        ]

        # ----------------------------------------------------
        # پیدا کردن Plan
        # ----------------------------------------------------

        query = select(
            Plan
        ).where(
            Plan.name == plan_name,
            Plan.price == price,
            Plan.volume_gb == volume_gb,
        )

        result = await session.execute(
            query
        )

        plan = (
            result.scalar_one_or_none()
        )

        # ----------------------------------------------------
        # ساخت Plan
        # ----------------------------------------------------

        if not plan:

            plan = Plan(
                name=plan_name,
                service_type=service_type,
                region=region,
                price=price,
                volume_gb=volume_gb,
                duration_days=30,
                description=plan_description,
                is_active=True,
            )

            session.add(plan)

            await session.flush()

        else:

            # ------------------------------------------------
            # تکمیل اطلاعات Planهای قدیمی
            # ------------------------------------------------

            changed = False

            if not plan.service_type:

                plan.service_type = service_type
                changed = True

            if not plan.region:

                plan.region = region
                changed = True

            if changed:

                await session.flush()

        # ----------------------------------------------------
        # Order
        # ----------------------------------------------------

        order = await create_order(
            session=session,
            user_id=user.id,
            plan_id=plan.id,
            amount=final_price,
            order_type="new",
            subscription_id=None,
            service_name=service_name,
        )

        order_id = order.id

    # ========================================================
    # State
    # ========================================================

    await state.update_data(
        service_name=service_name,
        order_id=order_id,
    )

    # ========================================================
    # PRICE
    # ========================================================

    if (
        original_price is not None
        and original_price > price
    ):

        base_price_display = plan_price_text(
            purchase_data["selected_plan"]
        )

    else:

        base_price_display = (
            f"{format_price(price)} تومان"
        )

    if referral_discount_amount > 0:

        price_display = (
            f"{base_price_display}\n"
            f"🎁 <b>تخفیف زیرمجموعه‌گیری:</b> "
            f"{referral_discount_percent:g}٪ "
            f"({format_price(referral_discount_amount)} تومان)\n"
            f"💳 <b>مبلغ نهایی:</b> "
            f"{format_price(final_price)} تومان"
        )

    else:

        price_display = (
            f"{base_price_display}"
        )

    safe_service_name = html.escape(
        service_name
    )

    service_title = html.escape(
        str(
            purchase_data["service_title"]
        )
    )

    country_label = html.escape(
        str(
            purchase_data["country_label"]
        )
    )

    plan_display_name = html.escape(
        str(
            purchase_data["plan_display_name"]
        )
    )

    connection = html.escape(
        str(
            purchase_data["service"].get(
                "connection",
                "نامشخص",
            )
        )
    )

    # ========================================================
    # PAYMENT
    # ========================================================

    text = (
        "💳 <b>پرداخت سفارش</b>\n\n"

        f"🧾 <b>شماره سفارش:</b> "
        f"<code>#{order_id}</code>\n\n"

        f"🏷 <b>نام سرویس:</b> "
        f"{safe_service_name}\n"

        f"🖥 <b>سرویس:</b> "
        f"{service_title}\n"

        f"🌍 <b>کشور:</b> "
        f"{country_label}\n"

        f"📦 <b>پلن:</b> "
        f"{plan_display_name}\n"

        f"🔌 <b>نوع اتصال:</b> "
        f"{connection}\n"

        f"⏱ <b>مدت:</b> "
        f"یک ماه\n"

        f"💰 <b>مبلغ:</b>\n"
        f"{price_display}\n\n"

        "━━━━━━━━━━━━━━━━━━\n\n"

        "💳 <b>شماره کارت:</b>\n"
        f"<code>{CARD_NUMBER}</code>\n\n"

        f"👤 <b>به نام:</b> "
        f"{html.escape(CARD_OWNER)}\n\n"

        "━━━━━━━━━━━━━━━━━━\n\n"

        "🔹 مبلغ دقیق را به کارت بالا واریز کنید.\n"
        "🔹 سپس رسید پرداخت را ارسال کنید.\n"
        "🔹 رسید باید واضح و خوانا باشد."
    )

    await message.answer(
        text,
        reply_markup=payment_keyboard(
            order_id
        ),
    )

    await state.clear()

    logger.info(
        "Order created | "
        "order_id=%s | "
        "user=%s | "
        "service=%s | "
        "service_name=%s | "
        "plan=%s | "
        "region=%s | "
        "base_amount=%s | "
        "referral_discount_percent=%s | "
        "referral_discount_amount=%s | "
        "final_amount=%s",
        order_id,
        message.from_user.id,
        service_type,
        service_name,
        plan_id,
        region,
        price,
        referral_discount_percent,
        referral_discount_amount,
        final_price,
    )


# ============================================================
# درخواست ارسال رسید
# ============================================================

@router.callback_query(
    F.data.startswith("send_receipt:")
)
async def request_receipt(
    callback: CallbackQuery,
    state: FSMContext,
):

    try:

        order_id = int(
            callback.data.split(":")[1]
        )

    except (
        ValueError,
        IndexError,
    ):

        await callback.answer(
            "❌ شماره سفارش نامعتبر است.",
            show_alert=True,
        )

        return

    async with get_session() as session:

        order = await get_order(
            session,
            order_id,
        )

    if not order:

        await callback.answer(
            "❌ سفارش پیدا نشد.",
            show_alert=True,
        )

        return

    if (
        not order.user
        or order.user.telegram_id
        != callback.from_user.id
    ):

        await callback.answer(
            "❌ این سفارش متعلق به شما نیست.",
            show_alert=True,
        )

        return

    if (
        order.status
        != OrderStatus.WAITING_RECEIPT.value
    ):

        await callback.answer(
            "⚠️ این سفارش در حال حاضر منتظر رسید نیست.",
            show_alert=True,
        )

        return

    await state.update_data(
        order_id=order_id
    )

    await state.set_state(
        PaymentStates.waiting_receipt
    )

    await callback.message.edit_text(
        "📸 <b>ارسال رسید پرداخت</b>\n\n"

        f"🧾 شماره سفارش: "
        f"<code>#{order.id}</code>\n\n"

        "لطفاً <b>عکس رسید پرداخت</b> را همینجا ارسال کنید.\n\n"

        "⚠️ فقط عکس رسید را ارسال کنید."
    )

    await callback.answer()


# ============================================================
# دریافت رسید
# ============================================================

@router.message(
    PaymentStates.waiting_receipt,
    F.photo,
)
async def receive_receipt(
    message: Message,
    state: FSMContext,
    bot: Bot,
):

    data = await state.get_data()

    order_id = data.get(
        "order_id"
    )

    if not order_id:

        await state.clear()

        await message.answer(
            "❌ سفارش مربوط به این رسید پیدا نشد.\n"
            "لطفاً دوباره از بخش خرید اقدام کنید."
        )

        return

    async with get_session() as session:

        order = await get_order(
            session,
            order_id,
        )

        if not order:

            await state.clear()

            await message.answer(
                "❌ سفارش پیدا نشد."
            )

            return

        if (
            not order.user
            or order.user.telegram_id
            != message.from_user.id
        ):

            await state.clear()

            await message.answer(
                "❌ این سفارش متعلق به شما نیست."
            )

            return

        if (
            order.status
            != OrderStatus.WAITING_RECEIPT.value
        ):

            await state.clear()

            await message.answer(
                "⚠️ این سفارش قبلاً بررسی شده است."
            )

            return

        receipt_file_id = (
            message.photo[-1].file_id
        )

        order.receipt_file_id = (
            receipt_file_id
        )

        order.status = (
            OrderStatus.WAITING_ADMIN.value
        )

        await session.commit()

        username = order.user.username

        first_name = (
            order.user.first_name
        )

        amount = order.amount

        plan_name = (
            order.plan.name
            if order.plan
            else "نامشخص"
        )

        service_name = (
            order.service_name
            if order.service_name
            else "بدون نام"
        )

        order_type = (
            order.order_type
            or "new"
        )

    await state.clear()

    username_text = (
        f"@{html.escape(username)}"
        if username
        else "ندارد"
    )

    order_type_text = (
        "🔄 تمدید سرویس"
        if order_type == "renew"
        else "🛒 خرید جدید"
    )

    admin_text = (
        "💳 <b>رسید پرداخت جدید</b>\n\n"

        f"🧾 <b>شماره سفارش:</b> "
        f"<code>#{order_id}</code>\n\n"

        f"👤 <b>نام:</b> "
        f"{html.escape(first_name or 'نامشخص')}\n"

        f"🔹 <b>Username:</b> "
        f"{username_text}\n"

        f"🆔 <b>Telegram ID:</b> "
        f"<code>{message.from_user.id}</code>\n\n"

        f"📌 <b>نوع سفارش:</b> "
        f"{order_type_text}\n\n"

        f"🏷 <b>نام سرویس:</b> "
        f"{html.escape(service_name)}\n\n"

        f"📦 <b>سفارش:</b> "
        f"{html.escape(plan_name)}\n\n"

        f"💰 <b>مبلغ:</b> "
        f"{format_price(amount)} تومان\n\n"

        "⏳ <b>وضعیت:</b> "
        "منتظر بررسی پشتیبانی"
    )

    admin_ids = get_admin_ids()

    sent_count = 0

    for admin_id in admin_ids:

        try:

            await bot.send_photo(
                chat_id=admin_id,
                photo=receipt_file_id,
                caption=admin_text,
                reply_markup=admin_receipt_keyboard(
                    order_id
                ),
            )

            sent_count += 1

        except Exception:

            logger.exception(
                "Failed to send receipt to admin %s",
                admin_id,
            )

    if sent_count > 0:

        await message.answer(
            "📸 <b>رسید دریافت شد.</b>\n\n"
            "⏳ رسید شما برای بررسی ارسال شد.\n"
            "پس از تأیید پرداخت، سفارش شما تکمیل می‌شود."
        )

    else:

        await message.answer(
            "📸 رسید دریافت شد.\n\n"
            "⚠️ رسید ثبت شد اما در ارسال آن به پشتیبانی مشکلی پیش آمد."
        )

    logger.info(
        "Receipt received | "
        "order_id=%s | "
        "user=%s | "
        "admins_sent=%s",
        order_id,
        message.from_user.id,
        sent_count,
    )


# ============================================================
# اگر متن به جای عکس ارسال شد
# ============================================================

@router.message(
    PaymentStates.waiting_receipt
)
async def receipt_must_be_photo(
    message: Message,
):

    await message.answer(
        "⚠️ لطفاً <b>عکس رسید پرداخت</b> را ارسال کنید."
    )


# ============================================================
# تأیید پرداخت
# ============================================================

@router.callback_query(
    F.data.startswith("admin_approve:")
)
async def admin_approve(
    callback: CallbackQuery,
    bot: Bot,
    state: FSMContext,
):

    admin_id = callback.from_user.id

    if not is_admin_user(admin_id):

        await callback.answer(
            "❌ شما دسترسی ادمین ندارید.",
            show_alert=True,
        )

        return

    try:

        order_id = int(
            callback.data.split(":")[1]
        )

    except (
        ValueError,
        IndexError,
    ):

        await callback.answer(
            "❌ شماره سفارش نامعتبر است.",
            show_alert=True,
        )

        return

    async with get_session() as session:

        order = await get_order(
            session,
            order_id,
        )

        if not order:

            await callback.answer(
                "❌ سفارش پیدا نشد.",
                show_alert=True,
            )

            return

        if (
            order.status
            != OrderStatus.WAITING_ADMIN.value
        ):

            await callback.answer(
                "⚠️ این سفارش قبلاً بررسی شده است.",
                show_alert=True,
            )

            return

        user_telegram_id = (
            order.user.telegram_id
        )

        plan_name = (
            order.plan.name
            if order.plan
            else "نامشخص"
        )

        service_name = (
            order.service_name
            if order.service_name
            else "بدون نام"
        )

        order_type = (
            order.order_type
            or "new"
        )

        subscription_id = (
            order.subscription_id
        )

        # ----------------------------------------------------
        # تمدید
        # ----------------------------------------------------

        if order_type == "renew":

            if not subscription_id:

                logger.error(
                    "Renewal order has no subscription_id | "
                    "order_id=%s",
                    order_id,
                )

                await callback.answer(
                    "❌ سرویس مربوط به تمدید پیدا نشد.",
                    show_alert=True,
                )

                return

            subscription = await get_subscription(
                session=session,
                subscription_id=subscription_id,
            )

            if not subscription:

                await callback.answer(
                    "❌ سرویس برای تمدید پیدا نشد.",
                    show_alert=True,
                )

                return

            if subscription.user_id != order.user_id:

                logger.error(
                    "Renewal ownership mismatch | "
                    "order_id=%s | "
                    "subscription_id=%s",
                    order_id,
                    subscription_id,
                )

                await callback.answer(
                    "❌ خطای امنیتی در تمدید سرویس.",
                    show_alert=True,
                )

                return

            if not order.plan_id:

                await callback.answer(
                    "❌ پلن تمدید سفارش پیدا نشد.",
                    show_alert=True,
                )

                return

            # ------------------------------------------------
            # Plan سفارش
            # ------------------------------------------------

            result = await session.execute(
                select(Plan).where(
                    Plan.id == order.plan_id
                )
            )

            order_plan = (
                result.scalar_one_or_none()
            )

            if not order_plan:

                await callback.answer(
                    "❌ پلن تمدید سفارش پیدا نشد.",
                    show_alert=True,
                )

                return

            # ------------------------------------------------
            # مدت
            # ------------------------------------------------

            duration_days = (
                order_plan.duration_days
                or 30
            )

            # ------------------------------------------------
            # تمدید
            # ------------------------------------------------

            from database.crud import extend_subscription

            subscription = await extend_subscription(
                session=session,
                subscription_id=subscription.id,
                duration_days=duration_days,
                new_config_text=None,
                new_subscription_text=None,
            )

            if not subscription:

                logger.error(
                    "Could not extend subscription | "
                    "order_id=%s | "
                    "subscription_id=%s",
                    order_id,
                    subscription_id,
                )

                await callback.answer(
                    "❌ تمدید سرویس انجام نشد.",
                    show_alert=True,
                )

                return

            # ------------------------------------------------
            # تغییر Plan
            # ------------------------------------------------

            subscription.plan_id = (
                order_plan.id
            )

            # ------------------------------------------------
            # وضعیت Order
            # ------------------------------------------------

            order.status = (
                OrderStatus.PAID.value
            )

            await session.commit()

            await session.refresh(
                subscription
            )

            new_expire_date = (
                subscription.expire_date
            )

        else:

            # ------------------------------------------------
            # خرید جدید
            # ------------------------------------------------

            order.status = (
                OrderStatus.PAID.value
            )

            await session.commit()

    # ========================================================
    # RENEWAL
    # ========================================================

    if order_type == "renew":

        try:

            await callback.message.edit_caption(
                caption=(
                    "✅ <b>تمدید با موفقیت انجام شد.</b>\n\n"

                    f"🧾 شماره سفارش: "
                    f"<code>#{order_id}</code>\n\n"

                    f"🏷 نام سرویس: "
                    f"{html.escape(service_name)}\n\n"

                    f"📦 پلن: "
                    f"{html.escape(plan_name)}\n\n"

                    f"⏱ مدت تمدید: "
                    f"{duration_days} روز\n\n"

                    f"📅 تاریخ انقضای جدید: "
                    f"{new_expire_date.strftime('%Y/%m/%d %H:%M')}"
                ),
                reply_markup=None,
            )

        except Exception:

            logger.exception(
                "Could not edit admin renewal message"
            )

        try:

            await bot.send_message(
                chat_id=user_telegram_id,
                text=(
                    "🎉 <b>سرویس شما با موفقیت تمدید شد.</b>\n\n"

                    f"🧾 شماره سفارش: "
                    f"<code>#{order_id}</code>\n\n"

                    f"🏷 <b>نام سرویس:</b> "
                    f"{html.escape(service_name)}\n\n"

                    f"📦 <b>پلن:</b> "
                    f"{html.escape(plan_name)}\n\n"

                    f"⏱ <b>مدت تمدید:</b> "
                    f"{duration_days} روز\n\n"

                    f"📅 <b>تاریخ انقضای جدید:</b> "
                    f"{new_expire_date.strftime('%Y/%m/%d %H:%M')}"
                ),
            )

        except Exception:

            logger.exception(
                "Could not notify user after renewal"
            )

        logger.info(
            "Renewal completed | "
            "order_id=%s | "
            "admin=%s | "
            "subscription_id=%s | "
            "plan=%s | "
            "service_name=%s | "
            "duration_days=%s | "
            "new_expire_date=%s",
            order_id,
            admin_id,
            subscription_id,
            plan_name,
            service_name,
            duration_days,
            new_expire_date,
        )

        await callback.answer(
            "✅ سرویس با موفقیت تمدید شد."
        )

        return

    # ========================================================
    # NEW ORDER
    # ========================================================

    try:

        await callback.message.edit_caption(
            caption=(
                "✅ <b>پرداخت تأیید شد.</b>\n\n"

                f"🧾 شماره سفارش: "
                f"<code>#{order_id}</code>\n\n"

                f"🏷 نام سرویس: "
                f"{html.escape(service_name)}\n\n"

                f"📦 سفارش: "
                f"{html.escape(plan_name)}\n\n"

                "وضعیت: "
                "🔐 <b>در انتظار ارسال کانفیگ</b>"
            ),
            reply_markup=None,
        )

    except Exception:

        logger.exception(
            "Could not edit admin receipt message"
        )

    try:

        await bot.send_message(
            chat_id=user_telegram_id,
            text=(
                "✅ <b>پرداخت شما تأیید شد.</b>\n\n"

                f"🧾 شماره سفارش: "
                f"<code>#{order_id}</code>\n\n"

                f"🏷 <b>نام سرویس:</b> "
                f"{html.escape(service_name)}\n\n"

                "⏳ سفارش شما در حال آماده‌سازی است.\n"
                "کانفیگ پس از آماده شدن برای شما ارسال می‌شود."
            ),
        )

    except Exception:

        logger.exception(
            "Could not notify user after payment approval"
        )

    try:

        started = await start_config_delivery(
            message=callback.message,
            state=state,
            order_id=order_id,
            admin_id=admin_id,
        )

        if not started:

            logger.error(
                "Config delivery could not start | "
                "order_id=%s | admin_id=%s",
                order_id,
                admin_id,
            )

            await callback.message.answer(
                "❌ پرداخت تأیید شد اما نتوانستم "
                "مرحله دریافت کانفیگ را شروع کنم.\n\n"
                f"🧾 سفارش: "
                f"<code>#{order_id}</code>"
            )

            await callback.answer(
                "⚠️ مرحله دریافت کانفیگ شروع نشد.",
                show_alert=True,
            )

            return

    except Exception:

        logger.exception(
            "Could not start config delivery | "
            "order_id=%s | admin_id=%s",
            order_id,
            admin_id,
        )

        await callback.message.answer(
            "❌ پرداخت تأیید شد اما شروع مرحله دریافت "
            "کانفیگ با خطا مواجه شد.\n\n"
            f"🧾 سفارش: "
            f"<code>#{order_id}</code>\n\n"
            "خطا را در bot.log بررسی کن."
        )

        await callback.answer(
            "⚠️ پرداخت تأیید شد ولی شروع ارسال کانفیگ خطا داشت.",
            show_alert=True,
        )

        return

    logger.info(
        "Payment approved | "
        "order_id=%s | "
        "admin=%s | "
        "plan=%s | "
        "service_name=%s",
        order_id,
        admin_id,
        plan_name,
        service_name,
    )

    await callback.answer(
        "✅ پرداخت تأیید شد؛ حالا کانفیگ را ارسال کن."
    )


# ============================================================
# رد پرداخت
# ============================================================

@router.callback_query(
    F.data.startswith("admin_reject:")
)
async def admin_reject(
    callback: CallbackQuery,
    bot: Bot,
):

    if not is_admin_user(
        callback.from_user.id
    ):

        await callback.answer(
            "❌ شما دسترسی ادمین ندارید.",
            show_alert=True,
        )

        return

    try:

        order_id = int(
            callback.data.split(":")[1]
        )

    except (
        ValueError,
        IndexError,
    ):

        await callback.answer(
            "❌ شماره سفارش نامعتبر است.",
            show_alert=True,
        )

        return

    async with get_session() as session:

        order = await get_order(
            session,
            order_id,
        )

        if not order:

            await callback.answer(
                "❌ سفارش پیدا نشد.",
                show_alert=True,
            )

            return

        if (
            order.status
            != OrderStatus.WAITING_ADMIN.value
        ):

            await callback.answer(
                "⚠️ این سفارش قبلاً بررسی شده است.",
                show_alert=True,
            )

            return

        order.status = (
            OrderStatus.REJECTED.value
        )

        await session.commit()

        user_telegram_id = (
            order.user.telegram_id
        )

        plan_name = (
            order.plan.name
            if order.plan
            else "نامشخص"
        )

        service_name = (
            order.service_name
            if order.service_name
            else "بدون نام"
        )

    try:

        await callback.message.edit_caption(
            caption=(
                "❌ <b>پرداخت رد شد.</b>\n\n"

                f"🧾 شماره سفارش: "
                f"<code>#{order_id}</code>\n\n"

                f"🏷 نام سرویس: "
                f"{html.escape(service_name)}\n\n"

                f"📦 سفارش: "
                f"{html.escape(plan_name)}\n\n"

                "وضعیت: پرداخت رد شد."
            ),
            reply_markup=None,
        )

    except Exception:

        logger.exception(
            "Could not edit rejected receipt"
        )

    try:

        await bot.send_message(
            chat_id=user_telegram_id,
            text=(
                "❌ <b>رسید پرداخت شما تأیید نشد.</b>\n\n"

                f"🧾 شماره سفارش: "
                f"<code>#{order_id}</code>\n\n"

                f"🏷 <b>نام سرویس:</b> "
                f"{html.escape(service_name)}\n\n"

                "لطفاً در صورت اشتباه، "
                "مجدداً رسید صحیح را ارسال کنید."
            ),
        )

    except Exception:

        logger.exception(
            "Could not notify user after payment rejection"
        )

    await callback.answer(
        "❌ پرداخت رد شد."
    )


# ============================================================
# لغو سفارش
# ============================================================

@router.callback_query(
    F.data.startswith("cancel_order:")
)
async def cancel_order(
    callback: CallbackQuery,
    state: FSMContext,
):

    try:

        order_id = int(
            callback.data.split(":")[1]
        )

    except (
        ValueError,
        IndexError,
    ):

        await callback.answer(
            "❌ شماره سفارش نامعتبر است.",
            show_alert=True,
        )

        return

    async with get_session() as session:

        order = await get_order(
            session,
            order_id,
        )

        if not order:

            await callback.answer(
                "❌ سفارش پیدا نشد.",
                show_alert=True,
            )

            return

        if (
            not order.user
            or order.user.telegram_id
            != callback.from_user.id
        ):

            await callback.answer(
                "❌ این سفارش متعلق به شما نیست.",
                show_alert=True,
            )

            return

        if (
            order.status
            != OrderStatus.WAITING_RECEIPT.value
        ):

            await callback.answer(
                "⚠️ امکان لغو این سفارش وجود ندارد.",
                show_alert=True,
            )

            return

        order.status = (
            OrderStatus.REJECTED.value
        )

        await session.commit()

    await state.clear()

    await callback.message.edit_text(
        "❌ <b>سفارش لغو شد.</b>\n\n"

        f"🧾 سفارش: "
        f"<code>#{order_id}</code>"
    )

    await callback.answer(
        "سفارش لغو شد."
    )