import asyncio
import os
from telethon import events, Button
import database as db
import keyboards as kb
from state import waiting, tmp
from services.provider_api import provider_api

PAGE_SIZE = 8
TEXT_KEYS = [
    ('welcome_text', '👋 پیام خوش‌آمدگویی'), ('guide_text', '📖 متن راهنما'),
    ('support_username', '🎧 آیدی/لینک پشتیبانی مستقیم'),
    ('charge_info_text', '💳 متن شارژ کیف‌پول (کارت‌به‌کارت + ارز دیجیتال)'),
    ('order_channel_public', '📢 آیدی کانال سفارشات (عمومی)'),
    ('order_channel_private', '🔒 آیدی کانال گزارشات (خصوصی)'),
    ('referral_percent', '🤝 درصد پورسانت رفرال'),
    ('btn_shop', '🔤 عنوان دکمه فروشگاه'),
    ('btn_guide', '🔤 عنوان دکمه راهنما'), ('btn_support', '🔤 عنوان دکمه پشتیبانی'),
    ('btn_account', '🔤 عنوان دکمه حساب من'), ('btn_track', '🔤 عنوان دکمه پیگیری سفارش'),
    ('emoji_category', '🔤 اموجی دسته‌ی اصلی'), ('emoji_subcategory', '🔤 اموجی زیردسته'), ('emoji_product', '🔤 اموجی محصول'),
    ('btn_all_products', '🔤 عنوان دکمه همه محصولات'), ('btn_referral', '🔤 عنوان دکمه رفرال (منوی اصلی)'),
    ('referral_signup_bonus', '🤝 پاداش ثابت به‌ازای هر رفرال جدید (تومان)'),
]
NUMERIC_TEXT_KEYS = {'referral_percent', 'referral_signup_bonus'}
# این کلیدها هنگام ویرایش، موجودیت‌های پیام (شامل اموجی سفارشی/پرمیوم تلگرام) را هم ذخیره می‌کنند.
RICH_TEXT_KEYS = {'welcome_text', 'guide_text', 'charge_info_text'}


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


def _product_view(pid):
    p = db.product(pid)
    if not p:
        return None, None
    txt = (f"📦 {p['name']}\n🗂 دسته: {p['category'] or '—'}\n💵 نرخ (هر ۱۰۰۰): {fmt(p['rate'])}\n"
           f"🔢 حداقل/حداکثر: {p['min_qty']}/{p['max_qty']}\n📝 {p['description'] or '—'}\n"
           f"وضعیت: {'✅ فعال' if p['active'] else '🚫 غیرفعال'}"
           + ('\n🛠 نوع: ثبت دستی (بدون API)' if p['manual'] else ''))
    btns = [
        [Button.inline('✏️ نام', f"a:pf:{pid}:name".encode()), Button.inline('💵 نرخ', f"a:pf:{pid}:rate".encode())],
        [Button.inline('🔢 حداقل', f"a:pf:{pid}:min_qty".encode()), Button.inline('🔢 حداکثر', f"a:pf:{pid}:max_qty".encode())],
        [Button.inline('🗂 دسته‌بندی', f"a:pf:{pid}:category".encode()), Button.inline('📝 توضیحات', f"a:pf:{pid}:description".encode())],
        [Button.inline('🔁 فعال/غیرفعال', f"a:ptoggle:{pid}".encode()), Button.inline('🗑 حذف', f"a:pdel:{pid}".encode())],
        *kb.back(b'a:plist:0'),
    ]
    return txt, btns


def _resolve_category_text(text):
    """متن دسته‌بندی وارد‌شده توسط ادمین را resolve می‌کند.
    فرمت «والد > فرزند» زیردسته می‌سازد/پیدا می‌کند؛ فرمت ساده یعنی دسته‌ی اصلی (سطح بالا)."""
    text = text.strip()
    if '>' in text:
        parent_name, child_name = [p.strip() for p in text.split('>', 1)]
        parent_id = db.add_category(parent_name, parent_id=None)
        return db.add_category(child_name, parent_id=parent_id)
    return db.add_category(text, parent_id=None)


def _ancestor_ids(cid):
    """شناسه‌ی همه‌ی اجداد یک دسته، برای جلوگیری از ایجاد حلقه هنگام جابجایی دسته‌ها."""
    ids = set()
    cur = db.get_category(cid)
    while cur and cur['parent_id']:
        ids.add(cur['parent_id'])
        cur = db.get_category(cur['parent_id'])
    return ids


async def _render_assign(e, gid, selected):
    gcat = db.get_category(gid)
    blocked = _ancestor_ids(gid) | {gid}
    candidates = [c for c in db.categories(parent_id=None, active_only=False) if c['id'] not in blocked]
    if not candidates:
        return await e.edit('دسته‌ی سطح‌بالای دیگری برای انتقال وجود ندارد.', buttons=kb.back(f"a:catv:{gid}".encode()))
    btns = [Button.inline(f"{'☑️' if c['id'] in selected else '⬜'} {c['name']}", f"a:catassigntg:{gid}:{c['id']}".encode()) for c in candidates]
    rows = kb.grid(btns, cols=2)
    rows.append([Button.inline(f'✅ اعمال ({len(selected)} مورد)', f"a:catassignok:{gid}".encode())])
    rows += kb.back(f"a:catv:{gid}".encode())
    return await e.edit(f"📥 دسته‌هایی که می‌خواهید داخل «{gcat['name']}» بروند را تیک بزنید:", buttons=rows)


def register(client, is_admin):

    @client.on(events.NewMessage(pattern=r'^/admin$'))
    async def admin_cmd(e):
        if is_admin(e.sender_id):
            await e.respond('🛠 پنل مدیریت', buttons=kb.admin_menu())

    @client.on(events.CallbackQuery())
    async def admin_callbacks(e):
        d = e.data.decode(); uid = e.sender_id
        if not (d == 'admin' or d.startswith('a:')):
            return
        if not is_admin(uid):
            return await e.answer('⛔ دسترسی ندارید.', alert=True)
        await e.answer()

        if d == 'admin':
            return await e.edit('🛠 پنل مدیریت', buttons=kb.admin_menu())

        a = d[2:] if d.startswith('a:') else ''

        # ---------- API ----------
        if a == 'api':
            return await e.edit('🔌 مدیریت API\nURL و Key در SQLite ذخیره می‌شوند و تغییرشان نیاز به ری‌استارت ندارد.', buttons=kb.api_menu())
        if a in ('url', 'key'):
            waiting[uid] = {'action': f'adm_api_{a}'}
            return await e.respond('🌐 URL جدید را ارسال کنید:' if a == 'url' else '🔑 API Key جدید را ارسال کنید:')
        if a == 'status':
            url = db.get_setting('api_url'); key = db.get_setting('api_key')
            masked = ('•' * max(0, len(key) - 4) + key[-4:]) if key else 'تنظیم نشده'
            return await e.respond(f'🌐 URL: {url or "تنظیم نشده"}\n🔑 Key: {masked}')
        if a == 'test':
            await e.edit('⏳ در حال تست اتصال...')
            r = await provider_api.balance()
            txt = '✅ اتصال برقرار است.' if r.ok else f'❌ اتصال ناموفق بود.\n{r.error}'
            return await e.edit(txt, buttons=kb.back(b'a:api'))
        if a == 'balance':
            await e.edit('⏳ در حال دریافت موجودی...')
            r = await provider_api.balance()
            if r.ok and isinstance(r.data, dict):
                txt = f"💰 {r.data.get('balance', '?')} {r.data.get('currency', '')}"
            else:
                txt = f'❌ دریافت موجودی ناموفق بود.\n{r.error}'
            return await e.edit(txt, buttons=kb.back(b'a:api'))
        if a == 'sync':
            await e.edit('⏳ در حال Sync محصولات...')
            r = await provider_api.services()
            if not r.ok:
                return await e.edit(f'❌ Sync ناموفق بود.\n{r.error}', buttons=kb.back(b'a:api'))
            data = r.data.get('services', r.data) if isinstance(r.data, dict) else r.data
            count = db.services_upsert(data)
            return await e.edit(f'✅ Sync انجام شد: {count} سرویس', buttons=kb.back(b'a:api'))

        # ---------- Products ----------
        if a == 'prod':
            return await e.edit('📦 مدیریت محصولات', buttons=[[Button.inline('➕ افزودن محصول', b'a:padd'), Button.inline('📋 لیست محصولات', b'a:plist:0')], *kb.back(b'admin')])
        if a == 'padd':
            tmp[uid] = {'new_product': {}}
            waiting[uid] = {'action': 'adm_padd_name'}
            return await e.respond('📦 نام محصول را ارسال کنید:\n(برای انصراف /cancel)')
        if a.startswith('plist:'):
            page = int(a.split(':')[1])
            rows = db.products(active_only=False)
            start = page * PAGE_SIZE; chunk = rows[start:start + PAGE_SIZE]
            if not chunk and page > 0:
                page = 0; chunk = rows[:PAGE_SIZE]
            items = [(f"{'✅' if p['active'] else '🚫'} {p['name'][:30]}", f"a:pv:{p['id']}".encode()) for p in chunk]
            btns = kb.smart_grid(items, cols=2)
            btns += kb.pagination_row('a:plist', page, start + PAGE_SIZE < len(rows))
            btns += kb.back(b'a:prod')
            return await e.edit(f'📋 محصولات ({len(rows)})' if rows else 'هنوز محصولی ثبت نشده است.', buttons=btns)
        if a.startswith('pv:'):
            pid = int(a.split(':')[1])
            txt, btns = _product_view(pid)
            if not txt:
                return await e.edit('یافت نشد.', buttons=kb.back(b'a:plist:0'))
            return await e.edit(txt, buttons=btns)
        if a.startswith('pf:'):
            _, pid, field = a.split(':')
            waiting[uid] = {'action': 'adm_pedit', 'pid': int(pid), 'field': field}
            prompts = {'name': 'نام جدید', 'rate': 'نرخ جدید (عدد، هر ۱۰۰۰ عدد)', 'min_qty': 'حداقل جدید',
                       'max_qty': 'حداکثر جدید', 'category': 'نام دسته‌بندی جدید (یا «والد > فرزند» برای زیردسته)',
                       'description': 'توضیحات جدید'}
            return await e.respond(f"✏️ {prompts.get(field, 'مقدار جدید')} را ارسال کنید:\n(برای انصراف /cancel)")
        if a.startswith('ptoggle:'):
            pid = int(a.split(':')[1]); db.toggle_product_active(pid)
            txt, btns = _product_view(pid)
            return await e.edit(txt, buttons=btns)
        if a.startswith('pdel:') and not a.startswith('pdelok:'):
            pid = int(a.split(':')[1])
            return await e.edit('⚠️ از حذف این محصول مطمئن هستید؟', buttons=[[Button.inline('✅ بله، حذف کن', f"a:pdelok:{pid}".encode()), Button.inline('❌ انصراف', f"a:pv:{pid}".encode())]])
        if a.startswith('pdelok:'):
            pid = int(a.split(':')[1]); db.delete_product(pid)
            return await e.edit('🗑 محصول حذف شد.', buttons=kb.back(b'a:plist:0'))

        # ---------- Categories (سلسله‌مراتب چندسطحی: گروه ← دسته ← زیردسته ← محصول) ----------
        if a == 'cat' or a.startswith('cat:'):
            page = int(a.split(':')[1]) if a.startswith('cat:') else 0
            cats = db.categories(parent_id=None, active_only=False)
            emoji_cat = db.get_setting('emoji_category', '🗂')
            start = page * PAGE_SIZE; chunk = cats[start:start + PAGE_SIZE]
            if not chunk and page > 0:
                page = 0; chunk = cats[:PAGE_SIZE]
            items = [(f"{emoji_cat} {c['name']}", f"a:catv:{c['id']}".encode()) for c in chunk]
            btns = kb.smart_grid(items, cols=2)
            btns.insert(0, [Button.inline('➕ افزودن دسته/گروه جدید', b'a:catadd')])
            btns += kb.pagination_row('a:cat', page, start + PAGE_SIZE < len(cats))
            btns += kb.back(b'admin')
            return await e.edit(f'🗂 دسته‌بندی‌های سطح بالا ({len(cats)})' if cats else 'دسته‌بندی‌ای ثبت نشده.', buttons=btns)
        if a == 'catadd':
            waiting[uid] = {'action': 'adm_cat_add'}
            return await e.respond('🗂 نام دسته/گروه جدید را ارسال کنید:\n(این یک دسته‌ی سطح بالا می‌سازد؛ بعداً می‌توانید دسته‌های دیگر را داخل آن جابجا کنید)')
        if a.startswith('catv:'):
            cid = int(a.split(':')[1]); cat = db.get_category(cid)
            if not cat:
                return await e.edit('یافت نشد.', buttons=kb.back(b'a:cat'))
            subs = db.categories(parent_id=cid, active_only=False)
            emoji_sub = db.get_setting('emoji_subcategory', '📁')
            items = [(f"{emoji_sub} {s['name']}", f"a:catv:{s['id']}".encode()) for s in subs]
            btns = kb.smart_grid(items, cols=2)
            btns.insert(0, [Button.inline('➕ افزودن زیردسته جدید', f"a:subadd:{cid}".encode())])
            btns.append([Button.inline('📥 آوردن دسته‌های موجود به اینجا', f"a:catassign:{cid}".encode())])
            btns.append([Button.inline('✏️ تغییر نام', f"a:catren:{cid}".encode()), Button.inline('🗑 حذف', f"a:catdelok:{cid}".encode())])
            back_target = f"a:catv:{cat['parent_id']}".encode() if cat['parent_id'] else b'a:cat'
            btns += kb.back(back_target)
            return await e.edit(f"🗂 {cat['name']} ({len(subs)} زیردسته)", buttons=btns)
        if a.startswith('subadd:'):
            pid = int(a.split(':')[1])
            waiting[uid] = {'action': 'adm_subcat_add', 'parent_id': pid}
            return await e.respond('📁 نام زیردسته جدید را ارسال کنید:')
        if a.startswith('catren:'):
            cid = int(a.split(':')[1]); waiting[uid] = {'action': 'adm_cat_ren', 'cid': cid}
            return await e.respond('✏️ نام جدید را ارسال کنید:')
        if a.startswith('catdelok:'):
            cid = int(a.split(':')[1]); db.delete_category(cid)
            return await e.edit('🗑 حذف شد.', buttons=kb.back(b'a:cat'))

        # ---------- Move existing top-level categories under another one (checklist) ----------
        if a.startswith('catassign:'):
            gid = int(a.split(':')[1])
            tmp[uid] = {'assign': {'target': gid, 'selected': set()}}
            return await _render_assign(e, gid, set())
        if a.startswith('catassigntg:'):
            _, gid, cid = a.split(':'); gid = int(gid); cid = int(cid)
            state_data = tmp.get(uid, {}).get('assign')
            if not state_data or state_data['target'] != gid:
                state_data = {'target': gid, 'selected': set()}
                tmp[uid] = {'assign': state_data}
            sel = state_data['selected']
            sel.symmetric_difference_update({cid})
            return await _render_assign(e, gid, sel)
        if a.startswith('catassignok:'):
            gid = int(a.split(':')[1])
            sel = tmp.get(uid, {}).get('assign', {}).get('selected', set())
            for cid in sel:
                db.set_category_parent(cid, gid)
            tmp.pop(uid, None)
            cat = db.get_category(gid)
            return await e.edit(f"✅ {len(sel)} دسته به «{cat['name']}» منتقل شد.", buttons=kb.back(f"a:catv:{gid}".encode()))

        # ---------- Users ----------
        if a == 'users':
            return await e.edit('👥 مدیریت مشتریان', buttons=[[Button.inline('🔎 جستجو', b'a:usearch'), Button.inline('📋 لیست', b'a:ulist:0')], *kb.back(b'admin')])
        if a == 'usearch':
            waiting[uid] = {'action': 'adm_user_search'}
            return await e.respond('🔎 آیدی عددی یا یوزرنیم را ارسال کنید:')
        if a.startswith('ulist:'):
            page = int(a.split(':')[1])
            rows, total = db.list_users(page=page, per_page=PAGE_SIZE)
            btns = [[Button.inline(f"{'⛔' if u['banned'] else '👤'} {u['username'] or u['telegram_id']}", f"a:uv:{u['telegram_id']}".encode())] for u in rows]
            btns += kb.pagination_row('a:ulist', page, (page + 1) * PAGE_SIZE < total)
            btns += kb.back(b'a:users')
            return await e.edit(f'👥 مشتریان ({total})', buttons=btns)
        if a.startswith('uv:'):
            tid = int(a.split(':')[1]); u = db.get_user(tid)
            if not u:
                return await e.edit('یافت نشد.', buttons=kb.back(b'a:users'))
            _, ocount = db.list_orders(user_id=u['id'], per_page=1)
            txt = (f"👤 کاربر {u['username'] or '—'}\n🆔 {u['telegram_id']}\n💰 موجودی: {fmt(u['balance'])} تومان\n"
                   f"📦 تعداد سفارش‌ها: {ocount}\nوضعیت مسدودی: {'⛔ مسدود' if u['banned'] else '✅ آزاد'}\n"
                   f"وضعیت احراز: {'✅' if u['verified'] else '❌'}")
            btns = [
                [Button.inline('💳 تغییر موجودی', f"a:ubal:{tid}".encode()), Button.inline('🧾 سفارش‌ها', f"a:uorders:{tid}:0".encode())],
                [Button.inline('⛔ مسدود/آزاد', f"a:uban:{tid}".encode()), Button.inline('🔁 تغییر وضعیت احراز', f"a:uverify:{tid}".encode())],
                *kb.back(b'a:ulist:0'),
            ]
            return await e.edit(txt, buttons=btns)
        if a.startswith('uban:'):
            tid = int(a.split(':')[1]); u = db.get_user(tid)
            db.set_banned(tid, not u['banned'])
            return await e.answer('✅ وضعیت تغییر کرد.')
        if a.startswith('uverify:'):
            tid = int(a.split(':')[1]); u = db.get_user(tid)
            db.set_verified(tid, not u['verified'])
            return await e.answer('✅ وضعیت احراز تغییر کرد.')
        if a.startswith('ubal:'):
            tid = int(a.split(':')[1]); waiting[uid] = {'action': 'adm_user_balance', 'tid': tid}
            return await e.respond('💳 مقدار تغییر را ارسال کنید (مثبت برای افزایش، منفی برای کاهش، مثلا: 50000 یا -20000):')
        if a.startswith('uorders:'):
            _, tid, page = a.split(':'); tid = int(tid); page = int(page)
            u = db.get_user(tid)
            rows, total = db.list_orders(user_id=u['id'], page=page, per_page=PAGE_SIZE)
            btns = [[Button.inline(f"#{o['display_no']} {o['product_name'][:20]} • {kb.STATUS_FA.get(o['status'], o['status'])}", f"a:ov:{o['id']}".encode())] for o in rows]
            btns += kb.pagination_row(f'a:uorders:{tid}', page, (page + 1) * PAGE_SIZE < total)
            btns += kb.back(f"a:uv:{tid}".encode())
            return await e.edit(f'🧾 سفارش‌های کاربر ({total})' if rows else 'سفارشی ثبت نشده.', buttons=btns)

        # ---------- Orders ----------
        if a == 'orders':
            btns = [[Button.inline('⏳ در انتظار', b'a:olist:processing:0'), Button.inline('✅ تکمیل شده', b'a:olist:completed:0')],
                    [Button.inline('❌ ناموفق', b'a:olist:failed:0'), Button.inline('📋 همه', b'a:olist:all:0')],
                    [Button.inline('🔢 شماره‌گذاری سفارش‌ها', b'a:ordseq')],
                    *kb.back(b'admin')]
            return await e.edit('🧾 مدیریت سفارش‌ها', buttons=btns)
        if a.startswith('olist:'):
            _, status, page = a.split(':'); page = int(page)
            st = None if status == 'all' else status
            rows, total = db.list_orders(status=st, page=page, per_page=PAGE_SIZE)
            btns = [[Button.inline(f"#{o['display_no']} {o['product_name'][:18]} • {o['username'] or o['user_telegram_id']}", f"a:ov:{o['id']}".encode())] for o in rows]
            btns += kb.pagination_row(f'a:olist:{status}', page, (page + 1) * PAGE_SIZE < total)
            btns += kb.back(b'a:orders')
            return await e.edit(f'🧾 سفارش‌ها ({total})' if rows else 'سفارشی یافت نشد.', buttons=btns)
        if a.startswith('ov:'):
            oid = int(a.split(':')[1]); o = db.get_order(oid)
            if not o:
                return await e.edit('یافت نشد.', buttons=kb.back(b'a:orders'))
            txt = (f"🧾 سفارش #{o['display_no']}\n👤 {o['username'] or o['user_telegram_id']}\n📦 {o['product_name']}\n"
                   f"🔗 {o['link']}\n🔢 تعداد: {o['quantity']}\n💵 مبلغ: {fmt(o['total'])} تومان\n"
                   f"📌 وضعیت: {kb.STATUS_FA.get(o['status'], o['status'])}\n🆔 شناسه پنل: {o['provider_order_id'] or '—'}")
            btns = [
                [Button.inline('✅ تکمیل', f"a:ost:{oid}:completed".encode()), Button.inline('❌ ناموفق', f"a:ost:{oid}:failed".encode())],
                [Button.inline('🚫 لغو', f"a:ost:{oid}:canceled".encode())],
            ]
            if o['provider_order_id']:
                btns.append([Button.inline('🔄 استعلام از پنل', f"a:ochk:{oid}".encode())])
            btns += kb.back(f"a:olist:all:0".encode())
            return await e.edit(txt, buttons=btns)
        if a.startswith('ost:'):
            _, oid, status = a.split(':'); oid = int(oid)
            o = db.get_order(oid)
            if status == 'failed' and o and o['status'] != 'failed':
                db.adjust_balance(o['user_telegram_id'], o['total'])  # refund on manual fail
            db.update_order_status(oid, status)
            if o and status == 'completed' and o['status'] != 'completed':
                try:
                    await client.send_message(o['user_telegram_id'], f"✅ سفارش شما #{o['display_no']} ({o['product_name']}) تکمیل شد.")
                except Exception:
                    pass
            return await e.answer('✅ وضعیت بروزرسانی شد.')
        if a.startswith('ochk:'):
            oid = int(a.split(':')[1]); o = db.get_order(oid)
            if not o or not o['provider_order_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)
            return await e.respond(f"📌 پاسخ پنل: {r.data}")

        # ---------- Identity verification (KYC) ----------
        if a.startswith('vap:'):
            vid = int(a.split(':')[1]); v = db.get_verification(vid)
            if not v or v['status'] != 'pending':
                return await e.answer('قبلاً پردازش شده.', alert=True)
            db.update_verification_status(vid, 'approved')
            db.set_verified(v['user_telegram_id'], True)
            await e.answer('✅ تایید شد.')
            try:
                await client.send_message(v['user_telegram_id'], '✅ احراز هویت شما تایید شد.')
            except Exception:
                pass
            return await e.edit(f"✅ احراز هویت #{vid} تایید شد.")
        if a.startswith('vrj:'):
            vid = int(a.split(':')[1]); v = db.get_verification(vid)
            if not v or v['status'] != 'pending':
                return await e.answer('قبلاً پردازش شده.', alert=True)
            db.update_verification_status(vid, 'rejected')
            await e.answer('❌ رد شد.')
            try:
                await client.send_message(v['user_telegram_id'], '❌ احراز هویت شما رد شد. برای اطلاعات بیشتر با پشتیبانی تماس بگیرید.')
            except Exception:
                pass
            return await e.edit(f"❌ احراز هویت #{vid} رد شد.")

        # ---------- Payment methods (card, wallet address, ...) ----------
        if a == 'pm':
            methods = db.list_payment_methods(active_only=False)
            btns = [[Button.inline(f"{'✅' if m['active'] else '🚫'} {m['name']}", f"a:pmv:{m['id']}".encode())] for m in methods]
            btns.insert(0, [Button.inline('➕ افزودن روش پرداخت', b'a:pmadd')])
            btns += kb.back(b'admin')
            return await e.edit(f'🏦 روش‌های پرداخت ({len(methods)})' if methods else 'هنوز روش پرداختی ثبت نشده.', buttons=btns)
        if a == 'pmadd':
            tmp[uid] = {'new_pm': {}}
            waiting[uid] = {'action': 'adm_pm_name'}
            return await e.respond('🏦 نام روش پرداخت را ارسال کنید (مثلاً: کارت به کارت، ولت ترون USDT):\n(برای انصراف /cancel)')
        if a.startswith('pmv:'):
            pmid = int(a.split(':')[1]); m = db.get_payment_method(pmid)
            if not m:
                return await e.edit('یافت نشد.', buttons=kb.back(b'a:pm'))
            txt = f"🏦 {m['name']}\n📝 {m['details']}\nوضعیت: {'✅ فعال' if m['active'] else '🚫 غیرفعال'}"
            btns = [
                [Button.inline('✏️ نام', f"a:pmf:{pmid}:name".encode()), Button.inline('📝 جزئیات', f"a:pmf:{pmid}:details".encode())],
                [Button.inline('🔁 فعال/غیرفعال', f"a:pmtoggle:{pmid}".encode()), Button.inline('🗑 حذف', f"a:pmdel:{pmid}".encode())],
                *kb.back(b'a:pm'),
            ]
            return await e.edit(txt, buttons=btns)
        if a.startswith('pmf:'):
            _, pmid, field = a.split(':')
            waiting[uid] = {'action': 'adm_pm_edit', 'pmid': int(pmid), 'field': field}
            label = 'نام جدید' if field == 'name' else 'جزئیات جدید (شماره کارت/آدرس ولت و توضیحات)'
            return await e.respond(f'✏️ {label} را ارسال کنید:\n(برای انصراف /cancel)')
        if a.startswith('pmtoggle:'):
            pmid = int(a.split(':')[1]); db.toggle_payment_method(pmid)
            m = db.get_payment_method(pmid)
            txt = f"🏦 {m['name']}\n📝 {m['details']}\nوضعیت: {'✅ فعال' if m['active'] else '🚫 غیرفعال'}"
            btns = [
                [Button.inline('✏️ نام', f"a:pmf:{pmid}:name".encode()), Button.inline('📝 جزئیات', f"a:pmf:{pmid}:details".encode())],
                [Button.inline('🔁 فعال/غیرفعال', f"a:pmtoggle:{pmid}".encode()), Button.inline('🗑 حذف', f"a:pmdel:{pmid}".encode())],
                *kb.back(b'a:pm'),
            ]
            return await e.edit(txt, buttons=btns)
        if a.startswith('pmdel:'):
            pmid = int(a.split(':')[1]); db.delete_payment_method(pmid)
            return await e.edit('🗑 حذف شد.', buttons=kb.back(b'a:pm'))

        # ---------- Charges (wallet top-ups) ----------
        if a == 'charges':
            return await e.edit('💳 مدیریت شارژ کیف پول', buttons=[[Button.inline('⏳ درخواست‌های در انتظار', b'a:clist:0')], *kb.back(b'admin')])
        if a.startswith('clist:'):
            page = int(a.split(':')[1])
            rows, total = db.list_charges(status='pending', page=page, per_page=PAGE_SIZE)
            btns = [[Button.inline(f"#{c['id']} {c['username'] or c['user_telegram_id']} • {fmt(c['amount'])}", f"a:cv:{c['id']}".encode())] for c in rows]
            btns += kb.pagination_row('a:clist', page, (page + 1) * PAGE_SIZE < total)
            btns += kb.back(b'a:charges')
            return await e.edit(f'💳 درخواست‌های در انتظار ({total})' if rows else 'درخواست در انتظاری نیست.', buttons=btns)
        if a.startswith('cv:'):
            chid = int(a.split(':')[1]); c = db.get_charge(chid)
            if not c:
                return await e.edit('یافت نشد.', buttons=kb.back(b'a:clist:0'))
            txt = (f"💳 درخواست #{c['id']}\n👤 {c['username'] or c['user_telegram_id']}\n"
                   f"🏦 روش: {c['method'] or '—'}\n💵 مبلغ: {fmt(c['amount'])} تومان\n📝 {c['receipt_text'] or '—'}\nوضعیت: {c['status']}")
            btns = [[Button.inline('✅ تایید', f"a:cap:{chid}".encode()), Button.inline('❌ رد', f"a:crj:{chid}".encode())], *kb.back(b'a:clist:0')]
            return await e.edit(txt, buttons=btns)
        if a.startswith('cap:'):
            chid = int(a.split(':')[1]); c = db.get_charge(chid)
            if not c or c['status'] != 'pending':
                return await e.answer('قبلاً پردازش شده.', alert=True)
            db.adjust_balance(c['user_telegram_id'], c['amount'])
            db.update_charge_status(chid, 'approved')
            await e.answer('✅ تایید شد.')
            try:
                await client.send_message(c['user_telegram_id'], f"✅ کیف پول شما به مبلغ {fmt(c['amount'])} تومان شارژ شد.")
            except Exception:
                pass
            return await e.edit(f"✅ درخواست #{chid} تایید و اعمال شد.")
        if a.startswith('crj:'):
            chid = int(a.split(':')[1]); c = db.get_charge(chid)
            if not c or c['status'] != 'pending':
                return await e.answer('قبلاً پردازش شده.', alert=True)
            db.update_charge_status(chid, 'rejected')
            await e.answer('❌ رد شد.')
            try:
                await client.send_message(c['user_telegram_id'], f"❌ درخواست شارژ کیف پول شما (#{chid}) رد شد.")
            except Exception:
                pass
            return await e.edit(f"❌ درخواست #{chid} رد شد.")

        # ---------- Gift codes ----------
        if a == 'gift':
            return await e.edit('🎁 مدیریت کدهای هدیه', buttons=[[Button.inline('➕ ساخت کد', b'a:giftadd'), Button.inline('📋 لیست کدها', b'a:giftlist:0')], *kb.back(b'admin')])
        if a == 'giftadd':
            tmp[uid] = {'new_gift': {}}
            waiting[uid] = {'action': 'adm_gift_code'}
            return await e.respond('🎁 کد دلخواه را بفرستید یا "-" برای تولید خودکار:\n(برای انصراف /cancel)')
        if a.startswith('giftlist:'):
            page = int(a.split(':')[1])
            rows, total = db.list_gift_codes(page=page, per_page=PAGE_SIZE)
            btns = [[Button.inline(f"{g['code']} ({g['used_count']}/{g['capacity']}) {'✅' if g['active'] else '🚫'}", f"a:giftv:{g['id']}".encode())] for g in rows]
            btns += kb.pagination_row('a:giftlist', page, (page + 1) * PAGE_SIZE < total)
            btns += kb.back(b'a:gift')
            return await e.edit(f'🎁 کدهای هدیه ({total})' if rows else 'هنوز کدی ساخته نشده.', buttons=btns)
        if a.startswith('giftv:'):
            gid = int(a.split(':')[1]); g = db.get_gift_code_by_id(gid)
            if not g:
                return await e.edit('یافت نشد.', buttons=kb.back(b'a:giftlist:0'))
            txt = f"🎁 کد: {g['code']}\n💵 مبلغ: {fmt(g['amount'])} تومان\n📦 ظرفیت: {g['used_count']}/{g['capacity']}\nوضعیت: {'✅ فعال' if g['active'] else '🚫 غیرفعال'}"
            btns = [[Button.inline('🔁 فعال/غیرفعال', f"a:gifttoggle:{gid}".encode()), Button.inline('🗑 حذف', f"a:giftdel:{gid}".encode())], *kb.back(b'a:giftlist:0')]
            return await e.edit(txt, buttons=btns)
        if a.startswith('gifttoggle:'):
            gid = int(a.split(':')[1]); db.toggle_gift_code(gid)
            return await e.answer('✅ وضعیت تغییر کرد.')
        if a.startswith('giftdel:'):
            gid = int(a.split(':')[1]); db.delete_gift_code(gid)
            return await e.edit('🗑 حذف شد.', buttons=kb.back(b'a:giftlist:0'))

        # ---------- Order sequencing / channels ----------
        if a == 'ordseq':
            waiting[uid] = {'action': 'adm_order_seq'}
            cur = db.get_setting('order_seq_next', '1')
            return await e.respond(f"🔢 شماره سفارش بعدی فعلاً: {cur}\nعدد شروع جدید را ارسال کنید:\n(برای انصراف /cancel)")
        if a.startswith('supreply:'):
            target = int(a.split(':')[1])
            waiting[uid] = {'action': 'adm_support_reply', 'target': target}
            return await e.respond(f'✏️ پاسخ خود را برای کاربر {target} بنویسید:\n(برای انصراف /cancel)')
        if a == 'refbanner':
            waiting[uid] = {'action': 'adm_ref_banner'}
            return await e.respond('🖼 تصویر بنر رفرال را ارسال کنید:\n(برای انصراف /cancel)')

        # ---------- Stats ----------
        if a == 'stats':
            s = db.get_stats()
            top = '\n'.join(f"• {t['name']}: {t['c']} سفارش" for t in s['top']) or '—'
            txt = (f"📊 آمار پلتفرم\n\n👥 کاربران: {s['users']} (مسدود: {s['banned']})\n"
                   f"📦 محصولات فعال: {s['products']}\n🧾 سفارش‌ها: {s['orders']} (در انتظار: {s['pending']}, تکمیل: {s['completed']})\n"
                   f"💵 مجموع فروش: {fmt(s['revenue'])} تومان\n💰 مجموع موجودی کیف پول‌ها: {fmt(s['wallet_total'])} تومان\n"
                   f"💳 درخواست‌های شارژ در انتظار: {s['pending_charges']}\n\n🏆 پرفروش‌ترین‌ها:\n{top}")
            return await e.edit(txt, buttons=kb.back(b'admin'))

        # ---------- Texts & buttons ----------
        if a == 'texts':
            btns = [[Button.inline(label, f"a:tf:{key}".encode())] for key, label in TEXT_KEYS]
            btns.append([Button.inline('🖼 بنر رفرال', b'a:refbanner')])
            btns += kb.back(b'admin')
            return await e.edit('📝 متن‌ها و دکمه‌های قابل تغییر:', buttons=btns)
        if a.startswith('tf:'):
            key = a.split(':', 1)[1]
            cur = db.get_setting(key)
            waiting[uid] = {'action': 'adm_text_edit', 'key': key}
            note = ''
            if key in RICH_TEXT_KEYS:
                note = '\n💡 این متن به کاربر نمایش داده می‌شود؛ می‌توانید داخلش اموجی پرمیوم/سفارشی تلگرام هم بگذارید، دقیقاً حفظ می‌شود.'
            elif key.startswith('btn_'):
                note = '\n⚠️ دکمه‌های شیشه‌ای تلگرام فقط اموجی معمولی را نمایش می‌دهند؛ اموجی پرمیوم/سفارشی در برچسب دکمه کار نمی‌کند (محدودیت خود تلگرام است).'
            return await e.respond(f"مقدار فعلی:\n{cur or '—'}\n\nمقدار جدید را ارسال کنید:{note}\n(برای انصراف /cancel)")

        # ---------- Broadcast ----------
        if a == 'bc':
            waiting[uid] = {'action': 'adm_bc_msg'}
            return await e.respond('📣 متن پیام همگانی را ارسال کنید:\n(برای انصراف /cancel)')
        if a == 'bcsend':
            text = tmp.get(uid, {}).get('bc_text')
            if not text:
                return await e.answer('متنی یافت نشد.', alert=True)
            tmp.pop(uid, None)
            await e.edit('📣 در حال ارسال پیام همگانی...')
            rows, total = db.list_users(page=0, per_page=100000)
            sent = 0
            for u in rows:
                try:
                    await client.send_message(u['telegram_id'], text)
                    sent += 1
                except Exception:
                    pass
                await asyncio.sleep(0.05)
            return await e.respond(f'✅ پیام برای {sent} از {total} کاربر ارسال شد.')
        if a == 'bccancel':
            tmp.pop(uid, None)
            return await e.edit('❌ پیام همگانی لغو شد.', buttons=kb.back(b'admin'))

    @client.on(events.NewMessage())
    async def admin_text_input(e):
        uid = e.sender_id
        if not is_admin(uid) or uid not in waiting:
            return
        st = waiting[uid]
        if not st['action'].startswith('adm_'):
            return
        if e.raw_text and e.raw_text.startswith('/cancel'):
            waiting.pop(uid, None); tmp.pop(uid, None)
            return await e.respond('❌ عملیات لغو شد.')
        action = st['action']
        text = (e.raw_text or '').strip()

        if action == 'adm_ref_banner':
            if not e.photo:
                return await e.respond('❌ لطفاً یک تصویر ارسال کنید.')
            os.makedirs('data', exist_ok=True)
            path = os.path.join('data', 'referral_banner.jpg')
            await e.download_media(file=path)
            db.set_setting('referral_banner_path', path)
            waiting.pop(uid, None)
            return await e.respond('✅ بنر رفرال ذخیره شد.')

        if action == 'adm_pm_name':
            if not text:
                return await e.respond('❌ نام نمی‌تواند خالی باشد.')
            tmp[uid]['new_pm']['name'] = text
            waiting[uid] = {'action': 'adm_pm_details'}
            return await e.respond('📝 جزئیات این روش پرداخت را ارسال کنید (شماره کارت/آدرس ولت و هر توضیح لازم):')
        if action == 'adm_pm_details':
            if not text:
                return await e.respond('❌ جزئیات نمی‌تواند خالی باشد.')
            name = tmp[uid]['new_pm']['name']
            pmid = db.create_payment_method(name, text)
            waiting.pop(uid, None); tmp.pop(uid, None)
            return await e.respond(f"✅ روش پرداخت «{name}» ثبت شد.", buttons=[[Button.inline('مشاهده', f"a:pmv:{pmid}".encode())]])
        if action == 'adm_pm_edit':
            if not text:
                return await e.respond('❌ مقدار نمی‌تواند خالی باشد.')
            db.update_payment_method(st['pmid'], **{st['field']: text})
            waiting.pop(uid, None)
            return await e.respond('✅ بروزرسانی شد.', buttons=[[Button.inline('مشاهده', f"a:pmv:{st['pmid']}".encode())]])

        if action == 'adm_gift_code':
            code = None if text == '-' else text.upper()
            tmp[uid]['new_gift']['code'] = code
            waiting[uid] = {'action': 'adm_gift_amount'}
            return await e.respond('💵 مبلغ هدیه را به تومان ارسال کنید:')
        if action == 'adm_gift_amount':
            try:
                amount = float(text)
            except ValueError:
                return await e.respond('❌ لطفاً یک عدد معتبر ارسال کنید.')
            tmp[uid]['new_gift']['amount'] = amount
            waiting[uid] = {'action': 'adm_gift_capacity'}
            return await e.respond('📦 ظرفیت کد (چند نفر می‌توانند استفاده کنند) را ارسال کنید:')
        if action == 'adm_gift_capacity':
            try:
                capacity = int(text)
                if capacity <= 0:
                    raise ValueError
            except ValueError:
                return await e.respond('❌ لطفاً یک عدد صحیح مثبت ارسال کنید.')
            ng = tmp[uid]['new_gift']
            code, gid = db.create_gift_code(ng['amount'], capacity, code=ng.get('code'))
            waiting.pop(uid, None); tmp.pop(uid, None)
            return await e.respond(f"✅ کد هدیه ساخته شد:\n🎁 {code}\n💵 {fmt(ng['amount'])} تومان\n📦 ظرفیت: {capacity}")

        if action == 'adm_order_seq':
            try:
                n = int(text)
                if n <= 0:
                    raise ValueError
            except ValueError:
                return await e.respond('❌ لطفاً یک عدد صحیح مثبت ارسال کنید.')
            db.set_order_seq_start(n); waiting.pop(uid, None)
            return await e.respond(f'✅ شماره سفارش بعدی از {n} شروع می‌شود.')

        if action == 'adm_support_reply':
            if not text:
                return await e.respond('❌ پیام نمی‌تواند خالی باشد.')
            target = st['target']; waiting.pop(uid, None)
            try:
                await client.send_message(target, f"🎧 پاسخ پشتیبانی:\n\n{text}")
                await e.respond('✅ پاسخ ارسال شد.')
            except Exception as ex:
                await e.respond(f'❌ ارسال ناموفق بود: {ex}')
            return

        if action == 'adm_api_url':
            if not (text.startswith('http://') or text.startswith('https://')):
                return await e.respond('❌ URL باید با http:// یا https:// شروع شود.')
            db.set_setting('api_url', text); waiting.pop(uid, None)
            return await e.respond('✅ API URL ذخیره شد.')
        if action == 'adm_api_key':
            db.set_setting('api_key', text); waiting.pop(uid, None)
            return await e.respond('✅ API Key ذخیره شد.')

        if action == 'adm_padd_name':
            if not text:
                return await e.respond('❌ نام نمی‌تواند خالی باشد.')
            tmp[uid]['new_product']['name'] = text
            waiting[uid] = {'action': 'adm_padd_category'}
            return await e.respond('🗂 نام دسته‌بندی را ارسال کنید. برای زیردسته از فرمت «دسته اصلی > زیردسته» استفاده کنید (مثلاً: تلگرام > ممبر)؛ برای بدون دسته "-" بفرستید:')
        if action == 'adm_padd_category':
            cid = None
            if text and text != '-':
                cid = _resolve_category_text(text)
            tmp[uid]['new_product']['category_id'] = cid
            waiting[uid] = {'action': 'adm_padd_rate'}
            return await e.respond('💵 نرخ را ارسال کنید (عدد، به ازای هر ۱۰۰۰ عدد):')
        if action == 'adm_padd_rate':
            try:
                rate = float(text)
            except ValueError:
                return await e.respond('❌ لطفاً یک عدد معتبر ارسال کنید.')
            tmp[uid]['new_product']['rate'] = rate
            waiting[uid] = {'action': 'adm_padd_min'}
            return await e.respond('🔢 حداقل تعداد را ارسال کنید:')
        if action == 'adm_padd_min':
            try:
                mn = int(text)
            except ValueError:
                return await e.respond('❌ لطفاً یک عدد صحیح ارسال کنید.')
            tmp[uid]['new_product']['min_qty'] = mn
            waiting[uid] = {'action': 'adm_padd_max'}
            return await e.respond('🔢 حداکثر تعداد را ارسال کنید:')
        if action == 'adm_padd_max':
            try:
                mx = int(text)
            except ValueError:
                return await e.respond('❌ لطفاً یک عدد صحیح ارسال کنید.')
            if mx < tmp[uid]['new_product']['min_qty']:
                return await e.respond('❌ حداکثر باید بزرگتر یا مساوی حداقل باشد.')
            tmp[uid]['new_product']['max_qty'] = mx
            waiting[uid] = {'action': 'adm_padd_desc'}
            return await e.respond('📝 توضیحات محصول را ارسال کنید یا برای رد شدن "-" ارسال کنید:')
        if action == 'adm_padd_desc':
            desc = '' if text == '-' else text
            np = tmp[uid]['new_product']
            pid = db.add_manual_product(np['name'], np.get('category_id'), np['rate'], np['min_qty'], np['max_qty'], desc)
            waiting.pop(uid, None); tmp.pop(uid, None)
            return await e.respond(f"✅ محصول «{np['name']}» با شناسه #{pid} ثبت شد.", buttons=[[Button.inline('مشاهده', f"a:pv:{pid}".encode())]])

        if action == 'adm_pedit':
            pid = st['pid']; field = st['field']
            try:
                if field == 'rate':
                    val = float(text)
                elif field in ('min_qty', 'max_qty'):
                    val = int(text)
                elif field == 'category':
                    cid = _resolve_category_text(text)
                    db.update_product(pid, category_id=cid)
                    waiting.pop(uid, None)
                    return await e.respond('✅ دسته‌بندی بروزرسانی شد.', buttons=[[Button.inline('مشاهده', f"a:pv:{pid}".encode())]])
                else:
                    val = text
            except ValueError:
                return await e.respond('❌ مقدار نامعتبر است.')
            db.update_product(pid, **{field: val})
            waiting.pop(uid, None)
            return await e.respond('✅ محصول بروزرسانی شد.', buttons=[[Button.inline('مشاهده', f"a:pv:{pid}".encode())]])

        if action == 'adm_cat_add':
            if not text:
                return await e.respond('❌ نام نمی‌تواند خالی باشد.')
            db.add_category(text, parent_id=None); waiting.pop(uid, None)
            return await e.respond(f'✅ دسته «{text}» اضافه شد.')
        if action == 'adm_subcat_add':
            if not text:
                return await e.respond('❌ نام نمی‌تواند خالی باشد.')
            db.add_category(text, parent_id=st['parent_id']); waiting.pop(uid, None)
            return await e.respond(f'✅ زیردسته «{text}» اضافه شد.')
        if action == 'adm_cat_ren':
            if not text:
                return await e.respond('❌ نام نمی‌تواند خالی باشد.')
            db.rename_category(st['cid'], text); waiting.pop(uid, None)
            return await e.respond('✅ نام به‌روزرسانی شد.')

        if action == 'adm_user_search':
            waiting.pop(uid, None)
            search = text.lstrip('@')
            rows, total = db.list_users(search=search, per_page=10)
            if not rows:
                return await e.respond('کاربری یافت نشد.')
            btns = [[Button.inline(f"{u['username'] or u['telegram_id']}", f"a:uv:{u['telegram_id']}".encode())] for u in rows]
            return await e.respond(f'نتایج جستجو ({total}):', buttons=btns)
        if action == 'adm_user_balance':
            try:
                delta = float(text.replace(',', ''))
            except ValueError:
                return await e.respond('❌ لطفاً یک عدد معتبر ارسال کنید.')
            newbal = db.adjust_balance(st['tid'], delta)
            waiting.pop(uid, None)
            await e.respond(f'✅ موجودی جدید: {fmt(newbal)} تومان')
            try:
                await client.send_message(st['tid'], f"💳 موجودی کیف پول شما {'افزایش' if delta > 0 else 'کاهش'} یافت.\nموجودی جدید: {fmt(newbal)} تومان")
            except Exception:
                pass
            return

        if action == 'adm_text_edit':
            if st['key'] in NUMERIC_TEXT_KEYS:
                try:
                    float(text)
                except ValueError:
                    return await e.respond('❌ لطفاً یک عدد معتبر ارسال کنید.')
            if st['key'] in RICH_TEXT_KEYS:
                db.set_setting_rich(st['key'], text, e.message.entities)
            else:
                db.set_setting(st['key'], text)
            waiting.pop(uid, None)
            return await e.respond('✅ ذخیره شد.')

        if action == 'adm_bc_msg':
            if not text:
                return await e.respond('❌ متن نمی‌تواند خالی باشد.')
            tmp.setdefault(uid, {})['bc_text'] = text
            waiting.pop(uid, None)
            _, total = db.list_users(per_page=1)
            return await e.respond(f'📣 پیش‌نمایش پیام برای {total} کاربر:\n\n{text}',
                                    buttons=[[Button.inline('✅ ارسال', b'a:bcsend'), Button.inline('❌ انصراف', b'a:bccancel')]])
