from telegram import ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton, Update
from telegram.constants import ParseMode
from telegram.ext import ContextTypes


# =========================================================
# پرمیوم ایموجی‌ها
# =========================================================
P_BUY = "5312361253610475399"
P_CARD = "5445353829304387411"
P_SUPPORT = "5789918778921850035"
P_ACCOUNT = "5296369303661067030"
P_HELP = "5444856076954520455"
P_CROWN = "5217822164362739968"

P_EYE = "5792131172410594168"
P_LINK = "5271604874419647061"
P_X = "4994791839895651680"
P_WARN = "4996823372311561500"
P_COIN = "6032713293049633080"
P_DIAMOND = "6032952342339395168"
P_MAIL = "5013050643519112149"
P_FIRE = "5424972470023104089"
P_PIN = "5397782960512444700"
P_PLUS = "5397916757333654639"
P_OK = "4997091399745668102"
P_BACK = "5816717549487788887"

P_MCI = "5965297742614894172"
P_IRANCELL = "5963110689433195255"
P_RIGHTEL = "5965519088049460281"
P_CHECK = "5206607081334906820"


def pemoji(emoji_id: str, fallback: str) -> str:
    return f"<tg-emoji emoji-id='{emoji_id}'>{fallback}</tg-emoji>"


def make_btn(text: str, callback_data: str = None, emoji_id: str = None, style: str = "primary", url: str = None):
    kwargs = {}

    if callback_data:
        kwargs["callback_data"] = callback_data

    if url:
        kwargs["url"] = url

    if emoji_id:
        kwargs["api_kwargs"] = {
            "icon_custom_emoji_id": emoji_id,
            "style": style,
        }

    return InlineKeyboardButton(text=text, **kwargs)


class SharzManager:
    def __init__(
        self,
        *,
        conn,
        cur,
        report_channel_id: int,
        logger,
        now_gregorian_str,
        jalali_datetime_str,
        format_money,
        format_username,
        is_admin,
        get_admin_panel_keyboard,
        get_user,
        change_balance,
        owner_id: int,
    ):
        self.conn = conn
        self.cur = cur
        self.report_channel_id = report_channel_id
        self.logger = logger
        self.now_gregorian_str = now_gregorian_str
        self.jalali_datetime_str = jalali_datetime_str
        self.format_money = format_money
        self.format_username = format_username
        self.is_admin = is_admin
        self.get_admin_panel_keyboard = get_admin_panel_keyboard
        self.get_user = get_user
        self.change_balance = change_balance
        self.owner_id = owner_id
        self.ensure_tables()

    def ensure_tables(self):
        self.cur.execute("""
        CREATE TABLE IF NOT EXISTS charge_codes (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            operator TEXT NOT NULL,
            amount INTEGER NOT NULL,
            pack_title TEXT NOT NULL,
            pack_price INTEGER DEFAULT 0,
            code TEXT NOT NULL,
            added_by INTEGER NOT NULL,
            added_by_username TEXT,
            created_at TEXT NOT NULL,
            is_used INTEGER DEFAULT 0,
            used_by INTEGER DEFAULT NULL,
            used_at TEXT DEFAULT NULL
        )
        """)

        try:
            self.cur.execute("ALTER TABLE charge_codes ADD COLUMN pack_price INTEGER DEFAULT 0")
        except Exception:
            pass

        self.conn.commit()

    def back_keyboard(self):
        return ReplyKeyboardMarkup([["🔙 بازگشت"]], resize_keyboard=True)

    def format_charge_code(self, operator: str, code: str) -> str:
        code = str(code).strip()

        if operator == "همراه اول":
            return f"*140*#{code}#"

        if operator == "ایرانسل":
            return f"*141*{code}#"

        if operator == "رایتل":
            return f"*140*{code}#"

        return code

    def add_charge_operator_keyboard(self):
        return ReplyKeyboardMarkup(
            [
                ["📞 افزودن شارژ همراه اول"],
                ["📱 افزودن شارژ ایرانسل"],
                ["🌐 افزودن شارژ رایتل"],
                ["🔙 بازگشت"],
            ],
            resize_keyboard=True
        )

    def mci_pack_keyboard(self):
        return ReplyKeyboardMarkup(
            [
                ["1 پک 20 هزار تومانی - 5 کد شارژ"],
                ["2 پک 20 هزار تومانی - 10 کد شارژ"],
                ["3 پک 20 هزار تومانی - 15 کد شارژ"],
                ["5 پک 20 هزار تومانی - 25 کد شارژ"],
                ["1 پک 50 هزار تومانی - 5 کد شارژ"],
                ["2 پک 50 هزار تومانی - 10 کد شارژ"],
                ["🔙 بازگشت"],
            ],
            resize_keyboard=True
        )

    def simple_operator_pack_keyboard(self):
        return ReplyKeyboardMarkup(
            [
                ["1 پک 20 هزار تومانی - 5 کد شارژ"],
                ["2 پک 20 هزار تومانی - 10 کد شارژ"],
                ["3 پک 20 هزار تومانی - 15 کد شارژ"],
                ["5 پک 20 هزار تومانی - 25 کد شارژ"],
                ["🔙 بازگشت"],
            ],
            resize_keyboard=True
        )

    def get_pack_info(self, operator: str, text: str):
        packs = {
            "1 پک 20 هزار تومانی - 5 کد شارژ": {
                "amount": 20000,
                "count": 5,
                "title": text,
                "key": "p20_1"
            },
            "2 پک 20 هزار تومانی - 10 کد شارژ": {
                "amount": 20000,
                "count": 10,
                "title": text,
                "key": "p20_2"
            },
            "3 پک 20 هزار تومانی - 15 کد شارژ": {
                "amount": 20000,
                "count": 15,
                "title": text,
                "key": "p20_3"
            },
            "5 پک 20 هزار تومانی - 25 کد شارژ": {
                "amount": 20000,
                "count": 25,
                "title": text,
                "key": "p20_5"
            },
            "1 پک 50 هزار تومانی - 5 کد شارژ": {
                "amount": 50000,
                "count": 5,
                "title": text,
                "key": "p50_1"
            },
            "2 پک 50 هزار تومانی - 10 کد شارژ": {
                "amount": 50000,
                "count": 10,
                "title": text,
                "key": "p50_2"
            },
        }

        if text not in packs:
            return None

        if operator in {"ایرانسل", "رایتل"} and "50 هزار" in text:
            return None

        return packs[text]

    def pack_by_key(self, operator: str, key: str):
        all_packs = [
            {
                "amount": 20000,
                "count": 5,
                "title": "1 پک 20 هزار تومانی - 5 کد شارژ",
                "key": "p20_1"
            },
            {
                "amount": 20000,
                "count": 10,
                "title": "2 پک 20 هزار تومانی - 10 کد شارژ",
                "key": "p20_2"
            },
            {
                "amount": 20000,
                "count": 15,
                "title": "3 پک 20 هزار تومانی - 15 کد شارژ",
                "key": "p20_3"
            },
            {
                "amount": 20000,
                "count": 25,
                "title": "5 پک 20 هزار تومانی - 25 کد شارژ",
                "key": "p20_5"
            },
            {
                "amount": 50000,
                "count": 5,
                "title": "1 پک 50 هزار تومانی - 5 کد شارژ",
                "key": "p50_1"
            },
            {
                "amount": 50000,
                "count": 10,
                "title": "2 پک 50 هزار تومانی - 10 کد شارژ",
                "key": "p50_2"
            },
        ]

        for pack in all_packs:
            if pack["key"] == key:
                if operator in {"ایرانسل", "رایتل"} and pack["amount"] == 50000:
                    return None
                return pack

        return None

    def operator_key_to_name(self, key: str):
        return {
            "mci": "همراه اول",
            "irancell": "ایرانسل",
            "rightel": "رایتل",
        }.get(key)

    def operator_name_to_key(self, name: str):
        return {
            "همراه اول": "mci",
            "ایرانسل": "irancell",
            "رایتل": "rightel",
        }.get(name)

    def parse_price(self, text: str):
        cleaned = (
            text.replace(",", "")
            .replace("٬", "")
            .replace("تومان", "")
            .replace("تومن", "")
            .strip()
        )

        if not cleaned.isdigit():
            return None

        price = int(cleaned)

        if price <= 0:
            return None

        return price

    async def start_add_charge(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        user_id = update.effective_user.id

        if not self.is_admin(user_id):
            await update.message.reply_text(
                f"{pemoji(P_X, '❌')} دسترسی ندارید.",
                parse_mode=ParseMode.HTML
            )
            return

        context.user_data.clear()
        context.user_data["flow"] = "admin_charge"
        context.user_data["charge_step"] = "choose_operator"

        await update.message.reply_text(
            f"{pemoji(P_PLUS, '➕')} <b>افزودن شارژ</b>\n\n"
            f"{pemoji(P_PIN, '📌')} نوع شارژ را انتخاب کن:",
            parse_mode=ParseMode.HTML,
            reply_markup=self.add_charge_operator_keyboard()
        )

    async def handle_charge_steps(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool:
        if not update.message:
            return False

        user = update.effective_user
        text = (update.message.text or "").strip()

        if not self.is_admin(user.id):
            return False

        if context.user_data.get("flow") != "admin_charge":
            return False

        step = context.user_data.get("charge_step")

        if text == "🔙 بازگشت":
            if step == "choose_operator":
                context.user_data.clear()
                await update.message.reply_text(
                    f"{pemoji(P_OK, '✅')} به پنل مدیریت برگشتی.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=self.get_admin_panel_keyboard(user.id)
                )
                return True

            if step == "choose_pack":
                context.user_data["charge_step"] = "choose_operator"
                context.user_data.pop("operator", None)

                await update.message.reply_text(
                    f"{pemoji(P_OK, '✅')} برگشتی به انتخاب اپراتور.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=self.add_charge_operator_keyboard()
                )
                return True

            if step in {"wait_codes", "wait_price"}:
                operator = context.user_data.get("operator")
                context.user_data["charge_step"] = "choose_pack"
                context.user_data.pop("pack", None)
                context.user_data.pop("pending_codes", None)

                kb = self.mci_pack_keyboard() if operator == "همراه اول" else self.simple_operator_pack_keyboard()

                await update.message.reply_text(
                    f"{pemoji(P_OK, '✅')} برگشتی به انتخاب پک.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=kb
                )
                return True

            context.user_data.clear()
            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} به پنل مدیریت برگشتی.",
                parse_mode=ParseMode.HTML,
                reply_markup=self.get_admin_panel_keyboard(user.id)
            )
            return True

        if step == "choose_operator":
            operator_map = {
                "📞 افزودن شارژ همراه اول": "همراه اول",
                "📱 افزودن شارژ ایرانسل": "ایرانسل",
                "🌐 افزودن شارژ رایتل": "رایتل",
            }

            if text not in operator_map:
                await update.message.reply_text(
                    f"{pemoji(P_WARN, '⚠️')} از دکمه‌های همین منو استفاده کن.",
                    parse_mode=ParseMode.HTML
                )
                return True

            operator = operator_map[text]
            context.user_data["operator"] = operator
            context.user_data["charge_step"] = "choose_pack"

            kb = self.mci_pack_keyboard() if operator == "همراه اول" else self.simple_operator_pack_keyboard()

            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} اپراتور انتخاب شد: <b>{operator}</b>\n\n"
                f"{pemoji(P_PIN, '📌')} حالا نوع پک را انتخاب کن:",
                parse_mode=ParseMode.HTML,
                reply_markup=kb
            )
            return True

        if step == "choose_pack":
            operator = context.user_data.get("operator")
            pack = self.get_pack_info(operator, text)

            if not pack:
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} پک نامعتبر است. از دکمه‌های همین منو استفاده کن.",
                    parse_mode=ParseMode.HTML
                )
                return True

            context.user_data["pack"] = pack
            context.user_data["charge_step"] = "wait_codes"

            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} <b>پک انتخاب شد</b>\n\n"
                f"{pemoji(P_BUY, '🛒')} {pack['title']}\n\n"
                f"{pemoji(P_PIN, '📌')} لطفاً دقیقاً <b>{pack['count']}</b> کد شارژ را بفرست.\n\n"
                f"{pemoji(P_MAIL, '✉')} هر کد را در یک خط جدا بفرست.",
                parse_mode=ParseMode.HTML,
                reply_markup=self.back_keyboard()
            )
            return True

        if step == "wait_codes":
            pack = context.user_data.get("pack") or {}
            expected_count = int(pack.get("count", 0))
            codes = [line.strip() for line in text.splitlines() if line.strip()]

            if len(codes) != expected_count:
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} <b>تعداد کدها اشتباه است.</b>\n\n"
                    f"{pemoji(P_PIN, '📌')} باید دقیقاً <b>{expected_count}</b> کد بفرستی.\n\n"
                    f"{pemoji(P_WARN, '⚠️')} الان <b>{len(codes)}</b> کد فرستادی.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=self.back_keyboard()
                )
                return True

            context.user_data["pending_codes"] = codes
            context.user_data["charge_step"] = "wait_price"

            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} <b>{expected_count}</b> کد دریافت شد.\n\n"
                f"{pemoji(P_COIN, '🪙')} حالا قیمت کل همین <b>{expected_count}</b> کد شارژ را به تومان بفرست.\n\n"
                f"{pemoji(P_PIN, '📌')} مثال:\n\n"
                f"<b>50000</b>",
                parse_mode=ParseMode.HTML,
                reply_markup=self.back_keyboard()
            )
            return True

        if step == "wait_price":
            operator = context.user_data.get("operator")
            pack = context.user_data.get("pack") or {}
            codes = context.user_data.get("pending_codes") or []

            pack_price = self.parse_price(text)

            if pack_price is None:
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} قیمت نامعتبر است.\n"
                    f"{pemoji(P_PIN, '📌')} فقط عدد تومان بفرست. مثال:\n\n"
                    f"<b>50000</b>",
                    parse_mode=ParseMode.HTML,
                    reply_markup=self.back_keyboard()
                )
                return True

            expected_count = int(pack.get("count", 0))
            amount = int(pack.get("amount", 0))
            pack_title = pack.get("title", "")
            added_by_username = self.format_username(user.username)

            for code in codes:
                self.cur.execute("""
                    INSERT INTO charge_codes (
                        operator, amount, pack_title, pack_price, code,
                        added_by, added_by_username, created_at, is_used
                    )
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0)
                """, (
                    operator,
                    amount,
                    pack_title,
                    pack_price,
                    code,
                    user.id,
                    added_by_username,
                    self.now_gregorian_str()
                ))

            self.conn.commit()

            report_text = (
                f"{pemoji(P_PLUS, '➕')} <b>شارژ جدید ثبت شد</b>\n\n"
                f"{pemoji(P_CROWN, '👑')} ثبت‌کننده: <b>{user.id}</b>\n\n"
                f"{pemoji(P_LINK, '🔗')} یوزرنیم: <b>{added_by_username}</b>\n\n"
                f"{pemoji(P_BUY, '🛒')} اپراتور: <b>{operator}</b>\n\n"
                f"{pemoji(P_COIN, '🪙')} مبلغ اسمی هر شارژ: <b>{self.format_money(amount)}</b> تومان\n\n"
                f"{pemoji(P_PIN, '📌')} نوع پک: <b>{pack_title}</b>\n\n"
                f"{pemoji(P_MAIL, '✉')} تعداد کدها: <b>{expected_count}</b>\n\n"
                f"{pemoji(P_DIAMOND, '💎')} قیمت کل ثبت‌شده: <b>{self.format_money(pack_price)}</b> تومان\n\n"
                f"{pemoji(P_FIRE, '🔥')} زمان: <b>{self.jalali_datetime_str()}</b>"
            )

            try:
                await context.bot.send_message(
                    chat_id=self.report_channel_id,
                    text=report_text,
                    parse_mode=ParseMode.HTML
                )
            except Exception as e:
                self.logger.warning("charge report failed: %s", e)

            context.user_data["charge_step"] = "choose_pack"
            context.user_data.pop("pack", None)
            context.user_data.pop("pending_codes", None)

            kb = self.mci_pack_keyboard() if operator == "همراه اول" else self.simple_operator_pack_keyboard()

            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} <b>{expected_count}</b> کد شارژ با موفقیت ثبت شد.\n\n"
                f"{pemoji(P_COIN, '🪙')} قیمت کل: <b>{self.format_money(pack_price)}</b> تومان",
                parse_mode=ParseMode.HTML,
                reply_markup=kb
            )
            return True

        return False

    def get_available_pack_price(self, operator: str, pack: dict):
        self.cur.execute("""
            SELECT pack_price, COUNT(*) AS cnt
            FROM charge_codes
            WHERE operator = ?
              AND amount = ?
              AND pack_title = ?
              AND is_used = 0
              AND pack_price > 0
            GROUP BY pack_price
            HAVING cnt >= ?
            ORDER BY id DESC
            LIMIT 1
        """, (operator, pack["amount"], pack["title"], pack["count"]))

        row = self.cur.fetchone()

        if not row:
            return None

        return int(row["pack_price"])

    def get_user_pack_keyboard(self, operator: str):
        operator_key = self.operator_name_to_key(operator)

        packs = [
            {
                "amount": 20000,
                "count": 5,
                "title": "1 پک 20 هزار تومانی - 5 کد شارژ",
                "key": "p20_1"
            },
            {
                "amount": 20000,
                "count": 10,
                "title": "2 پک 20 هزار تومانی - 10 کد شارژ",
                "key": "p20_2"
            },
            {
                "amount": 20000,
                "count": 15,
                "title": "3 پک 20 هزار تومانی - 15 کد شارژ",
                "key": "p20_3"
            },
            {
                "amount": 20000,
                "count": 25,
                "title": "5 پک 20 هزار تومانی - 25 کد شارژ",
                "key": "p20_5"
            },
        ]

        if operator == "همراه اول":
            packs.extend([
                {
                    "amount": 50000,
                    "count": 5,
                    "title": "1 پک 50 هزار تومانی - 5 کد شارژ",
                    "key": "p50_1"
                },
                {
                    "amount": 50000,
                    "count": 10,
                    "title": "2 پک 50 هزار تومانی - 10 کد شارژ",
                    "key": "p50_2"
                },
            ])

        rows = []

        for pack in packs:
            price = self.get_available_pack_price(operator, pack)

            if price is None:
                btn_text = f"{pack['title']} | ناموجود"
                callback = "charge_unavailable"
                rows.append([
                    make_btn(
                        btn_text,
                        callback_data=callback,
                        emoji_id=P_X,
                        style="danger"
                    )
                ])
            else:
                btn_text = f"{pack['title']} | {self.format_money(price)} تومان"
                callback = f"buycharge:{operator_key}:{pack['key']}"
                rows.append([
                    make_btn(
                        btn_text,
                        callback_data=callback,
                        emoji_id=P_CHECK,
                        style="success"
                    )
                ])

        rows.append([
            make_btn(
                "بازگشت",
                callback_data="charge_back",
                emoji_id=P_BACK,
                style="danger"
            )
        ])

        return InlineKeyboardMarkup(rows)

    async def show_user_charge_packs(self, update: Update, context: ContextTypes.DEFAULT_TYPE, operator: str):
        query = update.callback_query
        await query.answer()

        context.user_data.clear()
        context.user_data["flow"] = "user_buy_charge_packs"
        context.user_data["buy_operator"] = operator

        text = (
            f"{pemoji(P_BUY, '🛒')} <b>خرید شارژ</b>\n\n"
            f"{pemoji(P_PIN, '📌')} اپراتور انتخابی: <b>{operator}</b>\n\n"
            f"{pemoji(P_EYE, '👀')} پک موردنظر را انتخاب کن:"
        )

        try:
            await query.message.edit_text(
                text,
                parse_mode=ParseMode.HTML,
                reply_markup=self.get_user_pack_keyboard(operator)
            )
            context.user_data["buy_pack_message_id"] = query.message.message_id
        except Exception:
            sent = await query.message.reply_text(
                text,
                parse_mode=ParseMode.HTML,
                reply_markup=self.get_user_pack_keyboard(operator)
            )
            context.user_data["buy_pack_message_id"] = sent.message_id

    async def charge_back_callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE, home_keyboard):
        query = update.callback_query
        await query.answer()

        try:
            await query.message.delete()
        except Exception:
            pass

        await self.delete_buy_messages(context, query.message.chat_id)

        context.user_data.clear()
        await query.message.reply_text(
            f"{pemoji(P_OK, '✅')} <b>منوی کاربر</b>",
            parse_mode=ParseMode.HTML,
            reply_markup=home_keyboard
        )

    async def delete_buy_messages(self, context: ContextTypes.DEFAULT_TYPE, chat_id: int):
        for key in (
            "buy_pack_message_id",
            "buy_back_message_id",
            "last_user_panel_msg_id"
        ):

            msg_id = context.user_data.get(key)

            if msg_id:
                try:
                    await context.bot.delete_message(
                        chat_id=chat_id,
                        message_id=msg_id
                    )
                except Exception:
                    pass

    async def buy_charge_pack(self, update: Update, context: ContextTypes.DEFAULT_TYPE, home_keyboard):
        query = update.callback_query
        await query.answer()

        user = query.from_user
        data = query.data or ""

        if data == "charge_unavailable":
            await query.answer("این پک فعلاً موجود نیست.", show_alert=True)
            return

        try:
            _, operator_key, pack_key = data.split(":")
        except Exception:
            await query.answer("درخواست نامعتبر است.", show_alert=True)
            return

        operator = self.operator_key_to_name(operator_key)

        if not operator:
            await query.answer("اپراتور نامعتبر است.", show_alert=True)
            return

        pack = self.pack_by_key(operator, pack_key)

        if not pack:
            await query.answer("پک نامعتبر است.", show_alert=True)
            return

        pack_price = self.get_available_pack_price(operator, pack)

        if pack_price is None:
            await query.answer("این پک موجود نیست.", show_alert=True)
            return

        user_row = self.get_user(user.id)

        if not user_row:
            await self.delete_buy_messages(context, query.message.chat_id)
            context.user_data.clear()
            await query.message.reply_text(
                f"{pemoji(P_X, '❌')} کاربر پیدا نشد.",
                parse_mode=ParseMode.HTML,
                reply_markup=home_keyboard
            )
            return

        balance = int(user_row["balance"] or 0)

        if balance < pack_price:
            await self.delete_buy_messages(context, query.message.chat_id)
            context.user_data.clear()
            context.user_data["flow"] = "user_buy_charge_result"

            sent = await query.message.reply_text(
                f"{pemoji(P_X, '❌')} <b>موجودی کافی نیست.</b>\n\n"
                f"{pemoji(P_CARD, '💳')} لطفاً از قسمت افزایش موجودی اقدام کنید.",
                parse_mode=ParseMode.HTML,
                reply_markup=self.back_keyboard()
            )
            context.user_data["last_user_panel_msg_id"] = sent.message_id
            return

        self.cur.execute("""
            SELECT *
            FROM charge_codes
            WHERE operator = ?
              AND amount = ?
              AND pack_title = ?
              AND pack_price = ?
              AND is_used = 0
            ORDER BY id ASC
            LIMIT ?
        """, (
            operator,
            pack["amount"],
            pack["title"],
            pack_price,
            pack["count"]
        ))

        codes = self.cur.fetchall()

        if len(codes) < pack["count"]:
            await query.answer("موجودی این پک تمام شده است.", show_alert=True)
            return

        ok, new_balance = self.change_balance(
            user_id=user.id,
            amount=-pack_price,
            admin_id=self.owner_id,
            tx_type="charge_purchase",
            description=f"خرید شارژ {operator} - {pack['title']}"
        )

        if not ok:
            await self.delete_buy_messages(context, query.message.chat_id)
            context.user_data.clear()
            sent = await query.message.reply_text(
                f"{pemoji(P_X, '❌')} {new_balance}",
                parse_mode=ParseMode.HTML,
                reply_markup=home_keyboard
            )
            context.user_data["last_user_panel_msg_id"] = sent.message_id
            return

        now = self.now_gregorian_str()
        code_ids = [row["id"] for row in codes]

        for code_id in code_ids:
            self.cur.execute("""
                UPDATE charge_codes
                SET is_used = 1, used_by = ?, used_at = ?
                WHERE id = ?
            """, (user.id, now, code_id))

        self.cur.execute("""
            INSERT INTO orders (user_id, operator, amount, created_at)
            VALUES (?, ?, ?, ?)
        """, (
            user.id,
            operator,
            pack_price,
            now
        ))

        self.conn.commit()

        await self.delete_buy_messages(context, query.message.chat_id)

        code_lines = "\n".join([
            f"<code>{self.format_charge_code(operator, row['code'])}</code>"
            for row in codes
        ])

        report_code_lines = "\n".join([
            f"<code>{self.format_charge_code(operator, row['code'])}</code>"
            for row in codes
        ])

        context.user_data.clear()
        context.user_data["flow"] = "user_buy_charge_result"

        sent = await query.message.reply_text(
            f"{pemoji(P_OK, '✅')} <b>خرید شارژ با موفقیت انجام شد.</b>\n\n"
            f"{pemoji(P_BUY, '🛒')} اپراتور: <b>{operator}</b>\n\n"
            f"{pemoji(P_PIN, '📌')} پک: <b>{pack['title']}</b>\n\n"
            f"{pemoji(P_COIN, '🪙')} مبلغ پرداختی: <b>{self.format_money(pack_price)}</b> تومان\n\n"
            f"{pemoji(P_CARD, '💳')} موجودی جدید: <b>{self.format_money(new_balance)}</b> تومان\n\n"
            f"{pemoji(P_FIRE, '🔥')} <b>کدهای شارژ:</b>\n\n{code_lines}",
            parse_mode=ParseMode.HTML,
            reply_markup=self.back_keyboard()
        )

        context.user_data["charge_code_result_msg_id"] = sent.message_id

        report_text = (
            f"{pemoji(P_BUY, '🛒')} <b>خرید شارژ توسط کاربر</b>\n\n"
            f"{pemoji(P_ACCOUNT, '🔒')} کاربر: <b>{user.first_name or 'کاربر'}</b>\n\n"
            f"{pemoji(P_PIN, '📌')} آیدی عددی: <b>{user.id}</b>\n\n"
            f"{pemoji(P_LINK, '🔗')} یوزرنیم: <b>{self.format_username(user.username)}</b>\n\n"
            f"{pemoji(P_BUY, '🛒')} اپراتور: <b>{operator}</b>\n\n"
            f"{pemoji(P_MAIL, '✉')} پک: <b>{pack['title']}</b>\n\n"
            f"{pemoji(P_COIN, '🪙')} مبلغ پرداختی: <b>{self.format_money(pack_price)}</b> تومان\n\n"
            f"{pemoji(P_CARD, '💳')} موجودی جدید: <b>{self.format_money(new_balance)}</b> تومان\n\n"
            f"{pemoji(P_FIRE, '🔥')} کدهای خریداری‌شده:\n\n{report_code_lines}\n\n"
            f"{pemoji(P_PIN, '📌')} زمان: <b>{self.jalali_datetime_str()}</b>"
        )

        try:
            await context.bot.send_message(
                chat_id=self.report_channel_id,
                text=report_text,
                parse_mode=ParseMode.HTML
            )
        except Exception as e:
            self.logger.warning("purchase report failed: %s", e)
