import logging
import os
import sqlite3

from telegram import (
    Update,
    ReplyKeyboardMarkup,
    InlineKeyboardMarkup,
    InlineKeyboardButton,
)
from telegram.ext import (
    Application,
    CommandHandler,
    MessageHandler,
    CallbackQueryHandler,
    ContextTypes,
    filters,
)

TOKEN = "8671387511:AAF-0uhijAkiyVdeWlyJnfaIrhJgldf_Mgs"
ADMIN_ID = 1375533119
DB_PATH = os.path.join(os.path.dirname(__file__), "data", "bot.db")
CHANNEL = "@v2_ghostvpn"

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# ── Module-level FSM ──────────────────────────────────────────────────────────
USER_STATE: dict[int, dict] = {}
# admin_message_id → user_id  (for native Telegram reply routing)
SUPPORT_MSG_MAP: dict[int, int] = {}

# ═════════════════════════════════════════════════════════════════════════════
#  KEYBOARDS
# ═════════════════════════════════════════════════════════════════════════════
def get_main_menu(uid):
    u = db_get_user(uid)
    verified = u and u.get("verified")
    keyboard = [
        ["🛒 خرید سرویس", "🧪 اکانت تست"],
        ["👤 پروفایل", "💰 کیف پول"],
        ["📦 سرویس‌های من", "🎧 پشتیبانی"],
    ]
    if not verified:
        keyboard.append(["📩 درخواست احراز هویت", "📋 قوانین"])
    else:
        keyboard.append(["📋 قوانین"])
    return ReplyKeyboardMarkup(keyboard, resize_keyboard=True)

def get_admin_keyboard():
    status = setting("bot_status") or "on"
    toggle_label = "🔴 خاموش کردن ربات" if status == "on" else "🟢 روشن کردن ربات"
    status_line = "🟢 ربات: روشن" if status == "on" else "🔴 ربات: خاموش"
    return InlineKeyboardMarkup(
        [
            [InlineKeyboardButton(f"⚡ {status_line} ← {toggle_label}", callback_data="admin_toggle_bot")],
            [InlineKeyboardButton("📦 سفارشات در انتظار", callback_data="admin_pending")],
            [InlineKeyboardButton("💳 درخواست‌های شارژ", callback_data="admin_charges")],
            [
                InlineKeyboardButton(
                    "🪪 درخواست‌های احراز هویت", callback_data="admin_verifs"
                )
            ],
            [InlineKeyboardButton("📊 همه سفارش‌ها", callback_data="admin_all_orders")],
            [
                InlineKeyboardButton("➕ افزودن پلن", callback_data="admin_add_plan"),
                InlineKeyboardButton("📝 مشاهده پلن‌ها", callback_data="admin_view_plans"),
            ],
            [InlineKeyboardButton("🗑 حذف پلن", callback_data="admin_delete_plan")],
            [
                InlineKeyboardButton("➕ افزودن کانفیگ", callback_data="admin_add_config"),
                InlineKeyboardButton(
                    "📊 کانفیگ‌های موجود", callback_data="admin_view_configs"
                ),
            ],
            [InlineKeyboardButton("⚙️ تنظیم شماره کارت", callback_data="admin_set_card")],
            [
                InlineKeyboardButton(
                    "💳 افزایش موجودی دستی", callback_data="admin_charge_help"
                )
            ],
            [InlineKeyboardButton("📨 پیام به مشتری", callback_data="admin_msg_customer")],
            [
                InlineKeyboardButton("📋 لیست کاربران", callback_data="admin_users"),
                InlineKeyboardButton("📈 آمار", callback_data="admin_stats"),
            ],
            [InlineKeyboardButton("📊 گزارش فروش", callback_data="admin_sales_report")],
            [
                InlineKeyboardButton("🚫 مسدود کردن", callback_data="admin_ban"),
                InlineKeyboardButton("✅ رفع مسدودیت", callback_data="admin_unban"),
            ],
            [InlineKeyboardButton("📋 لیست مسدودشدگان", callback_data="admin_banned_list")],
            [InlineKeyboardButton("📢 ارسال پیام همگانی", callback_data="admin_broadcast")],
            [InlineKeyboardButton("📦 دانلود بکاپ دیتابیس", callback_data="admin_db_backup")],
            [
                InlineKeyboardButton("🏷 ایجاد کد تخفیف", callback_data="admin_create_discount"),
                InlineKeyboardButton("🗑 حذف کد تخفیف", callback_data="admin_delete_discount"),
            ],
            [InlineKeyboardButton("📋 لیست کدهای تخفیف", callback_data="admin_list_discounts")],
            [InlineKeyboardButton("📝 مدیریت متون ربات", callback_data="admin_texts")],
            [InlineKeyboardButton("🧪 اکانت‌های تست", callback_data="admin_trial_menu")],
        ]
    )

back_to_panel = InlineKeyboardMarkup(
    [[InlineKeyboardButton("🔙 بازگشت به پنل", callback_data="admin_back")]]
)
back_to_wallet = InlineKeyboardMarkup(
    [[InlineKeyboardButton("🔙 بازگشت", callback_data="wallet_menu")]]
)


def verif_action_kb(target_uid):
    return InlineKeyboardMarkup(
        [
            [
                InlineKeyboardButton(
                    "✅ تایید", callback_data=f"verif_approve_{target_uid}"
                ),
                InlineKeyboardButton(
                    "❌ رد", callback_data=f"verif_reject_{target_uid}"
                ),
            ]
        ]
    )


NOT_VERIFIED_TEXT = (
    "🔒 <b>ابتدا احراز هویت کنید</b>\n\n"
    "برای مشاهده شماره کارت و افزودن موجودی، باید هویت‌تان تأیید شود.\n\n"
    "از دکمه زیر درخواست احراز هویت دهید:"
)
NOT_VERIFIED_KB = InlineKeyboardMarkup(
    [
        [
            InlineKeyboardButton(
                "📩 درخواست احراز هویت", callback_data="request_verif"
            ),
        ]
    ]
)


def is_verified(uid) -> bool:
    u = db_get_user(uid)
    return bool(u and int(u.get("verified", 0)))


def order_action_kb(order_id):
    return InlineKeyboardMarkup(
        [
            [
                InlineKeyboardButton("✅ تایید", callback_data=f"approve_{order_id}"),
                InlineKeyboardButton("❌ رد", callback_data=f"reject_{order_id}"),
            ]
        ]
    )


def post_approve_kb(order_id):
    return InlineKeyboardMarkup(
        [
            [
                InlineKeyboardButton(
                    "📩 ارسال پیام به مشتری", callback_data=f"msg_user_{order_id}"
                )
            ],
            [
                InlineKeyboardButton(
                    "📦 ارسال کانفیگ", callback_data=f"send_config_{order_id}"
                )
            ],
            [InlineKeyboardButton("🔙 بازگشت به پنل", callback_data="admin_back")],
        ]
    )


def charge_action_kb(req_id):
    return InlineKeyboardMarkup(
        [
            [
                InlineKeyboardButton(
                    "✅ تایید شارژ", callback_data=f"charge_approve_{req_id}"
                ),
                InlineKeyboardButton("❌ رد", callback_data=f"charge_reject_{req_id}"),
            ]
        ]
    )


def wallet_kb(uid=None):
    verified = uid and (lambda u: u and u.get("verified"))(db_get_user(uid))
    rows = [[InlineKeyboardButton("💎 شارژ با ارز دیجیتال (TRC20)", callback_data="wallet_add_tron")]]
    if verified:
        rows.append([InlineKeyboardButton("🏦 کارت به کارت", callback_data="wallet_add")])
    rows.append([InlineKeyboardButton("💸 موجودی من", callback_data="wallet_balance")])
    rows.append([InlineKeyboardButton("🔙 بازگشت", callback_data="wallet_close")])
    return InlineKeyboardMarkup(rows)


def tron_action_kb(req_id):
    return InlineKeyboardMarkup(
        [
            [
                InlineKeyboardButton("✅ تایید واریز", callback_data=f"tron_approve_{req_id}"),
                InlineKeyboardButton("❌ رد واریز", callback_data=f"tron_reject_{req_id}"),
            ]
        ]
    )


def card_info_kb():
    return InlineKeyboardMarkup(
        [
            [
                InlineKeyboardButton(
                    "📷 ارسال رسید", callback_data="wallet_send_receipt"
                )
            ],
            [InlineKeyboardButton("🔙 بازگشت", callback_data="wallet_menu")],
        ]
    )


# ═════════════════════════════════════════════════════════════════════════════
#  DATABASE
# ═════════════════════════════════════════════════════════════════════════════
def init_db():
    os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
    with sqlite3.connect(DB_PATH) as con:
        con.executescript("""
            CREATE TABLE IF NOT EXISTS plans (
                id         INTEGER PRIMARY KEY AUTOINCREMENT,
                name       TEXT    NOT NULL,
                price      INTEGER NOT NULL
            );
            CREATE TABLE IF NOT EXISTS users (
                user_id    INTEGER PRIMARY KEY,
                username   TEXT,
                full_name  TEXT,
                balance    INTEGER DEFAULT 0,
                verified   INTEGER DEFAULT 0,
                joined_at  TEXT    DEFAULT (datetime('now'))
            );
            CREATE TABLE IF NOT EXISTS orders (
                id          INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id     INTEGER NOT NULL,
                plan_id     INTEGER NOT NULL,
                plan_name   TEXT    NOT NULL,
                plan_price  INTEGER NOT NULL,
                status      TEXT    DEFAULT 'pending',
                pay_method  TEXT    DEFAULT 'card',
                created_at  TEXT    DEFAULT (datetime('now')),
                updated_at  TEXT    DEFAULT (datetime('now'))
            );
            CREATE TABLE IF NOT EXISTS charge_requests (
                id           INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id      INTEGER NOT NULL,
                amount       INTEGER NOT NULL,
                receipt_file TEXT,
                status       TEXT    DEFAULT 'pending',
                created_at   TEXT    DEFAULT (datetime('now'))
            );
            CREATE TABLE IF NOT EXISTS configs (
                id          INTEGER PRIMARY KEY AUTOINCREMENT,
                plan_name   TEXT    NOT NULL,
                config_text TEXT    NOT NULL,
                status      TEXT    DEFAULT 'available',
                order_id    INTEGER,
                added_at    TEXT    DEFAULT (datetime('now'))
            );
            CREATE TABLE IF NOT EXISTS settings (
                key   TEXT PRIMARY KEY,
                value TEXT
            );
            CREATE TABLE IF NOT EXISTS message_log (
                id          INTEGER PRIMARY KEY AUTOINCREMENT,
                order_id    INTEGER NOT NULL,
                admin_id    INTEGER NOT NULL,
                customer_id INTEGER NOT NULL,
                msg_type    TEXT    NOT NULL,
                content     TEXT    NOT NULL,
                sent_at     TEXT    DEFAULT (datetime('now'))
            );
            CREATE TABLE IF NOT EXISTS discount_codes (
                id          INTEGER PRIMARY KEY AUTOINCREMENT,
                code        TEXT    NOT NULL UNIQUE,
                percentage  INTEGER NOT NULL,
                max_uses    INTEGER NOT NULL DEFAULT 1,
                expires_at  TEXT,
                created_at  TEXT    DEFAULT (datetime('now'))
            );
            CREATE TABLE IF NOT EXISTS discount_uses (
                id      INTEGER PRIMARY KEY AUTOINCREMENT,
                code_id INTEGER NOT NULL,
                user_id INTEGER NOT NULL,
                used_at TEXT    DEFAULT (datetime('now')),
                UNIQUE(code_id, user_id)
            );
            CREATE TABLE IF NOT EXISTS trial_accounts (
                id           INTEGER PRIMARY KEY AUTOINCREMENT,
                sub_link     TEXT,
                config_text  TEXT    NOT NULL,
                qr_file_id   TEXT,
                status       TEXT    DEFAULT 'available',
                assigned_to  INTEGER,
                assigned_at  TEXT,
                added_at     TEXT    DEFAULT (datetime('now'))
            );
            CREATE TABLE IF NOT EXISTS tron_deposits (
                id         INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id    INTEGER NOT NULL,
                amount_trx REAL    NOT NULL,
                txid       TEXT    NOT NULL UNIQUE,
                status     TEXT    DEFAULT 'pending',
                created_at TEXT    DEFAULT (datetime('now'))
            );
        """)
        for stmt in [
            "ALTER TABLE users  ADD COLUMN balance  INTEGER DEFAULT 0",
            "ALTER TABLE users  ADD COLUMN verified INTEGER DEFAULT 0",
            "ALTER TABLE users  ADD COLUMN banned   INTEGER DEFAULT 0",
            "ALTER TABLE orders ADD COLUMN plan_name      TEXT",
            "ALTER TABLE orders ADD COLUMN plan_price     INTEGER",
            "ALTER TABLE orders ADD COLUMN pay_method     TEXT DEFAULT 'card'",
            "ALTER TABLE orders ADD COLUMN updated_at     TEXT DEFAULT (datetime('now'))",
            "ALTER TABLE orders ADD COLUMN discount_code   TEXT",
            "ALTER TABLE orders ADD COLUMN discount_amount INTEGER DEFAULT 0",
            "ALTER TABLE plans  ADD COLUMN duration TEXT DEFAULT '1_month'",
            "ALTER TABLE orders ADD COLUMN service_name TEXT DEFAULT 'سرویس من'",
            "ALTER TABLE configs ADD COLUMN sub_link   TEXT",
            "ALTER TABLE configs ADD COLUMN qr_file_id TEXT",
        ]:
            try:
                con.execute(stmt)
            except sqlite3.OperationalError:
                pass
        con.execute(
            "INSERT OR IGNORE INTO settings (key,value) VALUES ('card_number','6219861947630454')"
        )
        con.execute(
            "INSERT OR IGNORE INTO settings (key,value) VALUES ('card_holder','Hadi Kazazi')"
        )
        con.execute(
            "INSERT OR IGNORE INTO settings (key,value) VALUES ('bot_status','on')"
        )
        con.execute(
            "INSERT OR IGNORE INTO settings (key,value) VALUES ('welcome_text',"
            "'👻 به Ghost VPN خوش اومدی، {name}!\n\nاز منوی زیر انتخاب کنید:')"
        )
        con.execute(
            "INSERT OR IGNORE INTO settings (key,value) VALUES ('bot_off_text',"
            "'❌ در حال حاضر دسترسی به ربات امکان پذیر نیست، لطفا در ساعات آینده دوباره امتحان کنید "
            "یا با پشتیبانی ربات تماس بگیرید.\n\nبرای بررسی مجدد از دستور زیر استفاده کنید:\n/start')"
        )
        con.execute(
            "INSERT OR IGNORE INTO settings (key,value) VALUES ('rules_text',"
            "'📋 قوانین استفاده از Ghost VPN:\n\n"
            "1️⃣ استفاده از سرویس برای فعالیت‌های غیرقانونی ممنوع است.\n"
            "2️⃣ اشتراک‌گذاری کانفیگ با دیگران ممنوع است.\n"
            "3️⃣ در صورت نقض قوانین، اکانت مسدود می‌شود.\n\n"
            "با خرید سرویس، قوانین فوق را پذیرفته‌اید.')"
        )
        con.commit()


# ── DB helpers ────────────────────────────────────────────────────────────────
def row(sql, params=()):
    with sqlite3.connect(DB_PATH) as con:
        con.row_factory = sqlite3.Row
        r = con.execute(sql, params).fetchone()
        return dict(r) if r else None


def rows(sql, params=()):
    with sqlite3.connect(DB_PATH) as con:
        con.row_factory = sqlite3.Row
        return [dict(r) for r in con.execute(sql, params).fetchall()]


def execute(sql, params=()):
    with sqlite3.connect(DB_PATH) as con:
        cur = con.execute(sql, params)
        con.commit()
        return cur.lastrowid


def setting(key):
    r = row("SELECT value FROM settings WHERE key=?", (key,))
    return r["value"] if r else ""


def set_setting(key, value):
    execute("INSERT OR REPLACE INTO settings (key,value) VALUES (?,?)", (key, value))


def is_bot_on() -> bool:
    return (setting("bot_status") or "on") == "on"


def get_text(key: str, default: str = "") -> str:
    """Return the admin-editable text for the given key, falling back to default."""
    return setting(key) or default


def set_text(key: str, value: str):
    set_setting(key, value)


# ── Ban helpers ────────────────────────────────────────────────────────────────
def is_banned(uid) -> bool:
    u = db_get_user(uid)
    return bool(u and int(u.get("banned", 0)))


def db_ban_user(uid):
    execute("UPDATE users SET banned=1 WHERE user_id=?", (uid,))


def db_unban_user(uid):
    execute("UPDATE users SET banned=0 WHERE user_id=?", (uid,))


def db_get_banned_users():
    return rows("SELECT user_id, username, full_name FROM users WHERE banned=1")


def db_get_all_users():
    return rows("SELECT user_id FROM users")


# ── Discount helpers ───────────────────────────────────────────────────────────
def db_create_discount(code, percentage, max_uses, expires_at=None):
    execute(
        "INSERT INTO discount_codes (code, percentage, max_uses, expires_at) VALUES (?,?,?,?)",
        (code.upper(), int(percentage), int(max_uses), expires_at),
    )


def db_delete_discount(code_id):
    execute("DELETE FROM discount_codes WHERE id=?", (code_id,))
    execute("DELETE FROM discount_uses WHERE code_id=?", (code_id,))


def db_get_discounts():
    return rows(
        """SELECT dc.*,
                  (SELECT COUNT(*) FROM discount_uses du WHERE du.code_id=dc.id) AS used_count
           FROM discount_codes dc ORDER BY dc.id DESC"""
    )


def db_validate_discount(code, user_id):
    """Returns (code_row, error_message). On success error_message is None."""
    import datetime as _dt
    dc = row("SELECT * FROM discount_codes WHERE code=?", (code.upper(),))
    if not dc:
        return None, "❌ کد تخفیف معتبر نیست."
    used = row(
        "SELECT COUNT(*) as cnt FROM discount_uses WHERE code_id=?", (dc["id"],)
    )["cnt"]
    if used >= dc["max_uses"]:
        return None, "❌ ظرفیت این کد تخفیف تمام شده است."
    if dc["expires_at"]:
        try:
            exp = _dt.datetime.strptime(dc["expires_at"], "%Y-%m-%d").date()
            if _dt.date.today() > exp:
                return None, "❌ این کد تخفیف منقضی شده است."
        except Exception:
            pass
    already = row(
        "SELECT 1 FROM discount_uses WHERE code_id=? AND user_id=?", (dc["id"], user_id)
    )
    if already:
        return None, "❌ شما قبلاً از این کد تخفیف استفاده کرده‌اید."
    return dc, None


def db_use_discount(code_id, user_id):
    try:
        execute(
            "INSERT OR IGNORE INTO discount_uses (code_id, user_id) VALUES (?,?)",
            (code_id, user_id),
        )
    except Exception:
        pass


DURATION_LABELS = {
    "1_month":   "📅 ۱ ماهه",
    "3_months":  "📅 ۳ ماهه",
    "lifetime":  "♾️ مادام‌العمر",
}

DURATION_ORDER = ["1_month", "3_months", "lifetime"]


# ── Plan helpers ───────────────────────────────────────────────────────────────
def db_get_plans():
    return rows("SELECT * FROM plans ORDER BY price")


def db_get_plans_by_duration(duration):
    return rows("SELECT * FROM plans WHERE duration=? ORDER BY price", (duration,))


def db_add_plan(name, price, duration="1_month"):
    execute(
        "INSERT INTO plans (name, price, duration) VALUES (?,?,?)",
        (name, int(price), duration),
    )


def db_delete_plan(plan_id):
    execute("DELETE FROM plans WHERE id=?", (plan_id,))


# ── User helpers ───────────────────────────────────────────────────────────────
def db_register_user(user):
    execute(
        "INSERT OR IGNORE INTO users (user_id, username, full_name) VALUES (?,?,?)",
        (user.id, user.username, user.full_name),
    )


def db_get_user(uid):
    return row("SELECT * FROM users WHERE user_id=?", (uid,))


def db_set_verified(uid, status: int):
    execute("UPDATE users SET verified=? WHERE user_id=?", (status, uid))


def db_add_balance(uid, amount):
    execute("UPDATE users SET balance = balance + ? WHERE user_id=?", (amount, uid))


def db_deduct_balance(uid, amount):
    execute("UPDATE users SET balance = balance - ? WHERE user_id=?", (amount, uid))


# ── Order helpers ──────────────────────────────────────────────────────────────
def db_create_order(user_id, plan, pay_method="card", discount_code=None, discount_amount=0, service_name="سرویس من"):
    return execute(
        "INSERT INTO orders (user_id, plan_id, plan_name, plan_price, pay_method, discount_code, discount_amount, service_name) VALUES (?,?,?,?,?,?,?,?)",
        (user_id, plan["id"], plan["name"], int(plan["price"]), pay_method, discount_code, discount_amount, service_name),
    )


def db_get_order(order_id):
    return row(
        """SELECT o.*, u.username, u.full_name, u.user_id as uid
           FROM orders o JOIN users u ON o.user_id=u.user_id
           WHERE o.id=?""",
        (order_id,),
    )


def db_approve_order(order_id):
    execute(
        "UPDATE orders SET status='approved', updated_at=datetime('now') WHERE id=?",
        (order_id,),
    )


def db_reject_order(order_id):
    execute(
        "UPDATE orders SET status='rejected', updated_at=datetime('now') WHERE id=?",
        (order_id,),
    )


# ── Charge helpers ─────────────────────────────────────────────────────────────
def db_create_charge(user_id, amount, file_id=None):
    return execute(
        "INSERT INTO charge_requests (user_id, amount, receipt_file) VALUES (?,?,?)",
        (user_id, amount, file_id),
    )


def db_get_charge(req_id):
    return row(
        """SELECT cr.*, u.full_name, u.username, u.user_id as uid
           FROM charge_requests cr JOIN users u ON cr.user_id=u.user_id
           WHERE cr.id=?""",
        (req_id,),
    )


# ── Tron deposit helpers ────────────────────────────────────────────────────────
TRON_WALLET = "TSnxoaXzmAf16PWuwQEncxGAEGd3GJp2DW"


def db_create_tron_deposit(user_id, amount_trx, txid):
    return execute(
        "INSERT INTO tron_deposits (user_id, amount_trx, txid) VALUES (?,?,?)",
        (user_id, amount_trx, txid),
    )


def db_get_tron_deposit(req_id):
    return row(
        """SELECT td.*, u.full_name, u.username, u.user_id as uid
           FROM tron_deposits td JOIN users u ON td.user_id=u.user_id
           WHERE td.id=?""",
        (req_id,),
    )


def db_txid_exists(txid):
    return row("SELECT id FROM tron_deposits WHERE txid=?", (txid,)) is not None


# ── Config helpers ─────────────────────────────────────────────────────────────
def db_add_config(plan_name: str, config_text: str, sub_link: str = None, qr_file_id: str = None):
    execute(
        "INSERT INTO configs (plan_name, config_text, sub_link, qr_file_id) VALUES (?,?,?,?)",
        (plan_name, config_text, sub_link, qr_file_id),
    )


def db_pop_config(plan_name: str):
    return row(
        "SELECT * FROM configs WHERE plan_name=? AND status='available' ORDER BY id LIMIT 1",
        (plan_name,),
    )


def db_mark_config_sold(config_id: int, order_id: int):
    execute(
        "UPDATE configs SET status='sold', order_id=? WHERE id=?",
        (order_id, config_id),
    )


# ── Stats helper ───────────────────────────────────────────────────────────────
def db_count(table, where=None, val=None):
    with sqlite3.connect(DB_PATH) as con:
        if where:
            return con.execute(
                f"SELECT COUNT(*) FROM {table} WHERE {where}=?", (val,)
            ).fetchone()[0]
        return con.execute(f"SELECT COUNT(*) FROM {table}").fetchone()[0]


# ═════════════════════════════════════════════════════════════════════════════
#  CHANNEL MEMBERSHIP CHECK
# ═════════════════════════════════════════════════════════════════════════════
JOIN_KB = InlineKeyboardMarkup(
    [
        [
            InlineKeyboardButton(
                "📢 عضویت در کانال", url=f"https://t.me/{CHANNEL.lstrip('@')}"
            )
        ],
        [InlineKeyboardButton("✅ بررسی عضویت", callback_data="check_join")],
    ]
)

JOIN_TEXT = (
    "🔒 <b>برای استفاده از ربات باید ابتدا در کانال عضو شوید.</b>\n\n"
    f"📢 کانال:\n{CHANNEL}\n\n"
    "بعد از عضویت روی دکمه زیر بزنید:"
)


async def is_channel_member(bot, uid: int) -> bool:
    if uid == ADMIN_ID:
        return True
    try:
        member = await bot.get_chat_member(CHANNEL, uid)
        return member.status in ("member", "administrator", "creator")
    except Exception:
        return False


def get_bot_off_text() -> str:
    return get_text("bot_off_text",
        "❌ در حال حاضر دسترسی به ربات امکان پذیر نیست، لطفا در ساعات آینده دوباره امتحان کنید "
        "یا با پشتیبانی ربات تماس بگیرید.\n\nبرای بررسی مجدد از دستور زیر استفاده کنید:\n/start"
    )


async def is_channel_member(bot, uid: int) -> bool:
    if uid == ADMIN_ID:
        return True
    try:
        member = await bot.get_chat_member(CHANNEL, uid)
        return member.status in ("member", "administrator", "creator")
    except Exception:
        return False


BAN_TEXT = (
    "⛔ شما از استفاده از ربات مسدود شده‌اید.\n"
    "در صورت نیاز با پشتیبانی تماس بگیرید."
)


async def gate_message(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool:
    uid = update.effective_user.id
    if uid != ADMIN_ID and is_banned(uid):
        msg = update.message
        if msg:
            await msg.reply_text(BAN_TEXT)
        return False
    if uid != ADMIN_ID and not is_bot_on():
        msg = update.message
        if msg:
            await msg.reply_text(get_bot_off_text())
        return False
    if await is_channel_member(context.bot, uid):
        return True
    msg = update.message
    if msg:
        await msg.reply_text(JOIN_TEXT, parse_mode="HTML", reply_markup=JOIN_KB)
    return False


async def gate_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool:
    uid = update.effective_user.id
    if uid != ADMIN_ID and is_banned(uid):
        query = update.callback_query
        try:
            await query.edit_message_text(BAN_TEXT)
        except Exception:
            await context.bot.send_message(chat_id=uid, text=BAN_TEXT)
        return False
    if uid != ADMIN_ID and not is_bot_on():
        query = update.callback_query
        try:
            await query.edit_message_text(get_bot_off_text())
        except Exception:
            await context.bot.send_message(chat_id=uid, text=get_bot_off_text())
        return False
    if await is_channel_member(context.bot, uid):
        return True
    query = update.callback_query
    try:
        await query.edit_message_text(
            JOIN_TEXT, parse_mode="HTML", reply_markup=JOIN_KB
        )
    except Exception:
        await context.bot.send_message(
            chat_id=uid, text=JOIN_TEXT, parse_mode="HTML", reply_markup=JOIN_KB
        )
    return False


# ═════════════════════════════════════════════════════════════════════════════
#  FORMATTING
# ═════════════════════════════════════════════════════════════════════════════
def fmt(n):
    return f"{int(n):,} تومان"


def card_text():
    return (
        f"💳 <b>شماره کارت:</b>\n"
        f"<code>{setting('card_number')}</code>\n\n"
        f"به نام: <b>{setting('card_holder')}</b>"
    )


def user_info_text(found, cnt):
    uname = f"@{found['username']}" if found.get("username") else "—"
    verified = "✅ احراز شده" if found.get("verified") else "❌ احراز نشده"
    banned = "🚫 مسدود" if found.get("banned") else "✅ فعال"
    joined = (found.get("joined_at") or "—")[:10]
    return (
        f"👤 <b>اطلاعات کاربر</b>\n\n"
        f"🆔 شناسه کاربر: <code>{found['user_id']}</code>\n"
        f"👤 نام: <b>{found.get('full_name') or '—'}</b>\n"
        f"📛 یوزرنیم: {uname}\n"
        f"💰 موجودی کیف پول: <b>{fmt(found.get('balance') or 0)}</b>\n"
        f"✅ وضعیت احراز هویت: {verified}\n"
        f"🚫 وضعیت مسدودیت: {banned}\n"
        f"📦 تعداد سفارش‌ها: <b>{cnt}</b>\n"
        f"📅 تاریخ عضویت: {joined}"
    )


def user_mgr_kb(target_uid):
    return InlineKeyboardMarkup([
        [
            InlineKeyboardButton("🚫 مسدود کردن", callback_data=f"usermgr_ban_{target_uid}"),
            InlineKeyboardButton("✅ رفع مسدودیت", callback_data=f"usermgr_unban_{target_uid}"),
        ],
        [
            InlineKeyboardButton("💰 تغییر موجودی", callback_data=f"usermgr_bal_{target_uid}"),
            InlineKeyboardButton("📨 ارسال پیام", callback_data=f"usermgr_msg_{target_uid}"),
        ],
        [InlineKeyboardButton("🔍 جستجوی دیگر", callback_data="admin_search_user")],
        [InlineKeyboardButton("🔙 بازگشت به لیست", callback_data="admin_users")],
    ])


# ── Trial account helpers ───────────────────────────────────────────────────
def db_add_trial(config_text, sub_link=None, qr_file_id=None):
    return execute(
        "INSERT INTO trial_accounts (config_text, sub_link, qr_file_id) VALUES (?,?,?)",
        (config_text, sub_link, qr_file_id),
    )


def db_get_available_trial():
    return row(
        "SELECT * FROM trial_accounts WHERE status='available' ORDER BY added_at ASC LIMIT 1"
    )


def db_assign_trial(trial_id, user_id):
    execute(
        "UPDATE trial_accounts SET status='used', assigned_to=?, assigned_at=datetime('now') WHERE id=?",
        (user_id, trial_id),
    )


def db_user_has_trial(user_id):
    return row(
        "SELECT id FROM trial_accounts WHERE assigned_to=? LIMIT 1", (user_id,)
    )


def db_list_trials():
    return rows("SELECT * FROM trial_accounts ORDER BY added_at DESC")


def db_delete_trial(trial_id):
    execute("DELETE FROM trial_accounts WHERE id=?", (trial_id,))


# ═════════════════════════════════════════════════════════════════════════════
#  COMMAND HANDLERS
# ═════════════════════════════════════════════════════════════════════════════
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if not await gate_message(update, context):
        return
    db_register_user(update.effective_user)
    USER_STATE.pop(update.effective_user.id, None)
    if update.effective_user.id == ADMIN_ID:
        await update.message.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
    else:
        welcome = get_text(
            "welcome_text",
            "👻 به Ghost VPN خوش اومدی، {name}!\n\nاز منوی زیر انتخاب کنید:"
        ).format(name=update.effective_user.first_name)
        await update.message.reply_text(
            welcome,
            parse_mode="HTML",
            reply_markup=get_main_menu(update.effective_user.id),
        )


async def admin_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID:
        return
    USER_STATE.pop(update.effective_user.id, None)
    await update.message.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())


async def charge_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID:
        return
    args = context.args
    if (
        len(args) != 2
        or not args[0].isdigit()
        or not args[1].replace(",", "").isdigit()
    ):
        await update.message.reply_text(
            "⚠️ فرمت:\n<code>/charge USER_ID AMOUNT</code>", parse_mode="HTML"
        )
        return
    target_id = int(args[0])
    amount = int(args[1].replace(",", ""))
    u = db_get_user(target_id)
    if not u:
        await update.message.reply_text("❌ کاربر یافت نشد.")
        return
    db_add_balance(target_id, amount)
    new_bal = db_get_user(target_id)["balance"]
    await update.message.reply_text(
        f"✅ {fmt(amount)} به موجودی <b>{u['full_name']}</b> افزوده شد.\nموجودی جدید: <b>{fmt(new_bal)}</b>",
        parse_mode="HTML",
    )
    try:
        await context.bot.send_message(
            chat_id=target_id,
            text=f"✅ موجودی شما {fmt(amount)} افزایش یافت.\n💰 موجودی فعلی: <b>{fmt(new_bal)}</b>",
            parse_mode="HTML",
        )
    except Exception:
        pass


# ═════════════════════════════════════════════════════════════════════════════
#  MESSAGE HANDLER  (FSM + menu buttons)
# ═════════════════════════════════════════════════════════════════════════════
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if not update.effective_user:
        return
    uid = update.effective_user.id
    _raw_text = (update.message.text or "")[:40] if update.message else ""
    _cur_state = USER_STATE.get(uid, {}).get("state")
    logger.info("MSG uid=%s state=%s text=%r", uid, _cur_state, _raw_text)
    if not await gate_message(update, context):
        logger.info("MSG uid=%s blocked by gate", uid)
        return
    msg = update.message
    text = msg.text.strip() if msg.text else ""
    st = USER_STATE.get(uid, {})
    state = st.get("state")

    # ── FSM: wallet receipt (photo) ───────────────────────────────────────────
    if state == "WAITING_CHARGE_RECEIPT" and msg.photo:
        amount = st.get("amount", 0)
        file_id = msg.photo[-1].file_id
        req_id = db_create_charge(uid, amount, file_id)
        USER_STATE.pop(uid, None)
        u = db_get_user(uid)
        try:
            await context.bot.send_photo(
                chat_id=ADMIN_ID,
                photo=file_id,
                caption=(
                    f"💳 <b>درخواست شارژ #{req_id}</b>\n\n"
                    f"👤 {u['full_name']} (@{u['username'] or 'N/A'}) [ID: {uid}]\n"
                    f"💰 مبلغ: <b>{fmt(amount)}</b>"
                ),
                parse_mode="HTML",
                reply_markup=charge_action_kb(req_id),
            )
        except Exception:
            pass
        await msg.reply_text(
            "✅ رسید شما ارسال شد.\nبعد از تایید ادمین، موجودی افزایش می‌یابد.",
            reply_markup=get_main_menu(uid),
        )
        return

    if state == "WAITING_CHARGE_RECEIPT" and not msg.photo:
        await msg.reply_text("📷 لطفاً تصویر رسید پرداخت را ارسال کنید.")
        return

    # ── FSM: verification photo ───────────────────────────────────────────────
    if state == "WAITING_VERIF_PHOTO" and msg.photo:
        file_id = msg.photo[-1].file_id
        USER_STATE.pop(uid, None)
        u = db_get_user(uid)
        try:
            await context.bot.send_photo(
                chat_id=ADMIN_ID,
                photo=file_id,
                caption=(
                    f"🪪 <b>درخواست احراز هویت</b>\n\n"
                    f"👤 {u['full_name']} (@{u['username'] or 'N/A'})\n"
                    f"🆔 آیدی: <code>{uid}</code>"
                ),
                parse_mode="HTML",
                reply_markup=verif_action_kb(uid),
            )
        except Exception:
            pass
        await msg.reply_text(
            "✅ عکس شما دریافت شد.\nپس از بررسی توسط ادمین، نتیجه اعلام می‌شود.",
            reply_markup=get_main_menu(uid),
        )
        return

    if state == "WAITING_VERIF_PHOTO" and not msg.photo:
        await msg.reply_text("📷 لطفاً تصویر کارت بانکی را ارسال کنید.")
        return

    # ── FSM: wallet charge amount ─────────────────────────────────────────────
    if state == "WAITING_CHARGE_AMOUNT":
        if not is_verified(uid):
            USER_STATE.pop(uid, None)
            await msg.reply_text(
                NOT_VERIFIED_TEXT, parse_mode="HTML", reply_markup=NOT_VERIFIED_KB
            )
            return
        clean = text.replace(",", "").replace("٬", "").replace(" ", "")
        if not clean.isdigit() or int(clean) <= 0:
            await msg.reply_text("⚠️ لطفاً یک مبلغ معتبر وارد کنید (مثلاً 50000):")
            return
        amount = int(clean)
        USER_STATE[uid] = {"state": "WAITING_CHARGE_RECEIPT", "amount": amount}
        await msg.reply_text(
            f"💰 مبلغ: <b>{fmt(amount)}</b>\n\n"
            f"{card_text()}\n\n"
            "لطفاً مبلغ را واریز کرده و تصویر رسید را ارسال کنید 👇",
            parse_mode="HTML",
        )
        return

    # ── FSM: Tron deposit — amount ────────────────────────────────────────────
    if state == "WAITING_TRON_AMOUNT":
        try:
            amount_trx = float(text.replace(",", "."))
            if amount_trx <= 0:
                raise ValueError
        except (ValueError, AttributeError):
            await msg.reply_text("⚠️ لطفاً مقدار ترون را به عدد وارد کنید (مثلاً: 100 یا 50.5):")
            return
        USER_STATE[uid] = {"state": "WAITING_TRON_TXID", "amount_trx": amount_trx}
        await msg.reply_text(
            f"💎 مقدار: <b>{amount_trx:g} TRX</b>\n\n"
            "🔗 لطفاً شناسه تراکنش (TXID) را وارد کنید:",
            parse_mode="HTML",
        )
        return

    # ── FSM: Tron deposit — TXID ──────────────────────────────────────────────
    if state == "WAITING_TRON_TXID":
        txid = text.strip() if text else ""
        if not txid or len(txid) < 10:
            await msg.reply_text("⚠️ لطفاً TXID معتبر وارد کنید:")
            return
        if db_txid_exists(txid):
            USER_STATE.pop(uid, None)
            await msg.reply_text(
                "❌ این TXID قبلاً ثبت شده است.\n"
                "در صورت اشتباه با پشتیبانی تماس بگیرید.",
                reply_markup=get_main_menu(uid),
            )
            return
        amount_trx = st.get("amount_trx", 0)
        req_id = db_create_tron_deposit(uid, amount_trx, txid)
        USER_STATE.pop(uid, None)
        u = db_get_user(uid)
        try:
            await context.bot.send_message(
                chat_id=ADMIN_ID,
                text=(
                    f"💎 <b>درخواست واریز ترون #{req_id}</b>\n\n"
                    f"👤 {u['full_name']} (@{u['username'] or 'N/A'})\n"
                    f"🆔 آیدی: <code>{uid}</code>\n"
                    f"💰 مقدار: <b>{amount_trx:g} TRX</b>\n"
                    f"🔗 TXID: <code>{txid}</code>"
                ),
                parse_mode="HTML",
                reply_markup=tron_action_kb(req_id),
            )
        except Exception:
            pass
        await msg.reply_text(
            "✅ درخواست واریز ترون شما ثبت شد.\nپس از تایید ادمین، موجودی افزایش می‌یابد.",
            reply_markup=get_main_menu(uid),
        )
        return

    # ── Admin FSM ──────────────────────────────────────────────────────────────
    if uid == ADMIN_ID:
        if state == "WAITING_TRIAL_LINK":
            link = text.strip() if text and text.strip() else None
            USER_STATE[uid] = {**st, "state": "WAITING_TRIAL_CONFIG", "trial_link": link}
            await msg.reply_text(
                "📋 <b>اطلاعات کانفیگ اکانت تست را وارد کنید:</b>",
                parse_mode="HTML",
            )
            return

        if state == "WAITING_TRIAL_CONFIG":
            if not text or not text.strip():
                await msg.reply_text("⚠️ متن کانفیگ را وارد کنید:")
                return
            USER_STATE[uid] = {**st, "state": "WAITING_TRIAL_QR", "trial_config": text.strip()}
            await msg.reply_text(
                "📷 <b>تصویر QR Code را ارسال کنید</b> (اختیاری).\n\n"
                "اگر QR ندارید، بنویسید <b>skip</b>:",
                parse_mode="HTML",
            )
            return

        if state == "WAITING_TRIAL_QR":
            link = st.get("trial_link")
            config = st.get("trial_config", "")
            qr_file_id = None
            if msg.photo:
                qr_file_id = msg.photo[-1].file_id
            elif text and text.strip().lower() in ("skip", "بدون qr", "-"):
                qr_file_id = None
            else:
                await msg.reply_text(
                    "📷 تصویر QR ارسال کنید یا بنویسید <b>skip</b>:",
                    parse_mode="HTML",
                )
                return
            USER_STATE.pop(uid, None)
            db_add_trial(config_text=config, sub_link=link, qr_file_id=qr_file_id)
            await msg.reply_text(
                "✅ <b>اکانت تست اضافه شد.</b>",
                parse_mode="HTML",
                reply_markup=get_admin_keyboard(),
            )
            return

        if state == "WAITING_PLAN_NAME":
            USER_STATE[uid] = {"state": "WAITING_PLAN_PRICE", "plan_name": text}
            await msg.reply_text(
                f"💰 قیمت پلن <b>{text}</b> را وارد کنید (عدد — تومان):",
                parse_mode="HTML",
            )
            return

        if state == "WAITING_PLAN_PRICE":
            clean = text.replace(",", "").replace("٬", "").replace(" ", "")
            if not clean.isdigit():
                await msg.reply_text("⚠️ فقط عدد وارد کنید:")
                return
            name = st.get("plan_name", "نامشخص")
            USER_STATE[uid] = {"state": "WAITING_PLAN_DURATION_CB", "plan_name": name, "plan_price": int(clean)}
            await msg.reply_text(
                f"📦 پلن: <b>{name}</b> — {fmt(int(clean))}\n\nمدت سرویس را انتخاب کنید:",
                parse_mode="HTML",
                reply_markup=InlineKeyboardMarkup([
                    [InlineKeyboardButton(DURATION_LABELS[d], callback_data=f"admin_plan_dur_{d}")]
                    for d in DURATION_ORDER
                ]),
            )
            return

        if state == "WAITING_SEARCH_USER":
            USER_STATE.pop(uid, None)
            query_text = text.strip()
            found = None
            if query_text.lstrip("-").isdigit():
                found = db_get_user(int(query_text))
            if not found and query_text.startswith("@"):
                found = row("SELECT * FROM users WHERE username=?", (query_text[1:],))
            if not found:
                found = row("SELECT * FROM users WHERE username=?", (query_text,))
            if not found:
                found = row("SELECT * FROM users WHERE full_name LIKE ?", (f"%{query_text}%",))
            if not found:
                await msg.reply_text(
                    "❌ کاربر پیدا نشد.",
                    reply_markup=InlineKeyboardMarkup(
                        [[InlineKeyboardButton("🔍 جستجوی دیگر", callback_data="admin_search_user")],
                         [InlineKeyboardButton("🔙 بازگشت به لیست", callback_data="admin_users")]]
                    ),
                )
                return
            total_orders = row(
                "SELECT COUNT(*) as cnt FROM orders WHERE user_id=?", (found["user_id"],)
            )
            cnt = total_orders["cnt"] if total_orders else 0
            await msg.reply_text(
                user_info_text(found, cnt),
                parse_mode="HTML",
                reply_markup=user_mgr_kb(found["user_id"]),
            )
            return

        if state == "WAITING_USERMGR_BAL":
            target_uid = st.get("target_uid")
            USER_STATE.pop(uid, None)
            clean = text.replace(",", "").replace("٬", "").replace(" ", "")
            if not clean.lstrip("-").isdigit():
                await msg.reply_text("⚠️ عدد معتبر وارد کنید:")
                return
            new_bal = int(clean)
            execute("UPDATE users SET balance=? WHERE user_id=?", (new_bal, target_uid))
            found = db_get_user(target_uid)
            cnt_r = row("SELECT COUNT(*) as cnt FROM orders WHERE user_id=?", (target_uid,))
            cnt = cnt_r["cnt"] if cnt_r else 0
            await msg.reply_text(
                f"✅ موجودی کاربر به <b>{fmt(new_bal)}</b> تغییر یافت.\n\n"
                + user_info_text(found, cnt),
                parse_mode="HTML",
                reply_markup=user_mgr_kb(target_uid),
            )
            return

        if state == "WAITING_USERMGR_MSG":
            target_uid = st.get("target_uid")
            USER_STATE.pop(uid, None)
            if not text:
                await msg.reply_text("✍️ لطفاً متن پیام را وارد کنید:")
                return
            try:
                await context.bot.send_message(chat_id=target_uid, text=text)
                await msg.reply_text("✅ پیام ارسال شد.")
            except Exception as e:
                await msg.reply_text(f"❌ خطا: {e}")
            found = db_get_user(target_uid)
            cnt_r = row("SELECT COUNT(*) as cnt FROM orders WHERE user_id=?", (target_uid,))
            cnt = cnt_r["cnt"] if cnt_r else 0
            await msg.reply_text(
                user_info_text(found, cnt),
                parse_mode="HTML",
                reply_markup=user_mgr_kb(target_uid),
            )
            return

        if state == "WAITING_BAN_ID":
            USER_STATE.pop(uid, None)
            if not text.lstrip("-").isdigit():
                await msg.reply_text("⚠️ آیدی عددی وارد کنید:")
                return
            target = int(text)
            if target == ADMIN_ID:
                await msg.reply_text("❌ نمی‌توان ادمین را مسدود کرد.")
                await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
                return
            db_ban_user(target)
            user = db_get_user(target)
            name = user["full_name"] if user else str(target)
            await msg.reply_text(f"🚫 کاربر <b>{name}</b> (<code>{target}</code>) مسدود شد.", parse_mode="HTML")
            await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
            return

        if state == "WAITING_UNBAN_ID":
            USER_STATE.pop(uid, None)
            if not text.lstrip("-").isdigit():
                await msg.reply_text("⚠️ آیدی عددی وارد کنید:")
                return
            target = int(text)
            db_unban_user(target)
            user = db_get_user(target)
            name = user["full_name"] if user else str(target)
            await msg.reply_text(f"✅ مسدودیت <b>{name}</b> (<code>{target}</code>) برداشته شد.", parse_mode="HTML")
            await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
            return

        if state == "WAITING_DISCOUNT_CODE":
            USER_STATE[uid] = {**st, "state": "WAITING_DISCOUNT_PERCENT", "d_code": text.upper()}
            await msg.reply_text("💯 درصد تخفیف را وارد کنید (عدد ۱ تا ۱۰۰):")
            return

        if state == "WAITING_DISCOUNT_PERCENT":
            if not text.isdigit() or not (1 <= int(text) <= 100):
                await msg.reply_text("⚠️ عدد بین ۱ تا ۱۰۰ وارد کنید:")
                return
            USER_STATE[uid] = {**st, "state": "WAITING_DISCOUNT_MAX_USES", "d_percent": int(text)}
            await msg.reply_text("🔢 حداکثر تعداد استفاده را وارد کنید:")
            return

        if state == "WAITING_DISCOUNT_MAX_USES":
            if not text.isdigit() or int(text) < 1:
                await msg.reply_text("⚠️ عدد معتبر وارد کنید:")
                return
            USER_STATE[uid] = {**st, "state": "WAITING_DISCOUNT_EXPIRES", "d_max": int(text)}
            await msg.reply_text(
                "📅 تاریخ انقضا را وارد کنید (فرمت: YYYY-MM-DD)\n"
                "برای بدون انقضا بنویسید: <code>ندارد</code>",
                parse_mode="HTML",
            )
            return

        if state == "WAITING_DISCOUNT_EXPIRES":
            expires = None
            if text.strip().lower() not in ("ندارد", "0", "-", "no", "none"):
                import datetime as _dt2
                try:
                    _dt2.datetime.strptime(text.strip(), "%Y-%m-%d")
                    expires = text.strip()
                except ValueError:
                    await msg.reply_text("⚠️ فرمت تاریخ اشتباه است. مثال: 2025-12-31\nیا بنویسید: ندارد")
                    return
            d_code   = st.get("d_code", "")
            d_pct    = st.get("d_percent", 0)
            d_max    = st.get("d_max", 1)
            USER_STATE.pop(uid, None)
            try:
                db_create_discount(d_code, d_pct, d_max, expires)
            except Exception as e:
                await msg.reply_text(f"❌ خطا: {e}")
                await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
                return
            exp_text = expires if expires else "ندارد"
            await msg.reply_text(
                f"✅ <b>کد تخفیف ایجاد شد</b>\n\n"
                f"🏷 کد: <code>{d_code}</code>\n"
                f"💯 درصد: <b>{d_pct}%</b>\n"
                f"🔢 حداکثر استفاده: <b>{d_max}</b>\n"
                f"📅 انقضا: <b>{exp_text}</b>",
                parse_mode="HTML",
            )
            await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
            return

        if state == "WAITING_EDIT_WELCOME":
            USER_STATE.pop(uid, None)
            set_text("welcome_text", text)
            await msg.reply_text(
                f"✅ <b>متن خوش‌آمدگویی ذخیره شد.</b>\n\n"
                f"پیش‌نمایش:\n{text.format(name='کاربر')}",
                parse_mode="HTML",
            )
            await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
            return

        if state == "WAITING_EDIT_MAINTENANCE":
            USER_STATE.pop(uid, None)
            set_text("bot_off_text", text)
            await msg.reply_text(
                f"✅ <b>متن تعمیرات ذخیره شد.</b>\n\nپیش‌نمایش:\n{text}",
                parse_mode="HTML",
            )
            await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
            return

        if state == "WAITING_EDIT_RULES":
            USER_STATE.pop(uid, None)
            set_text("rules_text", text)
            await msg.reply_text(
                f"✅ <b>متن قوانین ذخیره شد.</b>\n\nپیش‌نمایش:\n{text}",
                parse_mode="HTML",
            )
            await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
            return

        if state == "WAITING_BROADCAST_MSG":
            USER_STATE.pop(uid, None)
            all_users = db_get_all_users()
            total = len(all_users)
            success = 0
            failed = 0
            status_msg = await msg.reply_text(
                f"📢 در حال ارسال به <b>{total}</b> کاربر...", parse_mode="HTML"
            )
            for _u in all_users:
                target_uid = _u["user_id"]
                if target_uid == ADMIN_ID:
                    success += 1
                    continue
                try:
                    await context.bot.send_message(chat_id=target_uid, text=text)
                    success += 1
                except Exception:
                    failed += 1
            await status_msg.edit_text(
                f"📢 <b>ارسال همگانی تمام شد</b>\n\n"
                f"👥 کل کاربران: <b>{total}</b>\n"
                f"✅ موفق: <b>{success}</b>\n"
                f"❌ ناموفق: <b>{failed}</b>",
                parse_mode="HTML",
            )
            await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
            return

        if state == "WAITING_CARD_NUMBER":
            set_setting("card_number", text)
            USER_STATE[uid] = {"state": "WAITING_CARD_HOLDER"}
            await msg.reply_text("👤 نام صاحب کارت را وارد کنید:")
            return

        if state == "WAITING_CARD_HOLDER":
            set_setting("card_holder", text)
            USER_STATE.pop(uid, None)
            await msg.reply_text(
                f"✅ اطلاعات کارت ذخیره شد.\n\n{card_text()}", parse_mode="HTML"
            )
            await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
            return

        if state == "WAITING_ADD_CONFIG_TEXT":
            plan_name = st.get("plan_name", "")
            USER_STATE[uid] = {"state": "WAITING_ADD_CONFIG_SUBLINK", "plan_name": plan_name, "config_text": text}
            await msg.reply_text(
                "🔗 لینک سابسکریپشن را وارد کنید.\n\n"
                "اگر ندارید بنویسید: <b>skip</b>",
                parse_mode="HTML",
            )
            return

        if state == "WAITING_ADD_CONFIG_SUBLINK":
            plan_name = st.get("plan_name", "")
            config_text = st.get("config_text", "")
            sub_link = None if (not text or text.strip().lower() in ("skip", "-", "ندارد")) else text.strip()
            USER_STATE[uid] = {"state": "WAITING_ADD_CONFIG_QR", "plan_name": plan_name, "config_text": config_text, "sub_link": sub_link}
            await msg.reply_text(
                "📷 تصویر QR Code را ارسال کنید.\n\n"
                "اگر ندارید بنویسید: <b>skip</b>",
                parse_mode="HTML",
            )
            return

        if state == "WAITING_ADD_CONFIG_QR":
            plan_name = st.get("plan_name", "")
            config_text = st.get("config_text", "")
            sub_link = st.get("sub_link")
            qr_file_id = None
            if msg.photo:
                qr_file_id = msg.photo[-1].file_id
            USER_STATE.pop(uid, None)
            db_add_config(plan_name, config_text, sub_link=sub_link, qr_file_id=qr_file_id)
            avail = len(rows("SELECT id FROM configs WHERE plan_name=? AND status='available'", (plan_name,)))
            await msg.reply_text(
                f"✅ کانفیگ برای پلن <b>{plan_name}</b> ذخیره شد.\n"
                f"موجودی این پلن: <b>{avail}</b> کانفیگ",
                parse_mode="HTML",
            )
            await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
            return

        if state == "WAITING_CUSTOM_MSG":
            order_id = st.get("order_id")
            customer_id = st.get("customer_id")
            USER_STATE.pop(uid, None)
            try:
                await context.bot.send_message(
                    chat_id=customer_id,
                    text=f"📩 <b>پیام از پشتیبانی:</b>\n\n{text}",
                    parse_mode="HTML",
                )
                execute(
                    "INSERT INTO message_log (order_id, admin_id, customer_id, msg_type, content) VALUES (?,?,?,?,?)",
                    (order_id, uid, customer_id, "custom", text),
                )
                await msg.reply_text(
                    "✅ پیام با موفقیت ارسال شد.",
                    reply_markup=InlineKeyboardMarkup(
                        [
                            [
                                InlineKeyboardButton(
                                    "📬 ارسال مجدد",
                                    callback_data=f"msg_user_{order_id}",
                                ),
                                InlineKeyboardButton(
                                    "🔙 بازگشت", callback_data="admin_back"
                                ),
                            ]
                        ]
                    ),
                )
            except Exception as e:
                await msg.reply_text(f"❌ خطا در ارسال پیام: {e}")
            return

        if state == "WAITING_CONFIG":
            order_id = st.get("order_id")
            customer_id = st.get("customer_id")
            plan_name = st.get("plan_name", "")
            USER_STATE[uid] = {**st, "state": "WAITING_CONFIG_SUBLINK", "manual_config": text}
            await msg.reply_text(
                "🔗 لینک سابسکریپشن را وارد کنید.\n\n"
                "اگر ندارید بنویسید: <b>skip</b>",
                parse_mode="HTML",
            )
            return

        if state == "WAITING_CONFIG_SUBLINK":
            order_id = st.get("order_id")
            customer_id = st.get("customer_id")
            plan_name = st.get("plan_name", "")
            manual_config = st.get("manual_config", "")
            sub_link = None if (not text or text.strip().lower() in ("skip", "-", "ندارد")) else text.strip()
            USER_STATE[uid] = {**st, "state": "WAITING_CONFIG_QR", "sub_link": sub_link}
            await msg.reply_text(
                "📷 تصویر QR Code را ارسال کنید.\n\n"
                "اگر ندارید بنویسید: <b>skip</b>",
                parse_mode="HTML",
            )
            return

        if state == "WAITING_CONFIG_QR":
            order_id = st.get("order_id")
            customer_id = st.get("customer_id")
            plan_name = st.get("plan_name", "")
            manual_config = st.get("manual_config", "")
            sub_link = st.get("sub_link")
            qr_file_id = None
            if msg.photo:
                qr_file_id = msg.photo[-1].file_id
            USER_STATE.pop(uid, None)
            execute(
                "INSERT INTO configs (plan_name, config_text, sub_link, qr_file_id, status, order_id) VALUES (?,?,?,?,'sold',?)",
                (plan_name, manual_config, sub_link, qr_file_id, order_id),
            )
            parts = [
                f"✅ <b>سفارش شما با موفقیت ثبت شد</b>\n",
                f"📦 پلن: <b>{plan_name}</b>",
            ]
            if sub_link:
                parts.append(f"\n🔗 <b>Subscription Link:</b>\n<code>{sub_link}</code>")
            parts.append(f"\n📋 <b>Configuration:</b>\n<code>{manual_config}</code>")
            try:
                await context.bot.send_message(chat_id=customer_id, text="\n".join(parts), parse_mode="HTML")
                if qr_file_id:
                    await context.bot.send_photo(chat_id=customer_id, photo=qr_file_id, caption="📷 QR Code")
                execute(
                    "INSERT INTO message_log (order_id, admin_id, customer_id, msg_type, content) VALUES (?,?,?,?,?)",
                    (order_id, uid, customer_id, "config", manual_config),
                )
                await msg.reply_text(
                    "✅ کانفیگ با موفقیت ارسال شد.",
                    reply_markup=InlineKeyboardMarkup(
                        [
                            [
                                InlineKeyboardButton(
                                    "📦 ارسال مجدد",
                                    callback_data=f"send_config_{order_id}",
                                ),
                                InlineKeyboardButton(
                                    "🔙 بازگشت", callback_data="admin_back"
                                ),
                            ]
                        ]
                    ),
                )
            except Exception as e:
                await msg.reply_text(f"❌ خطا در ارسال کانفیگ: {e}")
            return

        if state == "WAITING_MSG_CUSTOMER_ID":
            clean = text.strip()
            if not clean.isdigit():
                await msg.reply_text("⚠️ آیدی عددی وارد کنید:")
                return
            target = db_get_user(int(clean))
            if not target:
                await msg.reply_text("❌ کاربر یافت نشد.")
                return
            USER_STATE[uid] = {
                "state": "WAITING_MSG_CUSTOMER_TEXT",
                "customer_id": int(clean),
                "customer_name": target["full_name"],
            }
            await msg.reply_text(
                f"✍️ پیام برای <b>{target['full_name']}</b> را بنویسید:",
                parse_mode="HTML",
            )
            return

        if state == "WAITING_MSG_CUSTOMER_TEXT":
            customer_id = st.get("customer_id")
            customer_name = st.get("customer_name", "")
            USER_STATE.pop(uid, None)
            try:
                await context.bot.send_message(
                    chat_id=customer_id,
                    text=f"📩 <b>پیام از پشتیبانی:</b>\n\n{text}",
                    parse_mode="HTML",
                )
                await msg.reply_text(
                    f"✅ پیام به <b>{customer_name}</b> ارسال شد.", parse_mode="HTML"
                )
            except Exception as e:
                await msg.reply_text(f"❌ خطا: {e}")
            await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
            return

    # ── FSM: support message from user ───────────────────────────────────────
    if state == "WAITING_SUPPORT_MSG":
        has_media = bool(msg.photo or msg.document or msg.video or msg.voice)
        if not text and not has_media:
            await msg.reply_text("✍️ لطفاً پیام، عکس، فایل، ویدیو یا ویس ارسال کنید.")
            return
        USER_STATE.pop(uid, None)
        u = db_get_user(uid)
        uname = f"@{u['username']}" if u and u.get("username") else "—"
        fname = u["full_name"] if u else "ناشناس"
        try:
            await context.bot.send_message(
                chat_id=ADMIN_ID,
                text=(
                    f"🎧 <b>پیام پشتیبانی</b>\n\n"
                    f"👤 <b>{fname}</b> ({uname})\n"
                    f"🆔 آیدی: <code>{uid}</code>"
                ),
                parse_mode="HTML",
                reply_markup=InlineKeyboardMarkup(
                    [[InlineKeyboardButton("📩 پاسخ به کاربر", callback_data=f"support_reply_{uid}")]]
                ),
            )
            sent = await context.bot.forward_message(
                chat_id=ADMIN_ID,
                from_chat_id=msg.chat_id,
                message_id=msg.message_id,
            )
            SUPPORT_MSG_MAP[sent.message_id] = uid
        except Exception:
            pass
        await msg.reply_text(
            "✅ پیام شما به پشتیبانی ارسال شد.\nبه زودی پاسخ خواهید گرفت.",
            reply_markup=get_main_menu(uid),
        )
        return

    # ── FSM: user discount code entry ─────────────────────────────────────────
    if state == "WAITING_SERVICE_NAME":
        plan_id   = st.get("plan_id")
        price     = st.get("price")
        d_code    = st.get("d_code")
        d_code_id = st.get("d_code_id")
        d_amount  = st.get("d_amount", 0)
        d_orig    = st.get("d_orig", price)
        d_pct     = st.get("d_pct", 0)
        service_name = (text.strip() if text and text.strip() else "سرویس من")
        plan = row("SELECT * FROM plans WHERE id=?", (int(plan_id),))
        if not plan:
            USER_STATE.pop(uid, None)
            await msg.reply_text("❌ پلن موردنظر پیدا نشد.", reply_markup=get_main_menu(uid))
            return
        u = db_get_user(uid)
        bal = int(u["balance"]) if u else 0
        if bal < price:
            shortage = price - bal
            USER_STATE.pop(uid, None)
            await msg.reply_text(
                f"❌ <b>موجودی کافی نیست</b>\n\n"
                f"💰 قیمت: <b>{fmt(price)}</b>\n"
                f"💳 موجودی شما: <b>{fmt(bal)}</b>\n"
                f"⚠️ کمبود: <b>{fmt(shortage)}</b>",
                parse_mode="HTML",
                reply_markup=get_main_menu(uid),
            )
            return
        db_deduct_balance(uid, price)
        order_id = db_create_order(
            uid, plan,
            pay_method="wallet",
            discount_code=d_code,
            discount_amount=d_amount,
            service_name=service_name,
        )
        db_approve_order(order_id)
        if d_code_id:
            db_use_discount(d_code_id, uid)
        USER_STATE.pop(uid, None)
        new_bal = int(db_get_user(uid)["balance"])
        cfg = db_pop_config(plan["name"])
        if cfg:
            db_mark_config_sold(cfg["id"], order_id)
            execute(
                "INSERT INTO message_log (order_id, admin_id, customer_id, msg_type, content) VALUES (?,?,?,?,?)",
                (order_id, ADMIN_ID, uid, "config", cfg["config_text"]),
            )
            discount_line = (
                f"🏷 تخفیف ({d_pct}%): <b>-{fmt(d_amount)}</b>\n" if d_code else ""
            )
            delivery_parts = [
                f"✅ <b>سفارش شما با موفقیت ثبت شد</b>\n",
                f"📝 سرویس: <b>{service_name}</b>",
                f"📦 پلن: <b>{plan['name']}</b>",
                (f"💰 قیمت اصلی: <b>{fmt(d_orig)}</b>" if d_code else ""),
                (f"🏷 تخفیف ({d_pct}%): <b>-{fmt(d_amount)}</b>" if d_code else ""),
                f"💸 مبلغ کسر شده: <b>{fmt(price)}</b>",
                f"💳 موجودی باقیمانده: <b>{fmt(new_bal)}</b>",
                f"شماره سفارش: <b>#{order_id}</b>",
            ]
            delivery_parts = [p for p in delivery_parts if p]
            if cfg["sub_link"]:
                delivery_parts.append(f"\n🔗 <b>Subscription Link:</b>\n<code>{cfg['sub_link']}</code>")
            delivery_parts.append(f"\n📋 <b>Configuration:</b>\n<code>{cfg['config_text']}</code>")
            await msg.reply_text(
                "\n".join(delivery_parts),
                parse_mode="HTML",
                reply_markup=get_main_menu(uid),
            )
            if cfg["qr_file_id"]:
                try:
                    await context.bot.send_photo(chat_id=uid, photo=cfg["qr_file_id"], caption="📷 QR Code")
                except Exception:
                    pass
        else:
            discount_line = (
                f"🏷 تخفیف ({d_pct}%): <b>-{fmt(d_amount)}</b>\n" if d_code else ""
            )
            await msg.reply_text(
                f"✅ <b>خرید با موفقیت انجام شد</b>\n\n"
                f"📝 سرویس: <b>{service_name}</b>\n"
                f"📦 پلن: <b>{plan['name']}</b>\n"
                + (f"💰 قیمت اصلی: <b>{fmt(d_orig)}</b>\n" if d_code else "")
                + discount_line
                + f"💸 مبلغ کسر شده: <b>{fmt(price)}</b>\n"
                f"💳 موجودی باقیمانده: <b>{fmt(new_bal)}</b>\n"
                f"شماره سفارش: <b>#{order_id}</b>\n\n"
                "⏳ کانفیگ به زودی توسط ادمین ارسال می‌شود.",
                parse_mode="HTML",
                reply_markup=get_main_menu(uid),
            )
        try:
            config_note = (
                "✅ کانفیگ خودکار ارسال شد"
                if cfg
                else "⚠️ موجودی کانفیگ ندارید — باید دستی ارسال کنید"
            )
            await context.bot.send_message(
                chat_id=ADMIN_ID,
                text=(
                    f"🛒 <b>سفارش جدید #{order_id}</b>\n\n"
                    f"👤 {u['full_name']} (@{u['username'] or 'N/A'}) [ID: {uid}]\n"
                    f"📝 نام سرویس: <b>{service_name}</b>\n"
                    f"📦 {plan['name']} — {fmt(plan['price'])}\n"
                    f"💳 موجودی باقیمانده کاربر: {fmt(new_bal)}\n\n"
                    f"{config_note}"
                ),
                parse_mode="HTML",
                reply_markup=post_approve_kb(order_id),
            )
        except Exception:
            pass
        return

    if state == "WAITING_USER_DISCOUNT_CODE":
        logger.info("DISCOUNT_FSM uid=%s text=%r plan_id=%s", uid, text[:30] if text else "", st.get("plan_id"))
        try:
            plan_id = st.get("plan_id")
            if not plan_id:
                USER_STATE.pop(uid, None)
                await msg.reply_text("❌ پلن انتخابی معتبر نیست. لطفاً دوباره پلن انتخاب کنید.", reply_markup=get_main_menu(uid))
                return
            plan = row("SELECT * FROM plans WHERE id=?", (int(plan_id),))
            cancel_kb = InlineKeyboardMarkup(
                [[InlineKeyboardButton("❌ انصراف", callback_data=f"plan_{plan_id}")]]
            )
            if not plan:
                USER_STATE.pop(uid, None)
                await msg.reply_text("❌ پلن موردنظر پیدا نشد.", reply_markup=get_main_menu(uid))
                return
            if not text:
                await msg.reply_text(
                    "🏷 لطفاً کد تخفیف خود را به صورت متن وارد کنید:", reply_markup=cancel_kb
                )
                return
            dc, err = db_validate_discount(text.strip(), uid)
            if err:
                await msg.reply_text(
                    f"{err}\n\nکد دیگری وارد کنید یا دکمه انصراف را بزنید:",
                    reply_markup=cancel_kb,
                )
                return
            original = int(plan["price"])
            pct = int(dc["percentage"])
            discount_amount = int(original * pct / 100)
            final_price = max(0, original - discount_amount)
            USER_STATE[uid] = {
                "state": "DISCOUNT_APPLIED",
                "plan_id": int(plan_id),
                "code": str(dc["code"]),
                "code_id": int(dc["id"]),
                "percentage": pct,
                "discount_amount": discount_amount,
                "original_price": original,
                "final_price": final_price,
            }
            u_now = db_get_user(uid)
            bal_now = int(u_now["balance"]) if u_now and u_now["balance"] is not None else 0
            price_lines = (
                f"📦 پلن: <b>{plan['name']}</b>\n"
                f"💰 قیمت اصلی: <b>{fmt(original)}</b>\n"
                f"🏷 تخفیف ({pct}%): <b>-{fmt(discount_amount)}</b>\n"
                f"✅ قیمت نهایی: <b>{fmt(final_price)}</b>\n"
                f"💳 موجودی کیف پول: <b>{fmt(bal_now)}</b>"
            )
            if bal_now >= final_price:
                await msg.reply_text(
                    f"✅ <b>کد تخفیف اعمال شد!</b>\n\n"
                    f"{price_lines}\n\n"
                    "آیا تأیید می‌کنید؟",
                    parse_mode="HTML",
                    reply_markup=InlineKeyboardMarkup(
                        [
                            [InlineKeyboardButton("💰 پرداخت با تخفیف", callback_data=f"confirm_buy_{plan_id}")],
                            [InlineKeyboardButton("❌ انصراف", callback_data="show_plans")],
                        ]
                    ),
                )
            else:
                shortage = final_price - bal_now
                await msg.reply_text(
                    f"✅ <b>کد تخفیف اعمال شد!</b>\n\n"
                    f"{price_lines}\n"
                    f"⚠️ کمبود: <b>{fmt(shortage)}</b>\n\n"
                    "برای پرداخت ابتدا موجودی خود را شارژ کنید.\n"
                    "پس از شارژ، دکمه پرداخت را بزنید — کد تخفیف ذخیره است.",
                    parse_mode="HTML",
                    reply_markup=InlineKeyboardMarkup(
                        [
                            [InlineKeyboardButton("🏦 کارت به کارت", callback_data="wallet_add")],
                            [InlineKeyboardButton("💰 پرداخت با تخفیف", callback_data=f"confirm_buy_{plan_id}")],
                            [InlineKeyboardButton("❌ انصراف", callback_data="show_plans")],
                        ]
                    ),
                )
        except Exception as _exc:
            logger.exception("DISCOUNT_FSM unhandled error uid=%s: %s", uid, _exc)
            await msg.reply_text(
                "⚠️ خطایی رخ داد. لطفاً دوباره کد را وارد کنید یا /start را بزنید.",
                reply_markup=InlineKeyboardMarkup(
                    [[InlineKeyboardButton("🏠 منوی اصلی", callback_data="show_plans")]]
                ),
            )
        return

    # ── FSM: admin support reply ──────────────────────────────────────────────
    # ── Admin: native Telegram reply → auto-route to user ────────────────────
    if uid == ADMIN_ID and msg.reply_to_message:
        replied_id = msg.reply_to_message.message_id
        target_uid = SUPPORT_MSG_MAP.get(replied_id)
        if target_uid:
            has_content = bool(msg.text or msg.photo or msg.document or msg.video or msg.voice)
            if not has_content:
                await msg.reply_text("✍️ لطفاً متن، عکس، فایل، ویدیو یا ویس ارسال کنید.")
                return
            try:
                await context.bot.send_message(
                    chat_id=target_uid,
                    text="📩 <b>پاسخ پشتیبانی:</b>",
                    parse_mode="HTML",
                )
                await context.bot.copy_message(
                    chat_id=target_uid,
                    from_chat_id=msg.chat_id,
                    message_id=msg.message_id,
                )
                customer = db_get_user(target_uid)
                cname = customer["full_name"] if customer else str(target_uid)
                await msg.reply_text(f"✅ پاسخ به <b>{cname}</b> ارسال شد.", parse_mode="HTML")
            except Exception as e:
                await msg.reply_text(f"❌ خطا در ارسال پاسخ: {e}")
            return

    if state == "WAITING_SUPPORT_REPLY" and uid == ADMIN_ID:
        customer_id = st.get("customer_id")
        customer_name = st.get("customer_name", "کاربر")
        has_content = bool(text or msg.photo or msg.document or msg.video or msg.voice)
        if not has_content:
            await msg.reply_text("✍️ لطفاً متن، عکس، فایل، ویدیو یا ویس ارسال کنید.")
            return
        USER_STATE.pop(uid, None)
        try:
            await context.bot.send_message(
                chat_id=customer_id,
                text="📩 <b>پاسخ پشتیبانی:</b>",
                parse_mode="HTML",
            )
            await context.bot.copy_message(
                chat_id=customer_id,
                from_chat_id=msg.chat_id,
                message_id=msg.message_id,
            )
            await msg.reply_text(
                f"✅ پاسخ به <b>{customer_name}</b> ارسال شد.", parse_mode="HTML"
            )
        except Exception as e:
            await msg.reply_text(f"❌ خطا در ارسال پاسخ: {e}")
        await msg.reply_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
        return

    # ── User menu buttons ─────────────────────────────────────────────────────
    if text == "🛒 خرید سرویس":
        buttons = [
            [InlineKeyboardButton(DURATION_LABELS[d], callback_data=f"duration_{d}")]
            for d in DURATION_ORDER
        ]
        await msg.reply_text(
            "⏱ مدت سرویس موردنظر را انتخاب کنید:",
            reply_markup=InlineKeyboardMarkup(buttons),
        )

    elif text == "🧪 اکانت تست":
        if db_user_has_trial(uid):
            await msg.reply_text("❌ شما قبلاً اکانت تست دریافت کرده‌اید.")
            return
        trial = db_get_available_trial()
        if not trial:
            await msg.reply_text(
                "⚠️ در حال حاضر اکانت تست موجود نیست.\n"
                "لطفاً بعداً دوباره امتحان کنید یا با پشتیبانی تماس بگیرید."
            )
            return
        db_assign_trial(trial["id"], uid)
        parts = ["🧪 <b>اکانت تست شما آماده است!</b>\n"]
        if trial.get("sub_link"):
            parts.append(f"🔗 <b>لینک اشتراک:</b>\n<code>{trial['sub_link']}</code>\n")
        parts.append(f"📋 <b>اطلاعات کانفیگ:</b>\n<code>{trial['config_text']}</code>")
        await msg.reply_text("\n".join(parts), parse_mode="HTML")
        if trial.get("qr_file_id"):
            await msg.reply_photo(
                photo=trial["qr_file_id"],
                caption="📷 QR Code اکانت تست شما",
            )
        try:
            u = db_get_user(uid)
            await context.bot.send_message(
                chat_id=ADMIN_ID,
                text=(
                    f"🧪 <b>اکانت تست تحویل داده شد</b>\n\n"
                    f"👤 {u.get('full_name') or uid} (@{u.get('username') or 'N/A'})\n"
                    f"🆔 ID: <code>{uid}</code>\n"
                    f"📦 اکانت تست #{trial['id']}"
                ),
                parse_mode="HTML",
            )
        except Exception:
            pass

    elif text == "💰 کیف پول":
        u = db_get_user(uid)
        bal = u["balance"] if u else 0
        await msg.reply_text(
            f"💰 <b>کیف پول</b>\n\nموجودی فعلی: <b>{fmt(bal)}</b>",
            parse_mode="HTML",
            reply_markup=wallet_kb(uid),
        )

    elif text == "👤 پروفایل":
        u = db_get_user(uid)
        verified = u and int(u.get("verified", 0))
        verif_badge = "✅ تایید شده" if verified else "❌ احراز نشده"
        await msg.reply_text(
            f"👤 <b>پروفایل</b>\n\n"
            f"آیدی: <code>{uid}</code>\n"
            f"نام: {update.effective_user.full_name}\n"
            f"موجودی: <b>{fmt(u['balance'] if u else 0)}</b>\n"
            f"احراز هویت: {verif_badge}",
            parse_mode="HTML",
        )

    elif text == "📩 درخواست احراز هویت":
        u = db_get_user(uid)
        if u and int(u.get("verified", 0)):
            await msg.reply_text("✅ حساب شما قبلاً تایید شده است.")
            return
        USER_STATE[uid] = {"state": "WAITING_VERIF_PHOTO"}
        await msg.reply_text(
            "📌 <b>احراز هویت برای خرید از Ghost VPN</b>\n\n"
            "برای تکمیل احراز هویت:\n\n"
            "1️⃣ از <b>کارت بانکی که واریز با آن انجام شده</b> عکس بگیرید\n"
            "2️⃣ یک برگه کنار کارت بگذارید\n"
            "3️⃣ روی آن بنویسید:\n\n"
            "<b>خرید VPN از Ghost VPN</b>\n\n"
            "⚠️ <b>شرایط عکس:</b>\n"
            "• فقط ۴ رقم آخر کارت مشخص باشد\n"
            "• CVV2 و تاریخ انقضا پوشانده شود\n"
            "• عکس واضح و بدون ادیت باشد\n\n"
            "عکس را ارسال کنید 👇",
            parse_mode="HTML",
        )

    elif text == "📦 سرویس‌های من":
        order_list = rows(
            "SELECT id, plan_name, plan_price, status, created_at, service_name FROM orders "
            "WHERE user_id=? ORDER BY created_at DESC LIMIT 10",
            (uid,),
        )
        if not order_list:
            await msg.reply_text("📦 هنوز سرویسی خریداری نکرده‌ای.")
            return
        em = {"pending": "⏳", "approved": "✅", "rejected": "❌"}
        lines = ["📦 <b>سرویس‌های من</b>\n"]
        buttons = []
        for o in order_list:
            sname = o["service_name"] or "سرویس من"
            status_icon = em.get(o["status"], "❓")
            lines.append(
                f"{status_icon} <b>{sname}</b> — {o['plan_name']} | {o['created_at'][:10]}"
            )
            buttons.append([InlineKeyboardButton(
                f"{status_icon} {sname} — {o['plan_name']}",
                callback_data=f"show_order_{o['id']}"
            )])
        await msg.reply_text(
            "\n".join(lines),
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(buttons),
        )

    elif text == "📋 قوانین":
        rules = get_text("rules_text", "📋 قوانین استفاده از Ghost VPN")
        await msg.reply_text(rules, parse_mode="HTML")

    elif text == "🎧 پشتیبانی":
        USER_STATE[uid] = {"state": "WAITING_SUPPORT_MSG"}
        await msg.reply_text(
            "🎧 پشتیبانی\n\n"
            "لطفاً پیام، عکس، فایل، ویدیو یا ویس خود را ارسال کنید.\n\n"
            "درخواست شما ثبت شده و توسط پشتیبانی بررسی خواهد شد.",
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("❌ انصراف", callback_data="support_cancel")]]
            ),
        )


# ═════════════════════════════════════════════════════════════════════════════
#  CALLBACK ROUTER
# ═════════════════════════════════════════════════════════════════════════════
async def button_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    await query.answer()
    data = query.data
    uid = query.from_user.id

    if data == "check_join":
        if await is_channel_member(context.bot, uid):
            db_register_user(update.effective_user)
            try:
                await query.edit_message_text(
                    "✅ <b>عضویت شما تایید شد</b>\n\nاکنون می‌توانید از ربات استفاده کنید.",
                    parse_mode="HTML",
                )
            except Exception:
                pass
            await context.bot.send_message(
                chat_id=uid,
                text=f"👻 به <b>Ghost VPN</b> خوش اومدی، <b>{update.effective_user.first_name}</b>!\n\nاز منوی زیر انتخاب کنید:",
                parse_mode="HTML",
                reply_markup=get_main_menu(uid),
            )
        else:
            await query.answer("❌ هنوز عضو کانال نیستید", show_alert=True)
        return

    if not await gate_callback(update, context):
        return

    if data == "request_verif":
        u = db_get_user(uid)
        if u and int(u.get("verified", 0)):
            await query.edit_message_text("✅ حساب شما قبلاً تایید شده است.")
            return
        USER_STATE[uid] = {"state": "WAITING_VERIF_PHOTO"}
        await query.edit_message_text(
            "📌 <b>احراز هویت برای خرید از Ghost VPN</b>\n\n"
            "برای تکمیل احراز هویت:\n\n"
            "1️⃣ از <b>کارت بانکی که واریز با آن انجام شده</b> عکس بگیرید\n"
            "2️⃣ یک برگه کنار کارت بگذارید\n"
            "3️⃣ روی آن بنویسید:\n\n"
            "<b>خرید VPN از Ghost VPN</b>\n\n"
            "⚠️ فقط ۴ رقم آخر کارت مشخص باشد\n"
            "CVV2 و تاریخ انقضا پوشانده شود\n\n"
            "عکس را ارسال کنید 👇",
            parse_mode="HTML",
        )
        return

    if data == "wallet_menu":
        u = db_get_user(uid)
        bal = u["balance"] if u else 0
        await query.edit_message_text(
            f"💰 <b>کیف پول</b>\n\nموجودی فعلی: <b>{fmt(bal)}</b>",
            parse_mode="HTML",
            reply_markup=wallet_kb(uid),
        )
        return

    if data == "wallet_close":
        await query.edit_message_text("🏠 به منوی اصلی بازگشتید.")
        return

    if data == "wallet_balance":
        u = db_get_user(uid)
        bal = u["balance"] if u else 0
        await query.edit_message_text(
            f"💸 <b>موجودی کیف پول شما:</b>\n\n<b>{fmt(bal)}</b>",
            parse_mode="HTML",
            reply_markup=back_to_wallet,
        )
        return

    if data == "wallet_add":
        if not is_verified(uid):
            await query.edit_message_text(
                NOT_VERIFIED_TEXT, parse_mode="HTML", reply_markup=NOT_VERIFIED_KB
            )
            return
        USER_STATE[uid] = {"state": "WAITING_CHARGE_AMOUNT"}
        await query.edit_message_text(
            f"➕ <b>افزودن موجودی</b>\n\n{card_text()}\n\nمبلغ موردنظر را به تومان وارد کنید:",
            parse_mode="HTML",
            reply_markup=back_to_wallet,
        )
        return

    if data == "wallet_send_receipt":
        if not is_verified(uid):
            await query.edit_message_text(
                NOT_VERIFIED_TEXT, parse_mode="HTML", reply_markup=NOT_VERIFIED_KB
            )
            return
        USER_STATE[uid] = {"state": "WAITING_CHARGE_RECEIPT", "amount": 0}
        await query.edit_message_text(
            "📷 تصویر رسید پرداخت را ارسال کنید:", reply_markup=back_to_wallet
        )
        return

    if data == "wallet_add_tron":
        USER_STATE[uid] = {"state": "WAITING_TRON_AMOUNT"}
        await query.edit_message_text(
            "💎 <b>شارژ کیف پول با ترون (TRC20)</b>\n\n"
            "آدرس کیف پول:\n"
            f"<code>{TRON_WALLET}</code>\n\n"
            "پس از واریز، مقدار ترون و شناسه تراکنش (TXID) را ارسال کنید.\n\n"
            "مقدار ترون (TRX) را وارد کنید 👇",
            parse_mode="HTML",
            reply_markup=back_to_wallet,
        )
        return

    if data == "show_plans":
        buttons = [
            [InlineKeyboardButton(DURATION_LABELS[d], callback_data=f"duration_{d}")]
            for d in DURATION_ORDER
        ]
        await query.edit_message_text(
            "⏱ مدت سرویس موردنظر را انتخاب کنید:",
            reply_markup=InlineKeyboardMarkup(buttons),
        )
        return

    if data.startswith("duration_"):
        duration = data[len("duration_"):]
        if duration not in DURATION_LABELS:
            await query.edit_message_text("❌ مدت نامعتبر است.")
            return
        plans = db_get_plans_by_duration(duration)
        label = DURATION_LABELS[duration]
        if not plans:
            await query.edit_message_text(
                f"{label}\n\nدر حال حاضر پلنی برای این مدت موجود نیست.",
                reply_markup=InlineKeyboardMarkup(
                    [[InlineKeyboardButton("🔙 بازگشت", callback_data="show_plans")]]
                ),
            )
            return
        buttons = [
            [InlineKeyboardButton(f"{p['name']} — {fmt(p['price'])}", callback_data=f"plan_{p['id']}")]
            for p in plans
        ]
        buttons.append([InlineKeyboardButton("🔙 بازگشت", callback_data="show_plans")])
        await query.edit_message_text(
            f"{label}\n\nپلن موردنظر را انتخاب کنید:",
            reply_markup=InlineKeyboardMarkup(buttons),
        )
        return

    if data.startswith("plan_") or data.startswith("buy_"):
        plan_id = int(data.split("_")[1])
        plan = row("SELECT * FROM plans WHERE id=?", (plan_id,))
        if not plan:
            await query.edit_message_text("این پلن دیگر موجود نیست.")
            return
        price = int(plan["price"])
        u = db_get_user(uid)
        bal = int(u["balance"]) if u else 0

        if bal < price:
            shortage = price - bal
            await query.edit_message_text(
                f"❌ <b>موجودی کافی نیست</b>\n\n"
                f"📦 پلن: <b>{plan['name']}</b>\n"
                f"💰 قیمت: <b>{fmt(price)}</b>\n"
                f"💳 موجودی شما: <b>{fmt(bal)}</b>\n"
                f"⚠️ کمبود: <b>{fmt(shortage)}</b>\n\n"
                "می‌توانید با کد تخفیف قیمت را کاهش دهید یا کیف پول را شارژ کنید.",
                parse_mode="HTML",
                reply_markup=InlineKeyboardMarkup(
                    [
                        [InlineKeyboardButton("🏷 کد تخفیف دارم", callback_data=f"apply_discount_{plan_id}")],
                        [InlineKeyboardButton("🏦 کارت به کارت", callback_data="wallet_add")],
                        [InlineKeyboardButton("💰 کیف پول", callback_data="wallet_menu")],
                        [InlineKeyboardButton("🔙 بازگشت", callback_data="show_plans")],
                    ]
                ),
            )
            return

        USER_STATE.pop(uid, None)  # clear any leftover discount state when re-selecting
        await query.edit_message_text(
            f"📦 <b>پلن انتخابی:</b> {plan['name']}\n"
            f"💰 <b>قیمت:</b> {fmt(price)}\n"
            f"💳 <b>موجودی کیف پول:</b> {fmt(bal)}\n\n"
            "آیا تأیید می‌کنید؟",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(
                [
                    [InlineKeyboardButton("💰 پرداخت از کیف پول", callback_data=f"confirm_buy_{plan_id}")],
                    [InlineKeyboardButton("🏷 کد تخفیف دارم", callback_data=f"apply_discount_{plan_id}")],
                    [InlineKeyboardButton("❌ انصراف", callback_data="show_plans")],
                ]
            ),
        )
        return

    if data.startswith("apply_discount_"):
        plan_id = int(data.split("_")[2])
        plan = row("SELECT * FROM plans WHERE id=?", (plan_id,))
        if not plan:
            await query.edit_message_text("این پلن دیگر موجود نیست.")
            return
        USER_STATE[uid] = {"state": "WAITING_USER_DISCOUNT_CODE", "plan_id": plan_id}
        await query.edit_message_text(
            f"🏷 <b>کد تخفیف</b>\n\n"
            f"📦 پلن: <b>{plan['name']}</b>\n"
            f"💰 قیمت اصلی: <b>{fmt(int(plan['price']))}</b>\n\n"
            "کد تخفیف خود را وارد کنید:",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("❌ انصراف", callback_data=f"plan_{plan_id}")]]
            ),
        )
        return

    if data.startswith("confirm_buy_"):
        plan_id = int(data.split("_")[2])
        plan = row("SELECT * FROM plans WHERE id=?", (plan_id,))
        if not plan:
            await query.edit_message_text("این پلن دیگر موجود نیست.")
            return

        # Check for a pending discount from FSM
        ds = USER_STATE.get(uid, {})
        has_discount = (
            ds.get("state") == "DISCOUNT_APPLIED"
            and ds.get("plan_id") == plan_id
        )
        if has_discount:
            price      = ds["final_price"]
            d_code     = ds["code"]
            d_code_id  = ds["code_id"]
            d_amount   = ds["discount_amount"]
            d_orig     = ds["original_price"]
            d_pct      = ds["percentage"]
        else:
            price     = int(plan["price"])
            d_code    = None
            d_code_id = None
            d_amount  = 0
            d_orig    = price
            d_pct     = 0

        u = db_get_user(uid)
        bal = int(u["balance"]) if u else 0

        if bal < price:
            shortage = price - bal
            await query.edit_message_text(
                f"❌ <b>موجودی کافی نیست</b>\n\n"
                f"💰 قیمت: <b>{fmt(price)}</b>\n"
                f"💳 موجودی شما: <b>{fmt(bal)}</b>\n"
                f"⚠️ کمبود: <b>{fmt(shortage)}</b>",
                parse_mode="HTML",
                reply_markup=InlineKeyboardMarkup(
                    [
                        [InlineKeyboardButton("🏦 کارت به کارت", callback_data="wallet_add")],
                        [InlineKeyboardButton("🔙 بازگشت", callback_data="show_plans")],
                    ]
                ),
            )
            return

        USER_STATE[uid] = {
            "state": "WAITING_SERVICE_NAME",
            "plan_id": plan_id,
            "price": price,
            "d_code": d_code,
            "d_code_id": d_code_id,
            "d_amount": d_amount,
            "d_orig": d_orig,
            "d_pct": d_pct,
        }
        await query.edit_message_text(
            "📝 یک نام برای سرویس خود انتخاب کنید.\n\n"
            "مثال:\n"
            "علی\n"
            "محمد\n"
            "حسن",
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("❌ انصراف", callback_data="show_plans")]]
            ),
        )
        return

    if data.startswith("approve_"):
        order_id = int(data.split("_")[1])
        order = db_get_order(order_id)
        if not order:
            await query.edit_message_text("سفارش یافت نشد.")
            return
        if order["status"] != "pending":
            await query.answer(f"این سفارش قبلاً {order['status']} شده.", show_alert=True)
            return
        db_approve_order(order_id)
        try:
            await context.bot.send_message(
                chat_id=order["uid"],
                text=f"✅ سفارش <b>#{order_id}</b> تایید شد.\nبه زودی کانفیگ ارسال می‌شود.",
                parse_mode="HTML",
            )
        except Exception:
            pass
        pay_label = "کیف پول 💰" if order["pay_method"] == "wallet" else "کارت به کارت 💳"
        summary = (
            f"✅ <b>سفارش #{order_id} تایید شده</b>\n\n"
            f"👤 {order['full_name']} (@{order['username'] or 'N/A'})\n"
            f"🆔 آیدی: <code>{order['uid']}</code>\n"
            f"📦 پلن: <b>{order['plan_name']}</b>\n"
            f"💰 مبلغ: <b>{fmt(order['plan_price'])}</b>\n"
            f"💳 روش پرداخت: {pay_label}\n\n"
            "اکنون می‌توانید پیام یا کانفیگ ارسال کنید:"
        )
        edit = query.edit_message_caption if query.message.caption else query.edit_message_text
        await edit(summary, parse_mode="HTML", reply_markup=post_approve_kb(order_id))
        return

    if data.startswith("reject_"):
        order_id = int(data.split("_")[1])
        order = db_get_order(order_id)
        if not order:
            await query.edit_message_text("سفارش یافت نشد.")
            return
        if order["status"] != "pending":
            await query.answer(f"این سفارش قبلاً {order['status']} شده.", show_alert=True)
            return
        db_reject_order(order_id)
        try:
            await context.bot.send_message(
                chat_id=order["uid"],
                text=f"❌ سفارش <b>#{order_id}</b> رد شد.\nبرای اطلاعات بیشتر با پشتیبانی تماس بگیرید.",
                parse_mode="HTML",
            )
        except Exception:
            pass
        txt = query.message.caption or query.message.text or ""
        edit = query.edit_message_caption if query.message.caption else query.edit_message_text
        await edit(txt + "\n\n❌ <b>رد شد</b>", parse_mode="HTML")
        return

    if data.startswith("msg_user_"):
        if uid != ADMIN_ID:
            return
        order_id = int(data.split("_")[2])
        order = db_get_order(order_id)
        if not order:
            await query.answer("سفارش یافت نشد.", show_alert=True)
            return
        USER_STATE[uid] = {
            "state": "WAITING_CUSTOM_MSG",
            "order_id": order_id,
            "customer_id": order["uid"],
        }
        logs = rows(
            "SELECT msg_type, content, sent_at FROM message_log WHERE order_id=? ORDER BY sent_at DESC LIMIT 5",
            (order_id,),
        )
        history = ""
        if logs:
            history = "\n\n📋 <b>پیام‌های قبلی:</b>\n" + "\n".join(
                f"• [{l['msg_type']}] {l['content'][:60]} — {l['sent_at'][:16]}"
                for l in logs
            )
        await query.edit_message_text(
            f"📩 <b>ارسال پیام به مشتری</b>\n\nسفارش #{order_id} | {order['full_name']}{history}\n\nپیام خود را وارد کنید:",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("🔙 بازگشت", callback_data=f"back_approve_{order_id}")]]
            ),
        )
        return

    if data.startswith("send_config_"):
        if uid != ADMIN_ID:
            return
        order_id = int(data.split("_")[2])
        order = db_get_order(order_id)
        if not order:
            await query.answer("سفارش یافت نشد.", show_alert=True)
            return
        cfg = db_pop_config(order["plan_name"])
        if cfg:
            db_mark_config_sold(cfg["id"], order_id)
            parts = [
                f"✅ <b>سفارش شما با موفقیت ثبت شد</b>\n",
                f"📦 پلن: <b>{order['plan_name']}</b>",
            ]
            if cfg["sub_link"]:
                parts.append(f"\n🔗 <b>Subscription Link:</b>\n<code>{cfg['sub_link']}</code>")
            parts.append(f"\n📋 <b>Configuration:</b>\n<code>{cfg['config_text']}</code>")
            try:
                await context.bot.send_message(
                    chat_id=order["uid"], text="\n".join(parts), parse_mode="HTML"
                )
                if cfg["qr_file_id"]:
                    await context.bot.send_photo(chat_id=order["uid"], photo=cfg["qr_file_id"], caption="📷 QR Code")
                execute(
                    "INSERT INTO message_log (order_id, admin_id, customer_id, msg_type, content) VALUES (?,?,?,?,?)",
                    (order_id, uid, order["uid"], "config", cfg["config_text"]),
                )
                await query.edit_message_text(
                    f"✅ کانفیگ از موجودی برای سفارش #{order_id} ارسال شد.",
                    reply_markup=back_to_panel,
                )
            except Exception as e:
                await query.edit_message_text(f"❌ خطا: {e}", reply_markup=back_to_panel)
            return

        USER_STATE[uid] = {
            "state": "WAITING_CONFIG",
            "order_id": order_id,
            "customer_id": order["uid"],
            "plan_name": order["plan_name"],
        }
        await query.edit_message_text(
            f"📦 <b>ارسال کانفیگ</b>\n\nسفارش #{order_id} | {order['full_name']}\nپلن: {order['plan_name']}\n\n"
            "⚠️ موجودی کانفیگ ندارید.\nلینک سابسکریپشن یا متن کانفیگ را وارد کنید:",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("🔙 بازگشت", callback_data=f"back_approve_{order_id}")]]
            ),
        )
        return

    if data.startswith("back_approve_"):
        if uid != ADMIN_ID:
            return
        order_id = int(data.split("_")[2])
        order = db_get_order(order_id)
        USER_STATE.pop(uid, None)
        if not order:
            await query.edit_message_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())
            return
        pay_label = "کیف پول 💰" if order["pay_method"] == "wallet" else "کارت به کارت 💳"
        summary = (
            f"✅ <b>سفارش #{order_id} تایید شده</b>\n\n"
            f"👤 {order['full_name']} (@{order['username'] or 'N/A'})\n"
            f"🆔 آیدی: <code>{order['uid']}</code>\n"
            f"📦 پلن: <b>{order['plan_name']}</b>\n"
            f"💰 مبلغ: <b>{fmt(order['plan_price'])}</b>\n"
            f"💳 روش پرداخت: {pay_label}\n\n"
            "اکنون می‌توانید پیام یا کانفیگ ارسال کنید:"
        )
        await query.edit_message_text(
            summary, parse_mode="HTML", reply_markup=post_approve_kb(order_id)
        )
        return

    if data.startswith("charge_approve_"):
        req_id = int(data.split("_")[2])
        req = db_get_charge(req_id)
        if not req:
            await query.edit_message_caption("درخواست یافت نشد.")
            return
        if req["status"] != "pending":
            await query.answer("این درخواست قبلاً پردازش شده.", show_alert=True)
            return
        execute("UPDATE charge_requests SET status='approved' WHERE id=?", (req_id,))
        db_add_balance(req["uid"], req["amount"])
        new_bal = db_get_user(req["uid"])["balance"]
        try:
            await context.bot.send_message(
                chat_id=req["uid"],
                text=f"✅ موجودی شما {fmt(req['amount'])} افزایش یافت.\n💰 موجودی فعلی: <b>{fmt(new_bal)}</b>",
                parse_mode="HTML",
            )
        except Exception:
            pass
        caption = query.message.caption or ""
        await query.edit_message_caption(
            caption + "\n\n✅ <b>تایید شد — موجودی افزوده شد</b>", parse_mode="HTML"
        )
        return

    if data.startswith("charge_reject_"):
        req_id = int(data.split("_")[2])
        req = db_get_charge(req_id)
        if not req:
            await query.edit_message_caption("درخواست یافت نشد.")
            return
        if req["status"] != "pending":
            await query.answer("این درخواست قبلاً پردازش شده.", show_alert=True)
            return
        execute("UPDATE charge_requests SET status='rejected' WHERE id=?", (req_id,))
        try:
            await context.bot.send_message(
                chat_id=req["uid"],
                text="❌ درخواست شارژ شما رد شد.\nبرای اطلاعات بیشتر با پشتیبانی تماس بگیرید.",
            )
        except Exception:
            pass
        caption = query.message.caption or ""
        await query.edit_message_caption(caption + "\n\n❌ <b>رد شد</b>", parse_mode="HTML")
        return

    if data.startswith("tron_approve_"):
        req_id = int(data.split("_")[2])
        req = db_get_tron_deposit(req_id)
        if not req:
            await query.edit_message_text("درخواست یافت نشد.")
            return
        if req["status"] != "pending":
            await query.answer("این درخواست قبلاً پردازش شده.", show_alert=True)
            return
        amount_trx = req["amount_trx"]
        execute("UPDATE tron_deposits SET status='approved' WHERE id=?", (req_id,))
        db_add_balance(req["uid"], int(amount_trx))
        new_bal = db_get_user(req["uid"])["balance"]
        try:
            await context.bot.send_message(
                chat_id=req["uid"],
                text=(
                    f"✅ واریز ترون شما تایید شد.\n"
                    f"💰 مقدار: <b>{amount_trx:g} TRX</b>\n"
                    f"💳 موجودی فعلی: <b>{fmt(new_bal)}</b>"
                ),
                parse_mode="HTML",
            )
        except Exception:
            pass
        await query.edit_message_text(
            query.message.text + "\n\n✅ <b>تایید شد — موجودی افزوده شد</b>",
            parse_mode="HTML",
        )
        return

    if data.startswith("tron_reject_"):
        req_id = int(data.split("_")[2])
        req = db_get_tron_deposit(req_id)
        if not req:
            await query.edit_message_text("درخواست یافت نشد.")
            return
        if req["status"] != "pending":
            await query.answer("این درخواست قبلاً پردازش شده.", show_alert=True)
            return
        execute("UPDATE tron_deposits SET status='rejected' WHERE id=?", (req_id,))
        try:
            await context.bot.send_message(
                chat_id=req["uid"],
                text="❌ درخواست واریز ترون شما رد شد.\nبرای اطلاعات بیشتر با پشتیبانی تماس بگیرید.",
            )
        except Exception:
            pass
        await query.edit_message_text(
            query.message.text + "\n\n❌ <b>رد شد</b>",
            parse_mode="HTML",
        )
        return

    if data.startswith("verif_approve_"):
        target_uid = int(data.split("_")[2])
        db_set_verified(target_uid, 1)
        try:
            await context.bot.send_message(
                chat_id=target_uid,
                text=(
                    "✅ <b>احراز هویت شما تایید شد</b>\n\n"
                    "اکنون می‌توانید شماره کارت را مشاهده کرده و موجودی اضافه کنید."
                ),
                parse_mode="HTML",
            )
        except Exception:
            pass
        caption = query.message.caption or query.message.text or ""
        edit = query.edit_message_caption if query.message.caption else query.edit_message_text
        await edit(caption + "\n\n✅ <b>تایید شد</b>", parse_mode="HTML")
        return

    if data.startswith("verif_reject_"):
        target_uid = int(data.split("_")[2])
        try:
            await context.bot.send_message(
                chat_id=target_uid,
                text="❌ <b>احراز هویت رد شد</b>\n\nلطفاً دوباره با عکس واضح‌تر تلاش کنید.",
                parse_mode="HTML",
            )
        except Exception:
            pass
        caption = query.message.caption or query.message.text or ""
        edit = query.edit_message_caption if query.message.caption else query.edit_message_text
        await edit(caption + "\n\n❌ <b>رد شد</b>", parse_mode="HTML")
        return

    # ── User-accessible callbacks ─────────────────────────────────────────────
    if data == "support_cancel":
        USER_STATE.pop(uid, None)
        await query.edit_message_text("❌ درخواست پشتیبانی لغو شد.")
        return

    if data.startswith("show_order_"):
        order_id = int(data.split("_")[2])
        o = row(
            "SELECT o.*, p.duration FROM orders o "
            "LEFT JOIN plans p ON o.plan_id = p.id "
            "WHERE o.id=? AND o.user_id=?",
            (order_id, uid),
        )
        if not o:
            await query.answer("سفارش پیدا نشد.", show_alert=True)
            return
        cfg = row("SELECT config_text, sub_link, qr_file_id FROM configs WHERE order_id=? LIMIT 1", (order_id,))
        config_text = cfg["config_text"] if cfg else None
        sub_link = cfg["sub_link"] if cfg else None
        qr_file_id = cfg["qr_file_id"] if cfg else None
        import datetime as _dt
        try:
            purchase_dt = _dt.datetime.strptime(o["created_at"][:10], "%Y-%m-%d")
        except Exception:
            purchase_dt = None
        duration = o.get("duration") or "1_month"
        if duration == "3_months":
            delta = _dt.timedelta(days=90)
        elif duration == "lifetime":
            delta = None
        else:
            delta = _dt.timedelta(days=30)
        if delta and purchase_dt:
            expire_str = (purchase_dt + delta).strftime("%Y-%m-%d")
        elif delta is None:
            expire_str = "♾️ مادام‌العمر"
        else:
            expire_str = "—"
        sname = o["service_name"] or "سرویس من"
        status_map = {"pending": "⏳ در انتظار", "approved": "✅ تایید شده", "rejected": "❌ رد شده"}
        status_label = status_map.get(o["status"], o["status"])
        text_parts = [
            f"📦 <b>جزئیات سرویس</b>\n",
            f"📝 <b>نام سرویس:</b> {sname}",
            f"📦 <b>پلن:</b> {o['plan_name']}",
            f"📊 <b>وضعیت:</b> {status_label}",
            f"📅 <b>تاریخ خرید:</b> {o['created_at'][:10]}",
            f"⏳ <b>تاریخ انقضا:</b> {expire_str}",
            f"📊 <b>ترافیک باقی‌مانده:</b> در دسترس نیست",
        ]
        detail_buttons = []
        if qr_file_id:
            detail_buttons.append([InlineKeyboardButton("📷 نمایش QR Code", callback_data=f"order_qr_{order_id}")])
        if sub_link:
            detail_buttons.append([InlineKeyboardButton("🔗 نمایش لینک اشتراک", callback_data=f"order_sublink_{order_id}")])
        if config_text:
            detail_buttons.append([InlineKeyboardButton("📋 نمایش کانفیگ", callback_data=f"order_config_{order_id}")])
        detail_buttons.append([InlineKeyboardButton("♻️ تمدید سرویس", callback_data="show_plans")])
        detail_buttons.append([InlineKeyboardButton("🔙 بازگشت", callback_data="back_my_services")])
        await query.edit_message_text(
            "\n".join(text_parts),
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(detail_buttons),
        )
        return

    if data.startswith("order_qr_"):
        order_id = int(data.split("_")[2])
        o = row("SELECT user_id FROM orders WHERE id=?", (order_id,))
        if not o or o["user_id"] != uid:
            await query.answer("دسترسی مجاز نیست.", show_alert=True)
            return
        cfg = row("SELECT qr_file_id FROM configs WHERE order_id=? LIMIT 1", (order_id,))
        if cfg and cfg["qr_file_id"]:
            await query.answer()
            await context.bot.send_photo(chat_id=uid, photo=cfg["qr_file_id"], caption="📷 QR Code")
        else:
            await query.answer("QR Code برای این سرویس ذخیره نشده.", show_alert=True)
        return

    if data.startswith("order_sublink_"):
        order_id = int(data.split("_")[2])
        o = row("SELECT user_id FROM orders WHERE id=?", (order_id,))
        if not o or o["user_id"] != uid:
            await query.answer("دسترسی مجاز نیست.", show_alert=True)
            return
        cfg = row("SELECT sub_link FROM configs WHERE order_id=? LIMIT 1", (order_id,))
        if cfg and cfg["sub_link"]:
            await query.answer()
            await context.bot.send_message(
                chat_id=uid,
                text=f"🔗 <b>Subscription Link:</b>\n<code>{cfg['sub_link']}</code>",
                parse_mode="HTML",
            )
        else:
            await query.answer("لینک سابسکریپشن برای این سرویس ذخیره نشده.", show_alert=True)
        return

    if data.startswith("order_config_"):
        order_id = int(data.split("_")[2])
        o = row("SELECT user_id FROM orders WHERE id=?", (order_id,))
        if not o or o["user_id"] != uid:
            await query.answer("دسترسی مجاز نیست.", show_alert=True)
            return
        cfg = row("SELECT config_text FROM configs WHERE order_id=? LIMIT 1", (order_id,))
        if cfg and cfg["config_text"]:
            await query.answer()
            await context.bot.send_message(
                chat_id=uid,
                text=f"📋 <b>Configuration:</b>\n<code>{cfg['config_text']}</code>",
                parse_mode="HTML",
            )
        else:
            await query.answer("کانفیگی برای این سرویس ذخیره نشده.", show_alert=True)
        return

    if data == "back_my_services":
        order_list = rows(
            "SELECT id, plan_name, status, created_at, service_name FROM orders "
            "WHERE user_id=? ORDER BY created_at DESC LIMIT 10",
            (uid,),
        )
        if not order_list:
            await query.edit_message_text("📦 هنوز سرویسی خریداری نکرده‌ای.")
            return
        em = {"pending": "⏳", "approved": "✅", "rejected": "❌"}
        lines = ["📦 <b>سرویس‌های من</b>\n"]
        buttons = []
        for o in order_list:
            sname = o["service_name"] or "سرویس من"
            status_icon = em.get(o["status"], "❓")
            lines.append(f"{status_icon} <b>{sname}</b> — {o['plan_name']} | {o['created_at'][:10]}")
            buttons.append([InlineKeyboardButton(
                f"{status_icon} {sname} — {o['plan_name']}",
                callback_data=f"show_order_{o['id']}"
            )])
        await query.edit_message_text(
            "\n".join(lines),
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(buttons),
        )
        return

    # ══════════════════════════════════════════════════════
    #  ADMIN PANEL ACTIONS
    # ══════════════════════════════════════════════════════
    if uid != ADMIN_ID:
        return

    if data == "admin_toggle_bot":
        current = setting("bot_status") or "on"
        new_status = "off" if current == "on" else "on"
        set_setting("bot_status", new_status)
        label = "🔴 خاموش شد" if new_status == "off" else "🟢 روشن شد"
        await query.answer(f"ربات {label}", show_alert=True)
        await query.edit_message_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())

    elif data.startswith("support_reply_"):
        if uid != ADMIN_ID:
            return
        customer_id = int(data.split("_")[2])
        customer = db_get_user(customer_id)
        USER_STATE[uid] = {
            "state": "WAITING_SUPPORT_REPLY",
            "customer_id": customer_id,
            "customer_name": customer["full_name"] if customer else str(customer_id),
        }
        await query.edit_message_text(
            f"✍️ پاسخ برای <b>{'@' + customer['username'] if customer and customer.get('username') else str(customer_id)}</b> را بنویسید:",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("🔙 بازگشت به پنل", callback_data="admin_back")]]
            ),
        )

    elif data == "admin_back":
        USER_STATE.pop(uid, None)
        await query.edit_message_text("⚙️ پنل مدیریت", reply_markup=get_admin_keyboard())

    elif data == "admin_db_backup":
        await query.answer()
        db_path = os.path.join(os.path.dirname(__file__), "data", "bot.db")
        if not os.path.exists(db_path):
            await context.bot.send_message(
                chat_id=uid,
                text="❌ فایل دیتابیس پیدا نشد.",
            )
        else:
            from datetime import datetime as _dt
            timestamp = _dt.now().strftime("%Y%m%d_%H%M%S")
            await context.bot.send_document(
                chat_id=uid,
                document=open(db_path, "rb"),
                filename=f"bot_backup_{timestamp}.db",
                caption=f"📦 <b>بکاپ دیتابیس</b>\n🕐 {_dt.now().strftime('%Y-%m-%d %H:%M:%S')}",
                parse_mode="HTML",
            )

    elif data == "admin_broadcast":
        USER_STATE[uid] = {"state": "WAITING_BROADCAST_MSG"}
        total = len(db_get_all_users())
        await query.edit_message_text(
            f"📢 <b>ارسال پیام همگانی</b>\n\n"
            f"👥 تعداد کاربران: <b>{total}</b>\n\n"
            f"پیام خود را بنویسید و ارسال کنید:",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_create_discount":
        USER_STATE[uid] = {"state": "WAITING_DISCOUNT_CODE"}
        await query.edit_message_text(
            "🏷 <b>ایجاد کد تخفیف</b>\n\nنام کد تخفیف را وارد کنید (مثال: GHOST20):",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_delete_discount":
        codes = db_get_discounts()
        if not codes:
            await query.edit_message_text("📋 هیچ کد تخفیفی موجود نیست.", reply_markup=back_to_panel)
            return
        buttons = [
            [InlineKeyboardButton(
                f"{dc['code']} ({dc['percentage']}%) — استفاده: {dc['used_count']}/{dc['max_uses']}",
                callback_data=f"del_discount_{dc['id']}"
            )]
            for dc in codes
        ]
        buttons.append([InlineKeyboardButton("🔙 بازگشت به پنل", callback_data="admin_back")])
        await query.edit_message_text(
            "🗑 <b>کد تخفیف موردنظر برای حذف را انتخاب کنید:</b>",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(buttons),
        )

    elif data.startswith("del_discount_"):
        code_id = int(data.split("_")[2])
        dc = row("SELECT * FROM discount_codes WHERE id=?", (code_id,))
        if dc:
            db_delete_discount(code_id)
            await query.edit_message_text(
                f"🗑 کد تخفیف <code>{dc['code']}</code> حذف شد.",
                parse_mode="HTML",
                reply_markup=back_to_panel,
            )
        else:
            await query.edit_message_text("❌ کد تخفیف پیدا نشد.", reply_markup=back_to_panel)

    elif data == "admin_trial_menu":
        avail = row("SELECT COUNT(*) as c FROM trial_accounts WHERE status='available'")
        used  = row("SELECT COUNT(*) as c FROM trial_accounts WHERE status='used'")
        await query.edit_message_text(
            f"🧪 <b>اکانت‌های تست</b>\n\n"
            f"✅ موجود: <b>{avail['c'] if avail else 0}</b>\n"
            f"📤 تحویل داده‌شده: <b>{used['c'] if used else 0}</b>",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup([
                [InlineKeyboardButton("➕ افزودن اکانت تست", callback_data="admin_trial_add")],
                [InlineKeyboardButton("📋 لیست اکانت‌های تست", callback_data="admin_trial_list")],
                [InlineKeyboardButton("🗑 حذف اکانت تست", callback_data="admin_trial_delete")],
                [InlineKeyboardButton("🔙 بازگشت به پنل", callback_data="admin_back")],
            ]),
        )

    elif data == "admin_trial_add":
        USER_STATE[uid] = {"state": "WAITING_TRIAL_LINK"}
        await query.edit_message_text(
            "➕ <b>افزودن اکانت تست</b>\n\n"
            "🔗 لینک اشتراک را وارد کنید:\n"
            "(اگر ندارید بنویسید <b>skip</b>)",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("🔙 بازگشت", callback_data="admin_trial_menu")]]
            ),
        )

    elif data == "admin_trial_list":
        trial_list = db_list_trials()
        if not trial_list:
            await query.edit_message_text(
                "📋 هیچ اکانت تستی ثبت نشده.",
                reply_markup=InlineKeyboardMarkup(
                    [[InlineKeyboardButton("🔙 بازگشت", callback_data="admin_trial_menu")]]
                ),
            )
            return
        lines = ["📋 <b>لیست اکانت‌های تست</b>\n"]
        for t in trial_list:
            st_icon = "✅" if t["status"] == "available" else "📤"
            assigned = f"→ کاربر <code>{t['assigned_to']}</code>" if t.get("assigned_to") else "موجود"
            lines.append(
                f"{st_icon} <b>#{t['id']}</b> | {assigned}\n"
                f"   🔗 {t['sub_link'] or '—'} | QR: {'✅' if t.get('qr_file_id') else '❌'}\n"
                f"   📅 {(t['added_at'] or '')[:10]}"
            )
        await query.edit_message_text(
            "\n\n".join(lines),
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("🔙 بازگشت", callback_data="admin_trial_menu")]]
            ),
        )

    elif data == "admin_trial_delete":
        trial_list = db_list_trials()
        if not trial_list:
            await query.edit_message_text(
                "🗑 هیچ اکانت تستی برای حذف وجود ندارد.",
                reply_markup=InlineKeyboardMarkup(
                    [[InlineKeyboardButton("🔙 بازگشت", callback_data="admin_trial_menu")]]
                ),
            )
            return
        buttons = []
        for t in trial_list:
            st_label = "✅" if t["status"] == "available" else "📤"
            link_short = (t["sub_link"] or "")[:25] or "بدون لینک"
            buttons.append([
                InlineKeyboardButton(
                    f"{st_label} #{t['id']} — {link_short}",
                    callback_data=f"admin_trial_del_{t['id']}",
                )
            ])
        buttons.append([InlineKeyboardButton("🔙 بازگشت", callback_data="admin_trial_menu")])
        await query.edit_message_text(
            "🗑 <b>حذف اکانت تست</b>\n\nکدام اکانت را حذف کنیم؟",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(buttons),
        )

    elif data.startswith("admin_trial_del_"):
        trial_id = int(data.split("_")[3])
        db_delete_trial(trial_id)
        await query.edit_message_text(
            f"✅ اکانت تست <b>#{trial_id}</b> حذف شد.",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("🔙 بازگشت", callback_data="admin_trial_menu")]]
            ),
        )

    elif data == "admin_texts":
        await query.edit_message_text(
            "📝 <b>مدیریت متون ربات</b>\n\nکدام متن را می‌خواهید ویرایش کنید؟",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup([
                [InlineKeyboardButton("👋 ویرایش متن خوش‌آمدگویی", callback_data="admin_edit_welcome")],
                [InlineKeyboardButton("🔧 ویرایش متن تعمیرات", callback_data="admin_edit_maintenance")],
                [InlineKeyboardButton("📋 ویرایش متن قوانین", callback_data="admin_edit_rules")],
                [InlineKeyboardButton("🔙 بازگشت به پنل", callback_data="admin_back")],
            ]),
        )

    elif data == "admin_edit_welcome":
        current = get_text("welcome_text", "👻 به Ghost VPN خوش اومدی، {name}!\n\nاز منوی زیر انتخاب کنید:")
        USER_STATE[uid] = {"state": "WAITING_EDIT_WELCOME"}
        await query.edit_message_text(
            f"👋 <b>ویرایش متن خوش‌آمدگویی</b>\n\n"
            f"متن فعلی:\n<code>{current}</code>\n\n"
            f"💡 برای نمایش نام کاربر از <code>{{name}}</code> استفاده کنید.\n\n"
            f"متن جدید را بنویسید:",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_edit_maintenance":
        current = get_bot_off_text()
        USER_STATE[uid] = {"state": "WAITING_EDIT_MAINTENANCE"}
        await query.edit_message_text(
            f"🔧 <b>ویرایش متن تعمیرات</b>\n\n"
            f"متن فعلی:\n<code>{current}</code>\n\n"
            f"متن جدید را بنویسید:",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_edit_rules":
        current = get_text("rules_text", "📋 قوانین استفاده از Ghost VPN")
        USER_STATE[uid] = {"state": "WAITING_EDIT_RULES"}
        await query.edit_message_text(
            f"📋 <b>ویرایش متن قوانین</b>\n\n"
            f"متن فعلی:\n<code>{current}</code>\n\n"
            f"متن جدید را بنویسید:",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_list_discounts":
        codes = db_get_discounts()
        if not codes:
            text = "📋 هیچ کد تخفیفی موجود نیست."
        else:
            lines = ["📋 <b>لیست کدهای تخفیف:</b>\n"]
            for dc in codes:
                remaining = dc["max_uses"] - dc["used_count"]
                exp = dc["expires_at"] or "ندارد"
                lines.append(
                    f"🏷 <code>{dc['code']}</code> — <b>{dc['percentage']}%</b>\n"
                    f"   ✅ استفاده: {dc['used_count']}/{dc['max_uses']} | باقیمانده: {remaining}\n"
                    f"   📅 انقضا: {exp}"
                )
            text = "\n\n".join(lines)
        await query.edit_message_text(text, parse_mode="HTML", reply_markup=back_to_panel)

    elif data == "admin_ban":
        USER_STATE[uid] = {"state": "WAITING_BAN_ID"}
        await query.edit_message_text(
            "🚫 <b>مسدود کردن کاربر</b>\n\nآیدی عددی تلگرام کاربر را وارد کنید:",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_unban":
        USER_STATE[uid] = {"state": "WAITING_UNBAN_ID"}
        await query.edit_message_text(
            "✅ <b>رفع مسدودیت</b>\n\nآیدی عددی تلگرام کاربر را وارد کنید:",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_banned_list":
        banned = db_get_banned_users()
        if not banned:
            text = "📋 هیچ کاربر مسدودی وجود ندارد."
        else:
            lines = ["📋 <b>لیست کاربران مسدود:</b>\n"]
            for i, u in enumerate(banned, 1):
                uname = f"@{u['username']}" if u.get("username") else "—"
                lines.append(
                    f"{i}. <b>{u['full_name']}</b> ({uname})\n"
                    f"   🆔 <code>{u['user_id']}</code>"
                )
            text = "\n".join(lines)
        await query.edit_message_text(text, parse_mode="HTML", reply_markup=back_to_panel)

    elif data == "admin_search_user":
        USER_STATE[uid] = {"state": "WAITING_SEARCH_USER"}
        await query.edit_message_text(
            "🔍 <b>جستجوی کاربر</b>\n\n"
            "آیدی عددی، یوزرنیم (با یا بدون @) یا نام کاربر را وارد کنید:",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("🔙 بازگشت به لیست", callback_data="admin_users")]]
            ),
        )

    elif data.startswith("usermgr_ban_"):
        target_uid = int(data.split("_")[2])
        if target_uid == ADMIN_ID:
            await query.answer("نمی‌توان ادمین را مسدود کرد.", show_alert=True)
            return
        db_ban_user(target_uid)
        found = db_get_user(target_uid)
        cnt_r = row("SELECT COUNT(*) as cnt FROM orders WHERE user_id=?", (target_uid,))
        cnt = cnt_r["cnt"] if cnt_r else 0
        await query.edit_message_text(
            f"🚫 کاربر مسدود شد.\n\n" + user_info_text(found, cnt),
            parse_mode="HTML",
            reply_markup=user_mgr_kb(target_uid),
        )

    elif data.startswith("usermgr_unban_"):
        target_uid = int(data.split("_")[2])
        db_unban_user(target_uid)
        found = db_get_user(target_uid)
        cnt_r = row("SELECT COUNT(*) as cnt FROM orders WHERE user_id=?", (target_uid,))
        cnt = cnt_r["cnt"] if cnt_r else 0
        await query.edit_message_text(
            f"✅ مسدودیت برداشته شد.\n\n" + user_info_text(found, cnt),
            parse_mode="HTML",
            reply_markup=user_mgr_kb(target_uid),
        )

    elif data.startswith("usermgr_bal_"):
        target_uid = int(data.split("_")[2])
        found = db_get_user(target_uid)
        cur_bal = found.get("balance", 0) if found else 0
        USER_STATE[uid] = {"state": "WAITING_USERMGR_BAL", "target_uid": target_uid}
        await query.edit_message_text(
            f"💰 <b>تغییر موجودی</b>\n\n"
            f"کاربر: <b>{found.get('full_name') or target_uid}</b>\n"
            f"موجودی فعلی: <b>{fmt(cur_bal)}</b>\n\n"
            "موجودی جدید را وارد کنید (عدد — تومان):",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("❌ انصراف", callback_data=f"usermgr_cancel_{target_uid}")]]
            ),
        )

    elif data.startswith("usermgr_msg_"):
        target_uid = int(data.split("_")[2])
        found = db_get_user(target_uid)
        USER_STATE[uid] = {"state": "WAITING_USERMGR_MSG", "target_uid": target_uid}
        await query.edit_message_text(
            f"📨 <b>ارسال پیام</b>\n\n"
            f"کاربر: <b>{found.get('full_name') or target_uid}</b>\n\n"
            "متن پیام را بنویسید:",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("❌ انصراف", callback_data=f"usermgr_cancel_{target_uid}")]]
            ),
        )

    elif data.startswith("usermgr_cancel_"):
        target_uid = int(data.split("_")[2])
        USER_STATE.pop(uid, None)
        found = db_get_user(target_uid)
        cnt_r = row("SELECT COUNT(*) as cnt FROM orders WHERE user_id=?", (target_uid,))
        cnt = cnt_r["cnt"] if cnt_r else 0
        await query.edit_message_text(
            user_info_text(found, cnt),
            parse_mode="HTML",
            reply_markup=user_mgr_kb(target_uid),
        )

    elif data == "admin_set_card":
        USER_STATE[uid] = {"state": "WAITING_CARD_NUMBER"}
        await query.edit_message_text(
            f"⚙️ <b>تنظیم شماره کارت</b>\n\nکارت فعلی:\n{card_text()}\n\nشماره کارت جدید را وارد کنید:",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data.startswith("admin_plan_dur_"):
        duration = data[len("admin_plan_dur_"):]
        if duration not in DURATION_LABELS:
            await query.edit_message_text("❌ مدت نامعتبر است.", reply_markup=back_to_panel)
            return
        ds = USER_STATE.get(uid, {})
        if ds.get("state") != "WAITING_PLAN_DURATION_CB":
            await query.edit_message_text("⚠️ جلسه منقضی شده. دوباره پلن را اضافه کنید.", reply_markup=back_to_panel)
            return
        plan_name = ds.get("plan_name", "نامشخص")
        plan_price = ds.get("plan_price", 0)
        USER_STATE.pop(uid, None)
        db_add_plan(plan_name, plan_price, duration)
        await query.edit_message_text(
            f"✅ پلن ثبت شد:\n<b>{plan_name}</b> — {fmt(plan_price)}\n🕐 مدت: {DURATION_LABELS[duration]}",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_add_plan":
        USER_STATE[uid] = {"state": "WAITING_PLAN_NAME"}
        await query.edit_message_text(
            "➕ <b>افزودن پلن جدید</b>\n\nنام پلن را بنویسید و ارسال کنید:",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_view_plans":
        plans = db_get_plans()
        if not plans:
            text = "📝 هیچ پلنی ثبت نشده."
        else:
            lines = ["📝 <b>لیست پلن‌ها</b>\n"]
            for d in DURATION_ORDER:
                group = [p for p in plans if (p.get("duration") or "1_month") == d]
                if group:
                    lines.append(f"\n{DURATION_LABELS[d]}")
                    for p in group:
                        lines.append(f"  • <b>#{p['id']}</b> {p['name']} — {fmt(p['price'])}")
            text = "\n".join(lines)
        await query.edit_message_text(text, parse_mode="HTML", reply_markup=back_to_panel)

    elif data == "admin_delete_plan":
        plans = db_get_plans()
        if not plans:
            await query.edit_message_text("هیچ پلنی برای حذف وجود ندارد.", reply_markup=back_to_panel)
            return
        buttons = [
            [InlineKeyboardButton(f"🗑 {p['name']} — {fmt(p['price'])}", callback_data=f"del_plan_{p['id']}")]
            for p in plans
        ]
        buttons.append([InlineKeyboardButton("🔙 بازگشت", callback_data="admin_back")])
        await query.edit_message_text(
            "🗑 <b>حذف پلن</b>\n\nانتخاب کنید:",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(buttons),
        )

    elif data.startswith("del_plan_"):
        db_delete_plan(int(data.split("_")[2]))
        await query.edit_message_text("✅ پلن حذف شد.", reply_markup=back_to_panel)

    elif data == "admin_add_config":
        plans = db_get_plans()
        if not plans:
            await query.edit_message_text("⚠️ ابتدا یک پلن ایجاد کنید.", reply_markup=back_to_panel)
            return
        buttons = [
            [InlineKeyboardButton(f"📦 {p['name']}", callback_data=f"pick_config_plan_{p['id']}")]
            for p in plans
        ]
        buttons.append([InlineKeyboardButton("🔙 بازگشت", callback_data="admin_back")])
        await query.edit_message_text(
            "➕ <b>افزودن کانفیگ</b>\n\nپلن مربوطه را انتخاب کنید:",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup(buttons),
        )

    elif data.startswith("pick_config_plan_"):
        plan_id = int(data.split("_")[3])
        plan = row("SELECT * FROM plans WHERE id=?", (plan_id,))
        if not plan:
            await query.edit_message_text("پلن یافت نشد.", reply_markup=back_to_panel)
            return
        USER_STATE[uid] = {"state": "WAITING_ADD_CONFIG_TEXT", "plan_name": plan["name"]}
        avail = len(
            rows("SELECT id FROM configs WHERE plan_name=? AND status='available'", (plan["name"],))
        )
        await query.edit_message_text(
            f"📦 پلن: <b>{plan['name']}</b>\n"
            f"موجودی فعلی: <b>{avail}</b> کانفیگ\n\n"
            "لینک سابسکریپشن یا متن کانفیگ جدید را ارسال کنید:",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_view_configs":
        config_rows = rows(
            "SELECT plan_name, status, COUNT(*) as cnt FROM configs GROUP BY plan_name, status ORDER BY plan_name, status"
        )
        if not config_rows:
            await query.edit_message_text("📊 هیچ کانفیگی ثبت نشده.", reply_markup=back_to_panel)
            return
        lines = ["📊 <b>وضعیت کانفیگ‌ها</b>\n"]
        current_plan = None
        for r in config_rows:
            if r["plan_name"] != current_plan:
                current_plan = r["plan_name"]
                lines.append(f"\n📦 <b>{current_plan}</b>")
            status_label = "✅ موجود" if r["status"] == "available" else "🔴 فروخته شده"
            lines.append(f"  {status_label}: {r['cnt']}")
        await query.edit_message_text("\n".join(lines), parse_mode="HTML", reply_markup=back_to_panel)

    elif data == "admin_charge_help":
        await query.edit_message_text(
            "💳 <b>افزایش موجودی دستی</b>\n\n"
            "<code>/charge USER_ID AMOUNT</code>\n\n"
            "مثال:\n<code>/charge 123456789 50000</code>",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_msg_customer":
        USER_STATE[uid] = {"state": "WAITING_MSG_CUSTOMER_ID"}
        await query.edit_message_text(
            "📨 <b>پیام به مشتری</b>\n\nآیدی عددی کاربر را وارد کنید:",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_charges":
        pending = rows(
            """SELECT cr.*, u.full_name, u.username
               FROM charge_requests cr JOIN users u ON cr.user_id=u.user_id
               WHERE cr.status='pending' ORDER BY cr.created_at""",
        )
        await query.edit_message_text(
            f"💳 <b>درخواست‌های شارژ در انتظار: {len(pending)}</b>",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )
        for r in pending:
            if r["receipt_file"]:
                await context.bot.send_photo(
                    chat_id=uid,
                    photo=r["receipt_file"],
                    caption=(
                        f"💳 <b>درخواست شارژ #{r['id']}</b>\n\n"
                        f"👤 {r['full_name']} (@{r['username'] or 'N/A'}) [ID: {r['user_id']}]\n"
                        f"💰 مبلغ: <b>{fmt(r['amount'])}</b>\n"
                        f"📅 {r['created_at'][:16]}"
                    ),
                    parse_mode="HTML",
                    reply_markup=charge_action_kb(r["id"]),
                )
            else:
                await context.bot.send_message(
                    chat_id=uid,
                    text=(
                        f"💳 <b>درخواست شارژ #{r['id']}</b>\n\n"
                        f"👤 {r['full_name']} [ID: {r['user_id']}]\n"
                        f"💰 مبلغ: <b>{fmt(r['amount'])}</b>"
                    ),
                    parse_mode="HTML",
                    reply_markup=charge_action_kb(r["id"]),
                )

    elif data == "admin_pending":
        pending = rows(
            """SELECT o.*, u.full_name, u.username
               FROM orders o JOIN users u ON o.user_id=u.user_id
               WHERE o.status='pending' ORDER BY o.created_at""",
        )
        await query.edit_message_text(
            f"📦 <b>سفارشات در انتظار: {len(pending)}</b>",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )
        for o in pending:
            await context.bot.send_message(
                chat_id=uid,
                text=(
                    f"📋 <b>سفارش #{o['id']}</b>\n\n"
                    f"👤 {o['full_name']} (@{o['username'] or 'N/A'}) [ID: {o['user_id']}]\n"
                    f"📦 {o['plan_name']} — {fmt(o['plan_price'])}\n"
                    f"💳 روش: {o['pay_method']}\n"
                    f"📅 {o['created_at'][:16]}"
                ),
                parse_mode="HTML",
                reply_markup=order_action_kb(o["id"]),
            )

    elif data == "admin_all_orders":
        all_ord = rows(
            """SELECT o.*, u.full_name FROM orders o JOIN users u ON o.user_id=u.user_id
               ORDER BY o.created_at DESC LIMIT 30"""
        )
        if not all_ord:
            await query.edit_message_text("هنوز سفارشی ثبت نشده.", reply_markup=back_to_panel)
            return
        em = {"pending": "⏳", "approved": "✅", "rejected": "❌"}
        lines = [f"📊 <b>همه سفارش‌ها ({len(all_ord)})</b>\n"]
        for o in all_ord:
            lines.append(
                f"{em.get(o['status'], '❓')} <b>#{o['id']}</b> {o['plan_name']} "
                f"— {o['full_name']} | {o['created_at'][:10]}"
            )
        await query.edit_message_text("\n".join(lines), parse_mode="HTML", reply_markup=back_to_panel)

    elif data == "admin_verifs":
        pending = rows(
            """SELECT u.user_id, u.full_name, u.username
               FROM users u
               WHERE u.verified=0
               ORDER BY u.joined_at DESC LIMIT 30"""
        )
        await query.edit_message_text(
            f"🪪 <b>کاربران احراز‌نشده: {len(pending)}</b>",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )
        for u in pending:
            await context.bot.send_message(
                chat_id=uid,
                text=(
                    f"🪪 <b>کاربر احراز‌نشده</b>\n\n"
                    f"👤 {u['full_name']} (@{u['username'] or 'N/A'})\n"
                    f"🆔 آیدی: <code>{u['user_id']}</code>"
                ),
                parse_mode="HTML",
                reply_markup=verif_action_kb(u["user_id"]),
            )

    elif data == "admin_users":
        user_list = rows(
            "SELECT user_id, username, full_name, balance, verified, joined_at FROM users ORDER BY joined_at DESC LIMIT 20"
        )
        if not user_list:
            await query.edit_message_text(
                "هنوز کاربری ثبت نشده.",
                reply_markup=InlineKeyboardMarkup([
                    [InlineKeyboardButton("🔍 جستجوی کاربر", callback_data="admin_search_user")],
                    [InlineKeyboardButton("🔙 بازگشت به پنل", callback_data="admin_back")],
                ]),
            )
            return
        lines = [f"📋 <b>لیست کاربران ({len(user_list)})</b>\n"]
        for u in user_list:
            badge = "✅" if u["verified"] else "❌"
            lines.append(
                f"• <code>{u['user_id']}</code> {u['full_name']} "
                f"(@{u['username'] or 'N/A'}) | 💰 {fmt(u['balance'])} | {badge}"
            )
        await query.edit_message_text(
            "\n".join(lines),
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup([
                [InlineKeyboardButton("🔍 جستجوی کاربر", callback_data="admin_search_user")],
                [InlineKeyboardButton("🔙 بازگشت به پنل", callback_data="admin_back")],
            ]),
        )

    elif data == "admin_stats":
        avail_configs = db_count("configs", "status", "available")
        sold_configs = db_count("configs", "status", "sold")
        await query.edit_message_text(
            f"📈 <b>آمار</b>\n\n"
            f"👥 کاربران: <b>{db_count('users')}</b>\n"
            f"✅ احراز شده: <b>{db_count('users', 'verified', 1)}</b>\n"
            f"📦 کل سفارش‌ها: <b>{db_count('orders')}</b>\n"
            f"⏳ سفارش در انتظار: <b>{db_count('orders', 'status', 'pending')}</b>\n"
            f"✅ سفارش تایید شده: <b>{db_count('orders', 'status', 'approved')}</b>\n"
            f"💳 شارژ در انتظار: <b>{db_count('charge_requests', 'status', 'pending')}</b>\n"
            f"🔗 کانفیگ موجود: <b>{avail_configs}</b>\n"
            f"🔴 کانفیگ فروخته: <b>{sold_configs}</b>",
            parse_mode="HTML",
            reply_markup=back_to_panel,
        )

    elif data == "admin_sales_report":
        await query.edit_message_text(
            "📊 <b>گزارش فروش</b>\n\nبازه زمانی را انتخاب کنید:",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup([
                [InlineKeyboardButton("📅 فروش امروز", callback_data="admin_sales_today")],
                [InlineKeyboardButton("📆 فروش این هفته", callback_data="admin_sales_week")],
                [InlineKeyboardButton("🗓 فروش این ماه", callback_data="admin_sales_month")],
                [InlineKeyboardButton("🔙 بازگشت به پنل", callback_data="admin_back")],
            ]),
        )

    elif data in ("admin_sales_today", "admin_sales_week", "admin_sales_month"):
        import sqlite3 as _sqlite3
        period_map = {
            "admin_sales_today": ("📅 فروش امروز", "DATE(created_at) = DATE('now')"),
            "admin_sales_week":  ("📆 فروش این هفته", "created_at >= DATE('now', '-6 days')"),
            "admin_sales_month": ("🗓 فروش این ماه", "strftime('%Y-%m', created_at) = strftime('%Y-%m', 'now')"),
        }
        label, where_clause = period_map[data]
        with _sqlite3.connect(DB_PATH) as _con:
            _con.row_factory = _sqlite3.Row
            stats_row = _con.execute(
                f"SELECT COUNT(*) as total_orders, "
                f"COALESCE(SUM(plan_price - COALESCE(discount_amount, 0)), 0) as total_revenue, "
                f"COUNT(DISTINCT user_id) as unique_customers "
                f"FROM orders WHERE status='approved' AND {where_clause}"
            ).fetchone()
        total_orders = stats_row["total_orders"] if stats_row else 0
        total_revenue = int(stats_row["total_revenue"]) if stats_row else 0
        unique_customers = stats_row["unique_customers"] if stats_row else 0
        await query.edit_message_text(
            f"📊 <b>گزارش فروش — {label}</b>\n\n"
            f"💰 <b>درآمد کل:</b> {fmt(total_revenue)}\n"
            f"📦 <b>تعداد سفارش:</b> {total_orders}\n"
            f"👥 <b>مشتریان یکتا:</b> {unique_customers}",
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup([
                [InlineKeyboardButton("📅 امروز", callback_data="admin_sales_today"),
                 InlineKeyboardButton("📆 این هفته", callback_data="admin_sales_week"),
                 InlineKeyboardButton("🗓 این ماه", callback_data="admin_sales_month")],
                [InlineKeyboardButton("🔙 بازگشت به پنل", callback_data="admin_back")],
            ]),
        )


# ── Global error handler ──────────────────────────────────────────────────────
async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE):
    import traceback
    logger.error("Unhandled exception: %s", context.error)
    traceback.print_exception(type(context.error), context.error, context.error.__traceback__)
    # Always notify the user so they never see silence
    try:
        if update and hasattr(update, "effective_message") and update.effective_message:
            await update.effective_message.reply_text(
                "⚠️ خطای موقتی رخ داد. لطفاً دوباره تلاش کنید یا /start را بزنید."
            )
        elif update and hasattr(update, "callback_query") and update.callback_query:
            try:
                await update.callback_query.answer("⚠️ خطا رخ داد. دوباره تلاش کنید.", show_alert=True)
            except Exception:
                pass
    except Exception:
        pass


# ── Entry point ───────────────────────────────────────────────────────────────
def main():
    if not TOKEN:
        raise RuntimeError("BOT_TOKEN environment variable is not set.")
    if not ADMIN_ID:
        raise RuntimeError("ADMIN_ID environment variable is not set.")
    init_db()
    app = Application.builder().token(TOKEN).build()
    app.add_handler(CommandHandler("start", start))
    app.add_handler(CommandHandler("lobestrhadi", admin_cmd))
    app.add_handler(CommandHandler("charge", charge_cmd))
    app.add_handler(CallbackQueryHandler(button_handler))
    app.add_handler(
        MessageHandler(
            (filters.TEXT | filters.PHOTO) & ~filters.COMMAND,
            handle_message,
        )
    )
    app.add_error_handler(error_handler)
    print("Bot Running...", flush=True)
    app.run_polling()


if __name__ == "__main__":
    main()
