import os
from telethon import events, Button
from telethon.tl.types import InputMediaDice
import database as db
import keyboards as kb
import state
from state import waiting, tmp
from services.provider_api import provider_api
from config import ADMIN_IDS

PAGE_SIZE = 8
CAT_PAGE_SIZE = 10
PROD_PAGE_SIZE = 10


def fmt_money(n):
    try:
        return f"{n:,.0f}"
    except Exception:
        return str(n)


def calc_total(rate, qty):
    # provider convention: rate = price per 1000 units
    return round(float(rate) * float(qty) / 1000.0, 2)


def _map_status(s):
    s = s.lower()
    if any(k in s for k in ('complet', 'finish')):
        return 'completed'
    if any(k in s for k in ('cancel', 'reject')):
        return 'canceled'
    if any(k in s for k in ('partial', 'fail', 'error')):
        return 'failed'
    if any(k in s for k in ('progress', 'process', 'pending', 'in_progress')):
        return 'processing'
    return None


def _support_link():
    link = db.get_setting('support_username') or 'https://t.me/SUPULT'
    if link.startswith('@'):
        return f'https://t.me/{link[1:]}'
    if not link.startswith('http'):
        return f'https://t.me/{link}'
    return link


def register(client, is_admin):

    @client.on(events.NewMessage(pattern=r'^/start(?:\s+(.+))?$'))
    async def start(e):
        sender = await e.get_sender()
        payload = e.pattern_match.group(1)
        referrer_tid = None
        if payload and payload.startswith('ref_'):
            try:
                rid = int(payload[4:])
                if rid != e.sender_id and db.get_user(rid):
                    referrer_tid = rid
            except ValueError:
                pass
        existing = db.get_user(e.sender_id)
        is_new = not existing
        db.upsert_user(sender, referrer_tid=None if existing else referrer_tid)
        u = db.get_user(e.sender_id)
        if u and u['banned']:
            return await e.respond('⛔ دسترسی شما به ربات مسدود شده است.')
        if is_new and referrer_tid:
            try:
                bonus = float(db.get_setting('referral_signup_bonus') or 0)
            except ValueError:
                bonus = 0
            if bonus > 0:
                db.adjust_balance(referrer_tid, bonus)
                try:
                    await client.send_message(referrer_tid, f"🎉 یک نفر با لینک دعوت شما وارد ربات شد و {fmt_money(bonus)} تومان به کیف پولت اضافه شد!")
                except Exception:
                    pass
        text, entities = db.get_setting_rich('welcome_text', 'سلام 👋\nبه فروشگاه خوش آمدید.')
        await e.respond(text, buttons=kb.main_menu(), formatting_entities=entities)

    @client.on(events.NewMessage(pattern=r'^/cancel$'))
    async def cancel_cmd(e):
        waiting.pop(e.sender_id, None); tmp.pop(e.sender_id, None)
        await e.respond('❌ عملیات لغو شد.')

    def blocked(uid):
        u = db.get_user(uid)
        return bool(u and u['banned'])

    @client.on(events.CallbackQuery())
    async def user_callbacks(e):
        d = e.data.decode(); uid = e.sender_id
        if blocked(uid):
            return await e.answer('⛔ دسترسی شما مسدود شده است.', alert=True)

        if d == 'home':
            await e.answer()
            return await e.edit('منوی اصلی', buttons=kb.main_menu())

        if d == 'guide':
            await e.answer()
            text, entities = db.get_setting_rich('guide_text')
            return await e.edit(text, buttons=kb.back(), formatting_entities=entities)

        # ---------------- support ----------------
        if d == 'support':
            await e.answer()
            return await e.edit('🎧 پشتیبانی', buttons=[
                [Button.url('💬 گفتگوی مستقیم', _support_link())],
                [Button.inline('✉️ ارسال پیام از طریق ربات', b'supportmsg')],
                *kb.back(),
            ])
        if d == 'supportmsg':
            await e.answer()
            waiting[uid] = {'action': 'support_msg'}
            return await e.edit('✉️ پیام خود را بنویسید، مستقیم برای پشتیبانی ارسال می‌شود:\n(برای انصراف /cancel)', buttons=kb.back(b'support'))

        # ---------------- order tracking ----------------
        if d == 'track':
            await e.answer()
            waiting[uid] = {'action': 'track_code'}
            return await e.edit('🔍 شماره سفارش (کد پیگیری) را ارسال کنید:\n(برای انصراف /cancel)', buttons=kb.back())

        # ---------------- shop / catalog ----------------
        if d == 'shop' or d.startswith('shop:'):
            await e.answer()
            page = int(d.split(':')[1]) if ':' in d else 0
            cats = db.categories(parent_id=None)
            if not cats:
                return await _render_products(e, db.products(), 0, back_cb=b'home')
            emoji_cat = db.get_setting('emoji_category', '🗂')
            start = page * CAT_PAGE_SIZE
            chunk = cats[start:start + CAT_PAGE_SIZE]
            if not chunk and page > 0:
                page = 0; chunk = cats[:CAT_PAGE_SIZE]
            items = [(f"{emoji_cat} {c['name']}", f"c:{c['id']}:0".encode()) for c in chunk]
            rows = kb.smart_grid(items, cols=2)
            rows.append([Button.inline(db.get_setting('btn_all_products', '📋 همه محصولات'), b'c:all:0')])
            rows += kb.pagination_row('shop', page, start + CAT_PAGE_SIZE < len(cats))
            rows += kb.back()
            return await e.edit('🛍 یک دسته‌بندی را انتخاب کنید:', buttons=rows)

        if d.startswith('c:'):
            await e.answer()
            parts = d.split(':')
            key = parts[1]; page = int(parts[2]) if len(parts) > 2 else 0
            if key == 'all':
                return await _render_products(e, db.products(), page, back_cb=b'shop:0', prefix='c:all')
            cid = int(key)
            cat = db.get_category(cid)
            subs = db.categories(parent_id=cid)
            if subs:
                emoji_sub = db.get_setting('emoji_subcategory', '📁')
                start = page * CAT_PAGE_SIZE
                chunk = subs[start:start + CAT_PAGE_SIZE]
                if not chunk and page > 0:
                    page = 0; chunk = subs[:CAT_PAGE_SIZE]
                items = [(f"{emoji_sub} {s['name']}", f"c:{s['id']}:0".encode()) for s in chunk]
                rows = kb.smart_grid(items, cols=2)
                rows += kb.pagination_row(f'c:{cid}', page, start + CAT_PAGE_SIZE < len(subs))
                rows += kb.back(b'shop:0')
                return await e.edit(f"🗂 {cat['name']} — یک زیردسته را انتخاب کنید:", buttons=rows)
            ps = db.products(category_id=cid)
            parent_cb = f"c:{cat['parent_id']}:0".encode() if cat and cat['parent_id'] else b'shop:0'
            return await _render_products(e, ps, page, back_cb=parent_cb, prefix=f'c:{cid}')

        if d.startswith('p:'):
            await e.answer()
            p = db.product(int(d[2:]))
            if not p or not p['active']:
                return await e.answer('محصول یافت نشد.', alert=True)
            txt = (f"📦 {p['name']}\n🗂 دسته: {p['category'] or '—'}\n"
                   f"💵 قیمت هر ۱۰۰۰ عدد: {fmt_money(p['rate'])} تومان\n"
                   f"🔢 حداقل: {p['min_qty']} | حداکثر: {p['max_qty']}\n"
                   f"📝 {p['description'] or 'بدون توضیح'}")
            back_cb = f"c:{p['category_id']}:0".encode() if p['category_id'] else b'c:all:0'
            return await e.edit(txt, buttons=[[Button.inline('🛒 خرید', f"buy:{p['id']}".encode())], *kb.back(back_cb)])

        # ---------------- buy flow: quantity first, then link ----------------
        if d.startswith('buy:'):
            await e.answer()
            pid = int(d[4:]); p = db.product(pid)
            if not p or not p['active']:
                return await e.answer('محصول یافت نشد.', alert=True)
            waiting[uid] = {'action': 'buy_qty', 'pid': pid}
            return await e.edit(f"📦 {p['name']}\n\n🔢 تعداد مورد نظر را وارد کنید (بین {p['min_qty']} تا {p['max_qty']}):\n(برای انصراف /cancel)")

        if d == 'cancelbuy':
            tmp.pop(uid, None); waiting.pop(uid, None)
            await e.answer('لغو شد.')
            return await e.edit('❌ سفارش لغو شد.', buttons=kb.main_menu())

        if d == 'confirmbuy':
            return await _confirm_purchase(client, e, uid)

        # ---------------- account hub ----------------
        if d == 'account':
            await e.answer()
            u = db.get_user(uid)
            bal = u['balance'] if u else 0
            uname = f"@{u['username']}" if u and u['username'] else '—'
            name = (u['first_name'] or '') if u else ''
            txt = f"👤 {name}\n🔖 {uname}\n🆔 {uid}\n\n💰 موجودی کیف پول: {fmt_money(bal)} تومان"
            return await e.edit(txt, buttons=kb.account_menu(bool(u['verified']) if u else False))

        if d == 'mystatus':
            await e.answer()
            u = db.get_user(uid)
            s = db.get_user_financial_summary(u['id'], uid)
            oc = s['order_counts']
            total_orders = sum(oc.values())
            txt = (f"📊 وضعیت حساب\n\n"
                   f"🗓 عضویت از: {u['created_at'][:10]}\n"
                   f"🪪 احراز هویت: {'✅ بله' if u['verified'] else '❌ خیر'}\n\n"
                   f"📦 مجموع سفارش‌ها: {total_orders}\n"
                   f"⏳ در انتظار: {oc.get('pending', 0)}\n"
                   f"⚙️ در حال پردازش: {oc.get('processing', 0)}\n"
                   f"✅ تکمیل‌شده: {oc.get('completed', 0)}\n"
                   f"❌ ناموفق: {oc.get('failed', 0)}\n"
                   f"🚫 لغوشده: {oc.get('canceled', 0)}\n\n"
                   f"💰 موجودی فعلی: {fmt_money(s['balance'])} تومان")
            return await e.edit(txt, buttons=kb.back(b'account'))

        if d.startswith('mytx:'):
            await e.answer()
            page = int(d.split(':')[1])
            u = db.get_user(uid)
            rows, total = db.list_charges(status='approved', user_id=u['id'], page=page, per_page=PAGE_SIZE)
            if not rows:
                return await e.edit('هنوز تراکنش موفقی ثبت نشده.', buttons=kb.back(b'account'))
            lines = ['💳 تراکنش‌های موفق شما:\n']
            for ch in rows:
                lines.append(f"#{ch['id']} • {fmt_money(ch['amount'])} تومان • {ch['method'] or '—'} • {ch['updated_at'][:10]}")
            btns = kb.pagination_row('mytx', page, (page + 1) * PAGE_SIZE < total)
            btns += kb.back(b'account')
            return await e.edit('\n'.join(lines), buttons=btns)

        if d == 'myledger':
            await e.answer()
            u = db.get_user(uid)
            s = db.get_user_financial_summary(u['id'], uid)
            net = s['topped_up'] - s['spent']
            txt = (f"🧮 حسابدار من\n\n"
                   f"💰 موجودی فعلی: {fmt_money(s['balance'])} تومان\n"
                   f"⬆️ مجموع شارژ تایید‌شده: {fmt_money(s['topped_up'])} تومان\n"
                   f"⬇️ مجموع خرج‌شده در سفارش‌ها: {fmt_money(s['spent'])} تومان\n"
                   f"📐 خالص: {fmt_money(net)} تومان")
            return await e.edit(txt, buttons=kb.back(b'account'))

        if d == 'verify_info':
            u = db.get_user(uid)
            if u and u['verified']:
                return await e.answer('✅ حساب شما احراز هویت شده است.', alert=True)
            if u and db.get_pending_verification(u['id']):
                return await e.answer('⏳ درخواست احراز هویت شما در حال بررسی است.', alert=True)
            await e.answer()
            waiting[uid] = {'action': 'verify_name'}
            return await e.edit('📝 برای احراز هویت، نام و نام خانوادگی کامل خود را ارسال کنید:\n(برای انصراف /cancel)', buttons=kb.back(b'account'))

        if d == 'giftcode':
            await e.answer()
            waiting[uid] = {'action': 'giftcode'}
            return await e.edit('🎁 کد هدیه را ارسال کنید:\n(برای انصراف /cancel)', buttons=kb.back(b'account'))

        if d == 'challenge':
            if not db.check_challenge_available(uid):
                return await e.answer('🎲 امروز قبلاً چالش رو انجام دادی. فردا دوباره سر بزن!', alert=True)
            await e.answer()
            try:
                dice_msg = await client.send_message(uid, file=InputMediaDice(emoticon='🎲'))
                value = dice_msg.media.value
            except Exception as ex:
                return await e.respond(f'❌ مشکلی در انداختن تاس پیش اومد: {ex}')
            reward = value * 50
            db.adjust_balance(uid, reward)
            db.mark_challenge_used(uid)
            return await e.respond(f"🎲 عدد {value} اومد!\n💰 {fmt_money(reward)} تومان به کیف پولت اضافه شد.\nفردا دوباره سر بزن!", buttons=kb.back(b'account'))

        if d == 'chargewallet':
            await e.answer()
            methods = db.list_payment_methods()
            if methods:
                btns = [[Button.inline(m['name'], f"chargepm:{m['id']}".encode())] for m in methods]
                btns += kb.back(b'account')
                return await e.edit('🏦 روش پرداخت را انتخاب کنید:', buttons=btns)
            info, entities = db.get_setting_rich('charge_info_text')
            if not info:
                return await e.edit('💳 در حال حاضر امکان شارژ کیف پول فراهم نیست، با پشتیبانی تماس بگیرید.', buttons=kb.back(b'account'))
            waiting[uid] = {'action': 'charge_amount', 'method': None}
            full = f"{info}\n\n💵 مبلغ واریزی را به تومان ارسال کنید:\n(برای انصراف /cancel)"
            return await e.edit(full, buttons=kb.back(b'account'), formatting_entities=entities)

        if d.startswith('chargepm:'):
            await e.answer()
            pmid = int(d.split(':')[1]); m = db.get_payment_method(pmid)
            if not m or not m['active']:
                return await e.answer('این روش پرداخت دیگر در دسترس نیست.', alert=True)
            waiting[uid] = {'action': 'charge_amount', 'method': m['name']}
            return await e.edit(f"🏦 {m['name']}\n📝 {m['details']}\n\n💵 مبلغ واریزی را به تومان ارسال کنید:\n(برای انصراف /cancel)", buttons=kb.back(b'chargewallet'))

        if d == 'transfer':
            await e.answer()
            waiting[uid] = {'action': 'transfer_target'}
            return await e.edit('🔁 آیدی عددی گیرنده را ارسال کنید:\n(برای انصراف /cancel)', buttons=kb.back(b'account'))

        if d == 'referral':
            await e.answer()
            pct = db.get_setting('referral_percent', '0')
            try:
                bonus = float(db.get_setting('referral_signup_bonus') or 0)
            except ValueError:
                bonus = 0
            link = f"https://t.me/{state.bot_username}?start=ref_{uid}" if state.bot_username else '—'
            txt = (f"🤝 با هر خرید دوستانی که با لینک شما وارد ربات بشن، {pct}٪ از مبلغ خریدشون "
                   f"به‌صورت رایگان به کیف پولت اضافه می‌شه!")
            if bonus > 0:
                txt += f"\n🎁 همین که یک نفر با لینکت وارد ربات بشه هم {fmt_money(bonus)} تومان هدیه می‌گیری!"
            txt += f"\n\n🔗 لینک دعوت شما:\n{link}"
            banner = db.get_setting('referral_banner_path')
            if banner and os.path.exists(banner):
                try:
                    await client.send_file(uid, banner, caption=txt, buttons=kb.back(b'home'))
                    return
                except Exception:
                    pass
            return await e.edit(txt, buttons=kb.back(b'home'))

        if d.startswith('myorders:'):
            await e.answer()
            page = int(d.split(':')[1])
            u = db.get_user(uid)
            rows, total = db.list_orders(user_id=u['id'], page=page, per_page=PAGE_SIZE)
            if not rows:
                return await e.edit('شما هنوز سفارشی ثبت نکرده‌اید.', buttons=kb.back(b'account'))
            lines = ['🧾 سفارش‌های شما:\n']
            btns = []
            for o in rows:
                lines.append(f"#{o['display_no']} • {o['product_name']} • {kb.STATUS_FA.get(o['status'], o['status'])}")
                btns.append([Button.inline(f"مشاهده #{o['display_no']}", f"ord:{o['id']}".encode())])
            has_next = (page + 1) * PAGE_SIZE < total
            btns += kb.pagination_row('myorders', page, has_next)
            btns += kb.back(b'account')
            return await e.edit('\n'.join(lines), buttons=btns)

        if d.startswith('ord:'):
            await e.answer()
            oid = int(d.split(':')[1]); o = db.get_order(oid)
            u = db.get_user(uid)
            if not o or (u and o['user_id'] != u['id']):
                return await e.answer('یافت نشد.', alert=True)
            txt = (f"🧾 سفارش #{o['display_no']}\n📦 {o['product_name']}\n🔗 {o['link']}\n"
                   f"🔢 تعداد: {o['quantity']}\n💵 مبلغ: {fmt_money(o['total'])} تومان\n"
                   f"📌 وضعیت: {kb.STATUS_FA.get(o['status'], o['status'])}")
            btns = []
            if o['provider_order_id']:
                btns.append([Button.inline('🔄 بروزرسانی وضعیت', f"ordchk:{o['id']}".encode())])
            btns += kb.back(b'myorders:0')
            return await e.edit(txt, buttons=btns)

        if d.startswith('ordchk:'):
            oid = int(d.split(':')[1]); o = db.get_order(oid)
            u = db.get_user(uid)
            if not o or (u and o['user_id'] != u['id']):
                return await e.answer('یافت نشد.', alert=True)
            r = await provider_api.status(order=o['provider_order_id'])
            if not r.ok:
                return await e.answer('❌ خطا در دریافت وضعیت.', alert=True)
            status_raw = str((r.data or {}).get('status', '')).lower()
            mapped = _map_status(status_raw)
            if mapped and mapped != o['status']:
                db.update_order_status(oid, mapped)
            await e.answer('وضعیت بروزرسانی شد ✅')
            o = db.get_order(oid)
            txt = (f"🧾 سفارش #{o['display_no']}\n📦 {o['product_name']}\n🔗 {o['link']}\n"
                   f"🔢 تعداد: {o['quantity']}\n💵 مبلغ: {fmt_money(o['total'])} تومان\n"
                   f"📌 وضعیت: {kb.STATUS_FA.get(o['status'], o['status'])}")
            return await e.edit(txt, buttons=[[Button.inline('🔄 بروزرسانی وضعیت', f"ordchk:{o['id']}".encode())]] + kb.back(b'myorders:0'))

    @client.on(events.NewMessage())
    async def user_text_input(e):
        uid = e.sender_id
        if e.raw_text and e.raw_text.startswith('/'):
            return
        if uid not in waiting:
            return
        st = waiting[uid]
        if st['action'].startswith('adm_'):
            return  # admin flow handles this
        action = st['action']

        if action == 'buy_qty':
            p = db.product(st['pid'])
            if not p or not p['active']:
                waiting.pop(uid, None)
                return await e.respond('❌ این محصول دیگر موجود نیست.')
            try:
                qty = int(e.raw_text.strip())
            except ValueError:
                return await e.respond('❌ لطفاً یک عدد صحیح ارسال کنید.')
            if qty < p['min_qty'] or qty > p['max_qty']:
                return await e.respond(f"❌ تعداد باید بین {p['min_qty']} و {p['max_qty']} باشد.")
            waiting[uid] = {'action': 'buy_link', 'pid': p['id'], 'qty': qty}
            return await e.respond('🔗 لینک/آیدی سفارش خود را ارسال کنید:')

        if action == 'buy_link':
            link = e.raw_text.strip()
            if not link:
                return await e.respond('❌ لینک نامعتبر است. دوباره ارسال کنید.')
            p = db.product(st['pid'])
            if not p or not p['active']:
                waiting.pop(uid, None)
                return await e.respond('❌ این محصول دیگر موجود نیست.')
            total = calc_total(p['rate'], st['qty'])
            waiting.pop(uid, None)
            tmp[uid] = {'pid': p['id'], 'link': link, 'qty': st['qty'], 'total': total}
            u = db.get_user(uid)
            bal = u['balance'] if u else 0
            txt = (f"🧾 پیش‌فاکتور\n📦 {p['name']}\n🔗 {link}\n🔢 تعداد: {st['qty']}\n"
                   f"💵 مبلغ قابل پرداخت: {fmt_money(total)} تومان\n💰 موجودی کیف پول: {fmt_money(bal)} تومان")
            btns = [[Button.inline('✅ تایید و پرداخت', b'confirmbuy'), Button.inline('❌ انصراف', b'cancelbuy')]]
            if bal < total:
                btns.insert(0, [Button.inline('➕ افزایش موجودی', b'chargewallet')])
            return await e.respond(txt, buttons=btns)

        if action == 'charge_amount':
            try:
                amount = float(e.raw_text.strip().replace(',', ''))
                if amount <= 0:
                    raise ValueError
            except ValueError:
                return await e.respond('❌ لطفاً یک مبلغ معتبر ارسال کنید.')
            waiting[uid] = {'action': 'charge_receipt', 'amount': amount, 'method': st.get('method')}
            return await e.respond('📎 حالا رسید پرداخت را به‌صورت عکس یا متن ارسال کنید:')

        if action == 'charge_receipt':
            amount = st['amount']; method = st.get('method')
            receipt_text = e.raw_text.strip() if e.raw_text else None
            receipt_file_id = 'photo' if e.photo else None
            u = db.get_user(uid)
            chid = db.create_charge(u['id'], amount, method=method, receipt_text=receipt_text, receipt_file_id=receipt_file_id)
            waiting.pop(uid, None)
            await e.respond('✅ درخواست شارژ کیف پول شما ثبت شد و پس از تایید ادمین اعمال می‌شود.')
            for aid in ADMIN_IDS:
                try:
                    txt = f"💳 درخواست شارژ جدید #{chid}\n👤 کاربر: {uid}\n🏦 روش: {method or '—'}\n💵 مبلغ: {fmt_money(amount)} تومان"
                    if e.photo:
                        await client.send_message(aid, txt, buttons=[[Button.inline('✅ تایید', f'a:cap:{chid}'.encode()), Button.inline('❌ رد', f'a:crj:{chid}'.encode())]])
                        await client.forward_messages(aid, e.message)
                    else:
                        txt += f"\n📝 رسید: {receipt_text or '—'}"
                        await client.send_message(aid, txt, buttons=[[Button.inline('✅ تایید', f'a:cap:{chid}'.encode()), Button.inline('❌ رد', f'a:crj:{chid}'.encode())]])
                except Exception:
                    pass
            return

        if action == 'giftcode':
            code = e.raw_text.strip()
            u = db.get_user(uid)
            ok, val = db.redeem_gift_code(u['id'], uid, code)
            waiting.pop(uid, None)
            if ok:
                return await e.respond(f"🎉 کد هدیه با موفقیت اعمال شد!\n💰 {fmt_money(val)} تومان به کیف پولت اضافه شد.")
            return await e.respond(f"❌ {val}")

        if action == 'verify_name':
            name = e.raw_text.strip() if e.raw_text else ''
            if not name:
                return await e.respond('❌ لطفاً نام معتبر ارسال کنید.')
            tmp.setdefault(uid, {})['verify'] = {'full_name': name}
            waiting[uid] = {'action': 'verify_phone'}
            return await e.respond('📱 شماره موبایل خود را ارسال کنید:')

        if action == 'verify_phone':
            phone = e.raw_text.strip() if e.raw_text else ''
            if not phone:
                return await e.respond('❌ لطفاً شماره موبایل معتبر ارسال کنید.')
            tmp[uid]['verify']['phone'] = phone
            waiting[uid] = {'action': 'verify_national_id'}
            return await e.respond('🪪 کد ملی خود را ارسال کنید:')

        if action == 'verify_national_id':
            nid = e.raw_text.strip() if e.raw_text else ''
            if not nid:
                return await e.respond('❌ لطفاً کد ملی معتبر ارسال کنید.')
            data = tmp[uid]['verify']
            u = db.get_user(uid)
            vid = db.create_verification(u['id'], data['full_name'], data['phone'], nid)
            waiting.pop(uid, None); tmp.pop(uid, None)
            await e.respond('✅ درخواست احراز هویت شما ثبت شد و پس از بررسی ادمین نتیجه اعلام می‌شود.')
            for aid in ADMIN_IDS:
                try:
                    await client.send_message(
                        aid,
                        f"🪪 درخواست احراز هویت جدید #{vid}\n👤 {data['full_name']}\n📱 {data['phone']}\n🔢 کد ملی: {nid}\n🆔 کاربر: {uid}",
                        buttons=[[Button.inline('✅ تایید', f'a:vap:{vid}'.encode()), Button.inline('❌ رد', f'a:vrj:{vid}'.encode())]])
                except Exception:
                    pass
            return

        if action == 'transfer_target':
            try:
                target = int(e.raw_text.strip())
            except ValueError:
                return await e.respond('❌ آیدی عددی نامعتبر است.')
            if target == uid:
                return await e.respond('❌ نمی‌تونی به خودت انتقال بدی.')
            if not db.get_user(target):
                return await e.respond('❌ این کاربر ربات را استارت نکرده. آیدی عددی را بررسی کنید.')
            waiting[uid] = {'action': 'transfer_amount', 'target': target}
            return await e.respond('💰 مبلغ انتقال را وارد کنید (تومان):')

        if action == 'transfer_amount':
            try:
                amount = float(e.raw_text.strip().replace(',', ''))
                if amount <= 0:
                    raise ValueError
            except ValueError:
                return await e.respond('❌ لطفاً یک مبلغ معتبر ارسال کنید.')
            target = st['target']
            ok, err = db.transfer_balance(uid, target, amount)
            waiting.pop(uid, None)
            if not ok:
                return await e.respond(f'❌ {err}')
            await e.respond(f'✅ مبلغ {fmt_money(amount)} تومان به کاربر {target} منتقل شد.')
            try:
                await client.send_message(target, f'💰 مبلغ {fmt_money(amount)} تومان از طرف یک کاربر به کیف پولت اضافه شد.')
            except Exception:
                pass
            return

        if action == 'track_code':
            try:
                no = int(e.raw_text.strip().lstrip('#'))
            except ValueError:
                return await e.respond('❌ شماره سفارش نامعتبر است.')
            u = db.get_user(uid)
            o = db.get_order_by_display_no(no, user_id=u['id'] if u else None)
            waiting.pop(uid, None)
            if not o:
                return await e.respond('❌ سفارشی با این شماره برای شما یافت نشد.')
            txt = f"🧾 سفارش #{o['display_no']}\n📦 {o['product_name']}\n📌 وضعیت: {kb.STATUS_FA.get(o['status'], o['status'])}"
            if o['provider_order_id']:
                r = await provider_api.status(order=o['provider_order_id'])
                if r.ok and isinstance(r.data, dict):
                    mapped = _map_status(str(r.data.get('status', '')))
                    if mapped and mapped != o['status']:
                        db.update_order_status(o['id'], mapped)
                    txt += f"\n📡 وضعیت لحظه‌ای پنل: {r.data.get('status')}"
            return await e.respond(txt)

        if action == 'support_msg':
            text = e.raw_text.strip() if e.raw_text else ''
            if not text:
                return await e.respond('❌ پیام نمی‌تواند خالی باشد.')
            waiting.pop(uid, None)
            await e.respond('✅ پیام شما برای پشتیبانی ارسال شد.')
            u = db.get_user(uid)
            uname = f"@{u['username']}" if u and u['username'] else str(uid)
            for aid in ADMIN_IDS:
                try:
                    await client.send_message(aid, f"✉️ پیام پشتیبانی از {uname} ({uid}):\n\n{text}",
                                               buttons=[[Button.inline('↩️ پاسخ', f"a:supreply:{uid}".encode())]])
                except Exception:
                    pass
            return


async def _confirm_purchase(client, e, uid):
    order = tmp.get(uid)
    if not order:
        return await e.answer('سفارش منقضی شده، دوباره تلاش کنید.', alert=True)
    p = db.product(order['pid'])
    if not p or not p['active']:
        tmp.pop(uid, None)
        return await e.answer('این محصول دیگر موجود نیست.', alert=True)
    if not db.try_charge(uid, order['total']):
        return await e.answer('❌ موجودی کیف پول کافی نیست.', alert=True)

    u = db.get_user(uid)
    if p['manual']:
        oid = db.create_order(u['id'], p['id'], order['link'], order['qty'], order['total'], status='pending')
        o = db.get_order(oid)
        msg = f"✅ سفارش {o['display_no']} ثبت شد!\nاین محصول به‌صورت دستی توسط ادمین پردازش می‌شود."
        for aid in ADMIN_IDS:
            try:
                await client.send_message(aid, f"🆕 سفارش دستی جدید #{o['display_no']}\n📦 {p['name']}\n👤 {uid}\n🔗 {order['link']}\n🔢 {order['qty']}")
            except Exception:
                pass
    else:
        oid = db.create_order(u['id'], p['id'], order['link'], order['qty'], order['total'], status='processing')
        r = await provider_api.add(service=p['service_id'], link=order['link'], quantity=order['qty'])
        if r.ok and isinstance(r.data, dict) and r.data.get('order'):
            db.update_order_status(oid, 'processing', provider_order_id=str(r.data['order']))
            o = db.get_order(oid)
            msg = f"✅ سفارش {o['display_no']} ثبت شد!\nوضعیت را از «👤 حساب من ← ۱۰ سفارش اخیر» پیگیری کنید."
        else:
            db.adjust_balance(uid, order['total'])  # refund
            db.update_order_status(oid, 'failed', note=str(r.error))
            tmp.pop(uid, None)
            await e.answer()
            return await e.edit(f"❌ ثبت سفارش در سامانه ارائه‌دهنده ناموفق بود و مبلغ به کیف پول بازگشت.\nخطا: {r.error}", buttons=kb.back())

    # --- order channels: public (generic) + private (full detail) ---
    pub = db.get_setting('order_channel_public')
    if pub:
        try:
            await client.send_message(pub, f"🛒 سفارش جدید #{o['display_no']}\n📦 {p['name']}\n🔢 تعداد: {order['qty']}")
        except Exception:
            pass
    priv = db.get_setting('order_channel_private')
    if priv:
        uname = f"@{u['username']}" if u['username'] else '—'
        try:
            await client.send_message(priv, f"🛒 سفارش #{o['display_no']}\n👤 {uname} ({uid})\n📦 {p['name']}\n"
                                             f"🔗 {order['link']}\n🔢 {order['qty']}\n💵 {fmt_money(order['total'])} تومان")
        except Exception:
            pass

    # --- referral commission on the referrer's wallet ---
    if u['referrer_tid']:
        try:
            pct = float(db.get_setting('referral_percent') or 0)
        except ValueError:
            pct = 0
        if pct > 0:
            commission = round(order['total'] * pct / 100, 2)
            if commission > 0:
                db.adjust_balance(u['referrer_tid'], commission)
                try:
                    await client.send_message(u['referrer_tid'], f"🎉 یکی از دوستانت خرید کرد و {fmt_money(commission)} تومان به کیف پولت اضافه شد!")
                except Exception:
                    pass

    tmp.pop(uid, None)
    await e.answer()
    return await e.edit(msg, buttons=kb.back())


def _products_text(ps):
    return 'محصولی موجود نیست؛ بعداً دوباره سر بزنید.' if not ps else '🛍 یک محصول را انتخاب کنید:'


def _product_label(p, emoji):
    name = p['name']
    if len(name) > 40:
        name = name[:37] + '…'
    return f"{emoji} {name}"


async def _render_products(e, ps, page, back_cb, prefix='c:all'):
    if not ps:
        return await e.edit(_products_text(ps), buttons=kb.back(back_cb))
    emoji_prod = db.get_setting('emoji_product', '🛒')
    start = page * PROD_PAGE_SIZE
    chunk = ps[start:start + PROD_PAGE_SIZE]
    if not chunk and page > 0:
        page = 0; chunk = ps[:PROD_PAGE_SIZE]
    items = [(_product_label(p, emoji_prod), f"p:{p['id']}".encode()) for p in chunk]
    rows = kb.smart_grid(items, cols=2)
    rows += kb.pagination_row(prefix, page, start + PROD_PAGE_SIZE < len(ps))
    rows += kb.back(back_cb)
    return await e.edit(_products_text(ps), buttons=rows)
