# ============================================================
# bot tel.py - نسخه نهایی با سیستم برداشت خودکار جم
# ============================================================

import os
import sys
import shutil
import sqlite3
import logging
import atexit
import asyncio
import re
import random

from datetime import datetime

from telegram import (
    Update,
    InlineKeyboardButton,
    InlineKeyboardMarkup,
    KeyboardButton,
    ReplyKeyboardMarkup,
    ReplyKeyboardRemove
)

from telegram.ext import (
    Application,
    CommandHandler,
    CallbackQueryHandler,
    MessageHandler,
    ContextTypes,
    filters
)

from telegram.request import HTTPXRequest


# ============================================================
# CONFIG
# ============================================================

TOKEN = "8932247879:AAEAc3lOvh213eKZWwwQ3idkEj4IjEG3YJ4"  # ← توکن خود را جایگزین کنید

OWNER_ID = 7847917145  # آیدی عددی ادمین اصلی
ADMIN_USERNAME = "@accforoshi"  # یوزرنیم ادمین
SUPPORT_USERNAME = "@accforoshi"  # یوزرنیم پشتیبان

CHANNEL_IDS = [
    -1003599328663,
    -1003543052257
]

CHANNEL_LINKS = [
    "https://t.me/+DADzEc3PT0lhYmQ0",
    "https://t.me/accforroshi"
]

DB_NAME = "bot_data.db"
BACKUP_FOLDER = "backup"
LOCK_FILE = "bot.lock"

INVITE_REWARD = 10000  # پاداش هر دعوت (تومان)
MIN_WITHDRAW = 150000  # حداقل درخواست نقدی
WITHDRAW_FEE = 50000   # کارمزد برداشت نقدی
REAL_PAYOUT = 100000   # مبلغ واقعی پرداختی

MIN_INVITES_FOR_GEM = 15  # حداقل دعوت برای برداشت جم
GEM_PER_INVITE = 100      # هر ۱۵ دعوت = ۱۰۰ جم

USERS_PER_PAGE = 10

PROXY_URL = None  # در صورت نیاز: "socks5://127.0.0.1:10808"


# ============================================================
# LOGGING
# ============================================================

logging.basicConfig(
    format="%(asctime)s - %(levelname)s - %(message)s",
    level=logging.INFO
)


# ============================================================
# DATABASE & BACKUP & LOCK
# ============================================================

def db():
    conn = sqlite3.connect(DB_NAME)
    conn.execute("PRAGMA foreign_keys = ON")
    return conn


def backup_database():
    if not os.path.exists(DB_NAME):
        print("ℹ️ دیتابیس قبلی وجود ندارد؛ بکاپ لازم نیست.")
        return
    if not os.path.exists(BACKUP_FOLDER):
        os.makedirs(BACKUP_FOLDER)
    filename = datetime.now().strftime("backup_%Y-%m-%d_%H-%M-%S.db")
    destination = os.path.join(BACKUP_FOLDER, filename)
    try:
        shutil.copy2(DB_NAME, destination)
        print(f"✅ بکاپ ساخته شد: {destination}")
    except Exception as e:
        print(f"❌ خطا در ساخت بکاپ: {e}")


def process_exists(pid):
    try:
        os.kill(pid, 0)
        return True
    except ProcessLookupError:
        return False
    except PermissionError:
        return True
    except Exception:
        return False


def create_lock():
    if os.path.exists(LOCK_FILE):
        try:
            with open(LOCK_FILE, "r", encoding="utf-8") as f:
                old_pid = int(f.read().strip())
        except Exception:
            old_pid = None
        if old_pid and process_exists(old_pid):
            print("❌ ربات قبلاً اجرا شده است.")
            print(f"PID فعال: {old_pid}")
            sys.exit(1)
        else:
            print("⚠️ قفل قبلی مربوط به اجرای قدیمی بود.")
            try:
                os.remove(LOCK_FILE)
            except Exception:
                pass
    with open(LOCK_FILE, "w", encoding="utf-8") as f:
        f.write(str(os.getpid()))
    print("🔐 قفل اجرای ربات فعال شد.")


def remove_lock():
    if os.path.exists(LOCK_FILE):
        try:
            os.remove(LOCK_FILE)
        except Exception:
            pass


atexit.register(remove_lock)


# ============================================================
# DATABASE MIGRATION
# ============================================================

def column_exists(table, column):
    conn = db()
    cur = conn.cursor()
    cur.execute(f"PRAGMA table_info({table})")
    columns = [row[1] for row in cur.fetchall()]
    conn.close()
    return column in columns


def add_column(table, column, datatype):
    if not column_exists(table, column):
        conn = db()
        cur = conn.cursor()
        cur.execute(f"ALTER TABLE {table} ADD COLUMN {column} {datatype}")
        conn.commit()
        conn.close()


def migrate():
    conn = db()
    cur = conn.cursor()
    
    cur.execute("""
        CREATE TABLE IF NOT EXISTS users(
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            telegram_id INTEGER UNIQUE,
            username TEXT,
            phone_number TEXT,
            balance INTEGER DEFAULT 0,
            invite_count INTEGER DEFAULT 0,
            blocked INTEGER DEFAULT 0,
            created TEXT,
            invited_by INTEGER DEFAULT 0,
            invite_rewarded INTEGER DEFAULT 0,
            payment_method TEXT DEFAULT 'card',
            card_number TEXT,
            game_id TEXT
        )
    """)
    
    cur.execute("""
        CREATE TABLE IF NOT EXISTS transactions(
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            user_id INTEGER,
            amount INTEGER,
            type TEXT,
            description TEXT,
            created TEXT
        )
    """)
    
    cur.execute("""
        CREATE TABLE IF NOT EXISTS withdrawals(
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            user_id INTEGER,
            amount INTEGER,
            actual_amount INTEGER,
            method TEXT,
            card_number TEXT,
            game_id TEXT,
            gem_count INTEGER DEFAULT 0,
            status TEXT DEFAULT 'pending',
            created TEXT
        )
    """)
    
    cur.execute("""
        CREATE TABLE IF NOT EXISTS admins(
            user_id INTEGER UNIQUE,
            created TEXT
        )
    """)
    
    conn.commit()
    conn.close()
    
    add_column("users", "invited_by", "INTEGER DEFAULT 0")
    add_column("users", "invite_rewarded", "INTEGER DEFAULT 0")
    add_column("users", "phone_number", "TEXT")
    add_column("users", "payment_method", "TEXT DEFAULT 'card'")
    add_column("users", "card_number", "TEXT")
    add_column("users", "game_id", "TEXT")
    add_column("withdrawals", "method", "TEXT")
    add_column("withdrawals", "card_number", "TEXT")
    add_column("withdrawals", "game_id", "TEXT")
    add_column("withdrawals", "gem_count", "INTEGER DEFAULT 0")
    add_column("withdrawals", "actual_amount", "INTEGER DEFAULT 0")
    
    conn = db()
    cur = conn.cursor()
    try:
        cur.execute("CREATE UNIQUE INDEX IF NOT EXISTS idx_unique_phone ON users(phone_number)")
        conn.commit()
    except sqlite3.OperationalError as e:
        if "already exists" not in str(e):
            raise
    conn.close()
    
    print("✅ دیتابیس آماده است.")


# ============================================================
# INITIAL START
# ============================================================

create_lock()
backup_database()
migrate()


# ============================================================
# USER FUNCTIONS
# ============================================================

def get_user(user_id):
    conn = db()
    cur = conn.cursor()
    cur.execute("""
        SELECT telegram_id, username, phone_number, balance, invite_count, blocked, 
               invited_by, invite_rewarded, payment_method, card_number, game_id
        FROM users WHERE telegram_id=?
    """, (user_id,))
    row = cur.fetchone()
    conn.close()
    return row


def get_user_by_phone(phone):
    conn = db()
    cur = conn.cursor()
    cur.execute("SELECT telegram_id FROM users WHERE phone_number=?", (phone,))
    row = cur.fetchone()
    conn.close()
    return row[0] if row else None


def find_user(identifier):
    conn = db()
    cur = conn.cursor()
    
    if isinstance(identifier, str):
        identifier = identifier.strip()
        if identifier.startswith('@'):
            identifier = identifier[1:]
    
    if isinstance(identifier, int) or (isinstance(identifier, str) and identifier.isdigit()):
        try:
            uid = int(identifier)
            cur.execute("""
                SELECT telegram_id, username, balance, invite_count, blocked
                FROM users WHERE telegram_id=?
            """, (uid,))
            row = cur.fetchone()
            if row:
                conn.close()
                return row
        except:
            pass
    
    if isinstance(identifier, str) and identifier:
        cur.execute("""
            SELECT telegram_id, username, balance, invite_count, blocked
            FROM users WHERE LOWER(username)=LOWER(?)
        """, (identifier,))
        row = cur.fetchone()
        if row:
            conn.close()
            return row
    
    conn.close()
    return None


def create_user(user_id, username, invited_by=0):
    conn = db()
    cur = conn.cursor()
    cur.execute("SELECT telegram_id FROM users WHERE telegram_id=?", (user_id,))
    exists = cur.fetchone()
    if exists:
        cur.execute("UPDATE users SET username=? WHERE telegram_id=?", (username, user_id))
        conn.commit()
        conn.close()
        return False
    if invited_by == user_id:
        invited_by = 0
    cur.execute("""
        INSERT INTO users (telegram_id, username, balance, invite_count, blocked, created, invited_by, invite_rewarded)
        VALUES(?,?,?,?,?,?,?,?)
    """, (user_id, username, 0, 0, 0, datetime.now().isoformat(), invited_by, 0))
    conn.commit()
    conn.close()
    return True


def update_user_phone(user_id, phone):
    conn = db()
    cur = conn.cursor()
    cur.execute("UPDATE users SET phone_number=? WHERE telegram_id=?", (phone, user_id))
    conn.commit()
    conn.close()


def update_user_payment(user_id, method, card_number=None, game_id=None):
    conn = db()
    cur = conn.cursor()
    cur.execute("""
        UPDATE users 
        SET payment_method=?, card_number=?, game_id=? 
        WHERE telegram_id=?
    """, (method, card_number, game_id, user_id))
    conn.commit()
    conn.close()


def is_blocked(user_id):
    row = get_user(user_id)
    if not row:
        return False
    return bool(row[5])


def is_phone_valid(phone):
    phone = re.sub(r'[\s\-]', '', phone)
    patterns = [
        r'^09\d{9}$',
        r'^989\d{9}$',
        r'^\+989\d{9}$',
        r'^00989\d{9}$'
    ]
    for pattern in patterns:
        if re.match(pattern, phone):
            if phone.startswith('+98'):
                phone = '0' + phone[3:]
            elif phone.startswith('98'):
                phone = '0' + phone[2:]
            elif phone.startswith('0098'):
                phone = '0' + phone[4:]
            return True, phone
    return False, None


def generate_captcha():
    a = random.randint(1, 20)
    b = random.randint(1, 20)
    answer = a + b
    question = f"{a} + {b} = ?"
    return question, answer


def persian_to_english(num_str):
    mapping = {
        '۰': '0', '۱': '1', '۲': '2', '۳': '3', '۴': '4',
        '۵': '5', '۶': '6', '۷': '7', '۸': '8', '۹': '9'
    }
    return ''.join(mapping.get(c, c) for c in num_str)


# ============================================================
# CHANNEL FUNCTIONS
# ============================================================

async def check_bot_channels(app):
    bot = app.bot
    for idx, channel_id in enumerate(CHANNEL_IDS):
        if channel_id == 0:
            continue
        try:
            me = await bot.get_chat_member(channel_id, bot.id)
            if me.status in ["member", "administrator", "creator"]:
                logging.info(f"✅ ربات در کانال {idx} (ID: {channel_id}) عضو است.")
            else:
                logging.warning(f"⚠️ ربات در کانال {idx} (ID: {channel_id}) عضو نیست! وضعیت: {me.status}")
        except Exception as e:
            logging.error(f"❌ خطا در بررسی عضویت ربات در کانال {idx} (ID: {channel_id}): {e}")


async def check_join(user_id, context):
    not_joined = []
    for idx, channel_id in enumerate(CHANNEL_IDS):
        if channel_id == 0:
            continue
        try:
            member = await context.bot.get_chat_member(channel_id, user_id)
            if member.status not in ["member", "administrator", "creator"]:
                not_joined.append(idx)
        except Exception:
            not_joined.append(idx)
    return len(not_joined) == 0, not_joined


def join_keyboard(not_joined_indices=None):
    if not_joined_indices is None:
        not_joined_indices = list(range(len(CHANNEL_IDS)))
    keyboard = []
    for idx in not_joined_indices:
        if idx < len(CHANNEL_LINKS) and CHANNEL_IDS[idx] != 0 and CHANNEL_LINKS[idx]:
            keyboard.append([
                InlineKeyboardButton(
                    f"📢 عضویت در کانال {idx+1}",
                    url=CHANNEL_LINKS[idx]
                )
            ])
    keyboard.append([
        InlineKeyboardButton("✅ بررسی عضویت", callback_data="check_join")
    ])
    return InlineKeyboardMarkup(keyboard)


# ============================================================
# USER MENU
# ============================================================

def user_menu():
    keyboard = [
        [InlineKeyboardButton("💰 موجودی", callback_data="balance"),
         InlineKeyboardButton("👥 دعوت دوستان", callback_data="invite")],
        [InlineKeyboardButton("💳 برداشت", callback_data="withdraw"),
         InlineKeyboardButton("📊 تراکنش‌ها", callback_data="transactions")],
        [InlineKeyboardButton("👤 حساب من", callback_data="profile"),
         InlineKeyboardButton("📞 پشتیبانی", callback_data="support")]
    ]
    return InlineKeyboardMarkup(keyboard)


def back_button():
    return InlineKeyboardMarkup([[InlineKeyboardButton("🔙 بازگشت", callback_data="home")]])


# ============================================================
# USER HANDLERS
# ============================================================

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    if not user:
        return
    if is_blocked(user.id):
        await update.message.reply_text("⛔ حساب شما مسدود شده است.")
        return

    inviter = 0
    if context.args:
        try:
            inviter = int(context.args[0])
        except (ValueError, TypeError):
            inviter = 0
    if inviter == user.id:
        inviter = 0

    create_user(user.id, user.username, inviter)

    joined_all, not_joined = await check_join(user.id, context)
    if not joined_all:
        keyboard = join_keyboard(not_joined)
        await update.message.reply_text(
            """
👋 سلام

برای استفاده از ربات ابتدا باید در **همه کانال‌ها** عضو شوید.

📢 روی لینک‌های زیر کلیک کرده و عضو شوید.
سپس روی «بررسی عضویت» بزنید.

🎁 پاداش دعوت فقط بعد از تأیید عضویت کاربر دعوت‌شده ثبت می‌شود.
""",
            reply_markup=keyboard
        )
        return

    user_data = get_user(user.id)
    if user_data and not user_data[2]:
        contact_button = KeyboardButton("📱 ارسال شماره تلفن", request_contact=True)
        reply_keyboard = ReplyKeyboardMarkup([[contact_button]], resize_keyboard=True, one_time_keyboard=True)
        await update.message.reply_text(
            """
📱 لطفاً شماره تلفن خود را ارسال کنید.

برای این کار روی دکمه‌ی زیر کلیک کنید:
""",
            reply_markup=reply_keyboard
        )
        context.user_data["phone_wait"] = True
        return

    await update.message.reply_text(
        f"""
سلام {user.first_name} 👋

به ربات جم اک فروشی خوش آمدید.

از منوی زیر استفاده کنید.
""",
        reply_markup=user_menu()
    )


def reward_inviter_for_user(user_id):
    conn = db()
    cur = conn.cursor()
    cur.execute("SELECT invited_by, invite_rewarded FROM users WHERE telegram_id=?", (user_id,))
    row = cur.fetchone()
    if not row:
        conn.close()
        return False
    inviter = row[0] or 0
    already_rewarded = row[1] or 0
    if already_rewarded == 1:
        conn.close()
        return False
    if not inviter or inviter == user_id:
        conn.close()
        return False
    cur.execute("SELECT telegram_id FROM users WHERE telegram_id=?", (inviter,))
    if not cur.fetchone():
        conn.close()
        return False
    cur.execute("UPDATE users SET balance = balance + ?, invite_count = invite_count + 1 WHERE telegram_id=?",
                (INVITE_REWARD, inviter))
    cur.execute("""
        INSERT INTO transactions (user_id, amount, type, description, created)
        VALUES(?,?,?,?,?)
    """, (inviter, INVITE_REWARD, "invite", f"پاداش دعوت کاربر {user_id}", datetime.now().isoformat()))
    cur.execute("UPDATE users SET invite_rewarded=1 WHERE telegram_id=?", (user_id,))
    conn.commit()
    conn.close()
    return True


async def check_join_button(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    user = query.from_user

    joined_all, not_joined = await check_join(user.id, context)
    if not joined_all:
        keyboard = join_keyboard(not_joined)
        await query.answer("❌ هنوز در همه‌ی کانال‌ها عضو نشده‌اید.", show_alert=True)
        return

    await query.answer("✅ عضویت در همه کانال‌ها تأیید شد.")
    create_user(user.id, user.username, 0)
    rewarded = reward_inviter_for_user(user.id)

    user_data = get_user(user.id)
    if user_data and not user_data[2]:
        contact_button = KeyboardButton("📱 ارسال شماره تلفن", request_contact=True)
        reply_keyboard = ReplyKeyboardMarkup([[contact_button]], resize_keyboard=True, one_time_keyboard=True)
        await query.edit_message_text(
            """
📱 لطفاً شماره تلفن خود را ارسال کنید.

برای این کار روی دکمه‌ی زیر کلیک کنید:
""",
            reply_markup=reply_keyboard
        )
        context.user_data["phone_wait"] = True
        return

    if rewarded:
        text = """
✅ عضویت شما تأیید شد.

🎁 پاداش دعوت ثبت شد.

از منوی زیر استفاده کنید.
"""
    else:
        text = """
✅ عضویت شما تأیید شد.

از منوی زیر استفاده کنید.
"""

    await query.edit_message_text(text, reply_markup=user_menu())


async def phone_message_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if not context.user_data.get("phone_wait"):
        return

    user = update.effective_user
    if is_blocked(user.id):
        context.user_data.pop("phone_wait", None)
        await update.message.reply_text("⛔ حساب شما مسدود شده است.", reply_markup=ReplyKeyboardRemove())
        return

    if update.message.contact:
        phone = update.message.contact.phone_number
    else:
        phone_raw = update.message.text.strip()
        is_valid, phone = is_phone_valid(phone_raw)
        if not is_valid:
            await update.message.reply_text(
                "❌ شماره تلفن معتبر نیست.\n"
                "لطفاً شماره ایران را به صورت 09... یا +989... وارد کنید.",
                reply_markup=ReplyKeyboardMarkup(
                    [[KeyboardButton("📱 ارسال شماره تلفن", request_contact=True)]],
                    resize_keyboard=True,
                    one_time_keyboard=True
                )
            )
            return

    if phone.startswith('+98'):
        phone = '0' + phone[3:]
    elif phone.startswith('98'):
        phone = '0' + phone[2:]

    existing = get_user_by_phone(phone)
    if existing and existing != user.id:
        await update.message.reply_text(
            "❌ این شماره تلفن قبلاً توسط کاربر دیگری ثبت شده است.\n"
            "اگر این شماره متعلق به شماست، لطفاً با پشتیبانی تماس بگیرید.",
            reply_markup=ReplyKeyboardRemove()
        )
        context.user_data.pop("phone_wait", None)
        return

    context.user_data["temp_phone"] = phone
    context.user_data["phone_wait"] = False
    context.user_data["captcha_wait"] = True

    question, answer = generate_captcha()
    context.user_data["captcha_answer"] = answer
    context.user_data["captcha_question"] = question

    await update.message.reply_text(
        f"""
✅ شماره تلفن شما دریافت شد.

🔐 لطفاً برای تأیید هویت، به سوال زیر پاسخ دهید:

❓ {question}

(عدد را وارد کنید)
""",
        reply_markup=ReplyKeyboardRemove()
    )


async def captcha_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if not context.user_data.get("captcha_wait"):
        return

    user = update.effective_user
    if is_blocked(user.id):
        context.user_data.pop("captcha_wait", None)
        context.user_data.pop("temp_phone", None)
        context.user_data.pop("captcha_answer", None)
        context.user_data.pop("captcha_question", None)
        await update.message.reply_text("⛔ حساب شما مسدود شده است.")
        return

    raw = update.message.text.strip()
    eng_num = persian_to_english(raw)
    try:
        user_answer = int(eng_num)
    except ValueError:
        await update.message.reply_text("❌ لطفاً یک عدد معتبر وارد کنید.")
        return

    correct_answer = context.user_data.get("captcha_answer")
    if user_answer != correct_answer:
        question, answer = generate_captcha()
        context.user_data["captcha_answer"] = answer
        context.user_data["captcha_question"] = question
        await update.message.reply_text(
            f"""
❌ پاسخ شما اشتباه بود.

لطفاً دوباره تلاش کنید:

❓ {question}

(عدد را وارد کنید)
"""
        )
        return

    phone = context.user_data.get("temp_phone")
    if phone:
        update_user_phone(user.id, phone)

    context.user_data.pop("captcha_wait", None)
    context.user_data.pop("temp_phone", None)
    context.user_data.pop("captcha_answer", None)
    context.user_data.pop("captcha_question", None)

    await update.message.reply_text(
        f"✅ شماره تلفن شما با موفقیت ثبت شد.\n\n📱 {phone}",
        reply_markup=user_menu()
    )


async def user_buttons(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    user = query.from_user
    data = query.data

    if is_blocked(user.id):
        await query.answer("⛔ حساب شما مسدود شده است.", show_alert=True)
        return

    await query.answer()

    if data not in ["home", "support"]:
        user_data = get_user(user.id)
        if user_data and not user_data[2]:
            contact_button = KeyboardButton("📱 ارسال شماره تلفن", request_contact=True)
            reply_keyboard = ReplyKeyboardMarkup([[contact_button]], resize_keyboard=True, one_time_keyboard=True)
            await query.edit_message_text(
                """
📱 لطفاً شماره تلفن خود را ارسال کنید.

برای این کار روی دکمه‌ی زیر کلیک کنید:
""",
                reply_markup=reply_keyboard
            )
            context.user_data["phone_wait"] = True
            return

    if data == "home":
        await query.edit_message_text("🏠 پنل کاربری\n\nیک گزینه را انتخاب کنید:", reply_markup=user_menu())
        return

    if data == "balance":
        row = get_user(user.id)
        balance = row[3] if row else 0
        await query.edit_message_text(
            f"""
💰 موجودی حساب

موجودی شما:

{balance:,} تومان

━━━━━━━━━━━━━━

💳 برداشت نقدی:
حداقل درخواست: {MIN_WITHDRAW:,} تومان
پرداخت واقعی: {REAL_PAYOUT:,} تومان (کارمزد {WITHDRAW_FEE:,} تومان)

🎮 برداشت جم: هر {MIN_INVITES_FOR_GEM} دعوت = {GEM_PER_INVITE} جم
""",
            reply_markup=back_button()
        )
        return

    if data == "invite":
        row = get_user(user.id)
        count = row[4] if row else 0
        bot_username = context.bot.username
        link = f"https://t.me/{bot_username}?start={user.id}"
        
        keyboard = [
            [InlineKeyboardButton("🔙 بازگشت", callback_data="home")]
        ]
        
        text = f"""
👥 دعوت دوستان

🔗 لینک دعوت شما:
`{link}`

━━━━━━━━━━━━━━

🎁 پاداش هر دعوت موفق:

{INVITE_REWARD:,} تومان

👥 تعداد دعوت‌های موفق:

{count}

━━━━━━━━━━━━━━

🎮 برداشت جم: هر {MIN_INVITES_FOR_GEM} دعوت = {GEM_PER_INVITE} جم

🎁 هر ۱۵ دعوت موفق = ۱۰۰,۰۰۰ تومان پاداش

━━━━━━━━━━━━━━

⚠️ قوانین سیستم دعوت:

• کاربر دعوت‌شده باید کاربر واقعی باشد.
• هر شخص فقط یک بار می‌تواند به عنوان کاربر جدید ثبت شود.
• ساخت چند اکانت برای دریافت پاداش ممنوع است.
• دعوت خودتان ممنوع است.
• پاداش فقط بعد از عضویت کاربر دعوت‌شده در کانال ثبت می‌شود.
"""
        await query.edit_message_text(text, reply_markup=InlineKeyboardMarkup(keyboard), parse_mode="Markdown")
        return

    if data == "profile":
        row = get_user(user.id)
        if not row:
            await query.edit_message_text("❌ اطلاعات شما یافت نشد.", reply_markup=back_button())
            return
        
        telegram_id, username, phone, balance, invite_count, blocked, invited_by, invite_rewarded, payment_method, card_number, game_id = row
        username_text = f"@{username}" if username else "ندارد"
        phone_text = phone if phone else "ثبت نشده"
        status = "🚫 مسدود" if blocked else "✅ فعال"
        payment_text = "کارت بانکی" if payment_method == 'card' else "جم (شارژ بازی)" if payment_method == 'game' else "ثبت نشده"
        payment_info = card_number if payment_method == 'card' else game_id
        payment_info_text = payment_info if payment_info else "ثبت نشده"
        
        gem_available = (invite_count // MIN_INVITES_FOR_GEM) * GEM_PER_INVITE

        await query.edit_message_text(
            f"""
👤 حساب کاربری

🆔 آیدی:
{telegram_id}

👤 نام:
{user.first_name}

📱 یوزرنیم:
{username_text}

📱 شماره تلفن:
{phone_text}

💰 موجودی:
{balance:,} تومان

👥 دعوت موفق:
{invite_count}

🎮 جم قابل برداشت:
{gem_available} جم

📌 وضعیت:
{status}

💳 روش دریافت:
{payment_text}

📝 اطلاعات:
{payment_info_text}
""",
            reply_markup=back_button()
        )
        return

    if data == "transactions":
        conn = db()
        cur = conn.cursor()
        cur.execute("""
            SELECT amount, type, description, created
            FROM transactions
            WHERE user_id=?
            ORDER BY id DESC LIMIT 15
        """, (user.id,))
        rows = cur.fetchall()
        conn.close()

        if not rows:
            text = "📊 تراکنش‌ها\n\nهنوز تراکنشی ثبت نشده است."
        else:
            text = "📊 آخرین تراکنش‌ها:\n\n"
            for amount, typ, desc, date in rows:
                icon = "🎁" if typ == "invite" else "💸" if typ == "withdraw" else "💰"
                if typ in ("admin_add", "admin_remove"):
                    icon = "🛠️"
                text += f"{icon} {amount:,} تومان\n📝 {desc}\n🕐 {date[:16]}\n━━━━━━━━━━━━\n"
        await query.edit_message_text(text, reply_markup=back_button())
        return

    if data == "withdraw":
        row = get_user(user.id)
        balance = row[3] if row else 0
        invite_count = row[4] if row else 0
        
        keyboard = [
            [InlineKeyboardButton("💳 کارت به کارت", callback_data="withdraw_card")],
            [InlineKeyboardButton("🎮 جم با آیدی", callback_data="withdraw_game")],
            [InlineKeyboardButton("🔙 بازگشت", callback_data="home")]
        ]
        
        await query.edit_message_text(
            f"""
💳 برداشت

💰 موجودی نقدی شما: {balance:,} تومان

💳 برداشت نقدی:
حداقل درخواست: {MIN_WITHDRAW:,} تومان
پرداخت واقعی: {REAL_PAYOUT:,} تومان (کارمزد {WITHDRAW_FEE:,} تومان)

━━━━━━━━━━━━━━

🎮 برداشت جم با آی‌دی:
👥 تعداد دعوت‌های موفق: {invite_count}
🎁 هر {MIN_INVITES_FOR_GEM} دعوت = {GEM_PER_INVITE} جم

━━━━━━━━━━━━━━

لطفاً روش دریافت را انتخاب کنید:
""",
            reply_markup=InlineKeyboardMarkup(keyboard)
        )
        return

    if data == "withdraw_card":
        context.user_data["withdraw_method"] = "card"
        context.user_data["withdraw_wait"] = True
        
        await query.edit_message_text(
            f"""
💳 برداشت کارت به کارت

💰 حداقل درخواست: {MIN_WITHDRAW:,} تومان
💳 پرداخت واقعی: {REAL_PAYOUT:,} تومان (کارمزد {WITHDRAW_FEE:,} تومان)

لطفاً شماره کارت ۱۶ رقمی خود را وارد کنید:

مثال:
5859831012345678
""",
            reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("❌ لغو", callback_data="cancel_withdraw")]])
        )
        return

    if data == "withdraw_game":
        # تنظیم مرحله دریافت آیدی بازی
        context.user_data["withdraw_method"] = "game"
        context.user_data["withdraw_wait"] = True
        context.user_data["withdraw_step"] = "game_id"
        
        row = get_user(user.id)
        invite_count = row[4] if row else 0
        gem_available = (invite_count // MIN_INVITES_FOR_GEM) * GEM_PER_INVITE
        
        await query.edit_message_text(
            f"""
🎮 برداشت جم با آی‌دی

👥 تعداد دعوت‌های موفق: {invite_count}
🎁 هر {MIN_INVITES_FOR_GEM} دعوت = {GEM_PER_INVITE} جم
🎁 جم قابل برداشت: {gem_available} جم

لطفاً آیدی خود در بازی را وارد کنید:

مثال:
1234567890
""",
            reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("❌ لغو", callback_data="cancel_withdraw")]])
        )
        return

    if data == "cancel_withdraw":
        context.user_data.pop("withdraw_wait", None)
        context.user_data.pop("withdraw_method", None)
        context.user_data.pop("withdraw_info", None)
        context.user_data.pop("withdraw_step", None)
        await query.edit_message_text("✅ عملیات برداشت لغو شد.", reply_markup=user_menu())
        return

    if data == "support":
        support_text = f"""
📞 پشتیبانی

در صورت وجود هرگونه سؤال یا مشکل، می‌توانید با پشتیبان در ارتباط باشید.

👤 پشتیبان: {SUPPORT_USERNAME}
🆔 آیدی عددی: {OWNER_ID}

لینک مستقیم:
[t.me/{SUPPORT_USERNAME.replace('@', '')}](https://t.me/{SUPPORT_USERNAME.replace('@', '')})

"""
        await query.edit_message_text(support_text, reply_markup=back_button(), parse_mode="Markdown")
        return


# ============================================================
# WITHDRAW HANDLERS
# ============================================================

async def withdraw_game_id_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """دریافت آیدی بازی و ثبت درخواست برداشت جم"""
    if context.user_data.get("withdraw_step") != "game_id":
        return

    user = update.effective_user
    if is_blocked(user.id):
        context.user_data.pop("withdraw_wait", None)
        context.user_data.pop("withdraw_method", None)
        context.user_data.pop("withdraw_step", None)
        await update.message.reply_text("⛔ حساب شما مسدود شده است.")
        return

    game_id = update.message.text.strip()
    if not re.match(r'^\d+$', game_id):
        await update.message.reply_text("❌ آیدی بازی باید عددی باشد.\nلطفاً دوباره وارد کنید.")
        return

    row = get_user(user.id)
    if not row:
        context.user_data.pop("withdraw_wait", None)
        context.user_data.pop("withdraw_method", None)
        context.user_data.pop("withdraw_step", None)
        await update.message.reply_text("❌ حساب شما پیدا نشد.")
        return

    invite_count = row[4]
    gem_available = (invite_count // MIN_INVITES_FOR_GEM) * GEM_PER_INVITE

    # ثبت درخواست برداشت جم
    conn = db()
    cur = conn.cursor()
    cur.execute("""
        INSERT INTO withdrawals (user_id, amount, actual_amount, method, game_id, gem_count, status, created)
        VALUES(?,?,?,?,?,?,?,?)
    """, (user.id, 0, 0, "game", game_id, gem_available, "pending", datetime.now().isoformat()))
    withdrawal_id = cur.lastrowid
    conn.commit()
    conn.close()

    context.user_data.pop("withdraw_wait", None)
    context.user_data.pop("withdraw_method", None)
    context.user_data.pop("withdraw_step", None)

    await update.message.reply_text(
        f"""
✅ درخواست برداشت جم ثبت شد.

🆔 شماره درخواست: #{withdrawal_id}

🎮 آیدی بازی: {game_id}
🎁 تعداد جم قابل برداشت: {gem_available} جم

⏳ وضعیت: در انتظار بررسی مدیر
""",
        reply_markup=user_menu()
    )


async def withdraw_card_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """مرحله دریافت شماره کارت برای برداشت نقدی"""
    if not context.user_data.get("withdraw_wait") or context.user_data.get("withdraw_method") != "card":
        return

    user = update.effective_user
    if is_blocked(user.id):
        context.user_data.pop("withdraw_wait", None)
        context.user_data.pop("withdraw_method", None)
        await update.message.reply_text("⛔ حساب شما مسدود شده است.")
        return

    card = update.message.text.strip().replace(" ", "").replace("-", "")
    if not re.match(r'^\d{16}$', card):
        await update.message.reply_text("❌ شماره کارت باید ۱۶ رقم باشد.\nلطفاً دوباره وارد کنید.")
        return

    context.user_data["withdraw_info"] = {"card_number": card}
    context.user_data["withdraw_step"] = "amount_card"

    row = get_user(user.id)
    balance = row[3] if row else 0

    await update.message.reply_text(
        f"""
💳 مبلغ درخواست برداشت را وارد کنید:

💰 موجودی شما: {balance:,} تومان
💳 حداقل درخواست: {MIN_WITHDRAW:,} تومان
💳 پرداخت واقعی: {REAL_PAYOUT:,} تومان (کارمزد {WITHDRAW_FEE:,} تومان)

مثال:
150000
""",
        reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("❌ لغو", callback_data="cancel_withdraw")]])
    )


async def withdraw_amount_card_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """مرحله دریافت مبلغ برای برداشت نقدی"""
    if context.user_data.get("withdraw_step") != "amount_card":
        return

    user = update.effective_user
    if is_blocked(user.id):
        context.user_data.pop("withdraw_wait", None)
        context.user_data.pop("withdraw_method", None)
        context.user_data.pop("withdraw_info", None)
        context.user_data.pop("withdraw_step", None)
        await update.message.reply_text("⛔ حساب شما مسدود شده است.")
        return

    try:
        amount = int(update.message.text.replace(",", "").replace(" ", ""))
    except ValueError:
        await update.message.reply_text("❌ مبلغ صحیح نیست.\nلطفاً یک عدد معتبر وارد کنید.")
        return

    if amount < MIN_WITHDRAW:
        await update.message.reply_text(f"❌ مبلغ کمتر از حداقل درخواست است.\nحداقل درخواست: {MIN_WITHDRAW:,} تومان")
        return

    row = get_user(user.id)
    if not row:
        context.user_data.pop("withdraw_wait", None)
        context.user_data.pop("withdraw_method", None)
        context.user_data.pop("withdraw_info", None)
        context.user_data.pop("withdraw_step", None)
        await update.message.reply_text("❌ حساب شما پیدا نشد.")
        return

    balance = row[3]
    if amount > balance:
        await update.message.reply_text(f"❌ موجودی کافی نیست.\n💰 موجودی: {balance:,} تومان")
        return

    actual_amount = amount - WITHDRAW_FEE
    if actual_amount < 0:
        await update.message.reply_text(
            f"❌ مبلغ درخواستی کمتر از کارمزد {WITHDRAW_FEE:,} تومان است.\n"
            f"حداقل درخواست: {MIN_WITHDRAW:,} تومان"
        )
        return

    card_number = context.user_data.get("withdraw_info", {}).get("card_number")

    conn = db()
    cur = conn.cursor()
    cur.execute("""
        INSERT INTO withdrawals (user_id, amount, actual_amount, method, card_number, status, created)
        VALUES(?,?,?,?,?,?,?)
    """, (user.id, amount, actual_amount, "card", card_number, "pending", datetime.now().isoformat()))
    withdrawal_id = cur.lastrowid
    conn.commit()
    conn.close()

    context.user_data.pop("withdraw_wait", None)
    context.user_data.pop("withdraw_method", None)
    context.user_data.pop("withdraw_info", None)
    context.user_data.pop("withdraw_step", None)

    await update.message.reply_text(
        f"""
✅ درخواست برداشت نقدی ثبت شد.

🆔 شماره درخواست: #{withdrawal_id}

💰 مبلغ درخواستی: {amount:,} تومان
💳 مبلغ پرداختی: {actual_amount:,} تومان (کارمزد {WITHDRAW_FEE:,} تومان)
📌 روش: کارت به کارت - {card_number}

⏳ وضعیت: در انتظار بررسی مدیر
""",
        reply_markup=user_menu()
    )


# ============================================================
# ADMIN SYSTEM
# ============================================================

def is_admin(user_id):
    if user_id == OWNER_ID:
        return True
    conn = db()
    cur = conn.cursor()
    cur.execute("SELECT user_id FROM admins WHERE user_id=?", (user_id,))
    result = cur.fetchone()
    conn.close()
    return result is not None


def admin_menu():
    keyboard = [
        [InlineKeyboardButton("📊 آمار", callback_data="admin_stats"),
         InlineKeyboardButton("👥 کاربران", callback_data="admin_users")],
        [InlineKeyboardButton("💸 برداشت‌ها", callback_data="admin_withdraw")],
        [InlineKeyboardButton("💰 گزارش مالی", callback_data="admin_finance")],
        [InlineKeyboardButton("📢 ارسال پیام همگانی", callback_data="admin_broadcast")],
        [InlineKeyboardButton("💳 مدیریت موجودی", callback_data="admin_balance_manage")],
        [InlineKeyboardButton("👥 مدیریت ادمین‌ها", callback_data="admin_manage_admins")],
        [InlineKeyboardButton("🔙 پنل کاربر", callback_data="home")]
    ]
    return InlineKeyboardMarkup(keyboard)


async def admin(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    if not is_admin(user.id):
        await update.message.reply_text("⛔ دسترسی ندارید.")
        return
    await update.message.reply_text(
        f"""
👑 پنل مدیریت

👤 ادمین: {ADMIN_USERNAME}

یکی از گزینه‌ها را انتخاب کنید:
""",
        reply_markup=admin_menu()
    )


# ============================================================
# ADMIN COMMANDS
# ============================================================

async def block_user(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    if not is_admin(user.id):
        await update.message.reply_text("⛔ دسترسی ندارید.")
        return

    if not context.args:
        await update.message.reply_text("❗ لطفاً آیدی یا یوزرنیم کاربر را وارد کنید.\nمثال: /block 123456789\nیا: /block @username")
        return

    identifier = " ".join(context.args)
    target = find_user(identifier)
    if not target:
        await update.message.reply_text("❌ کاربر پیدا نشد.")
        return

    target_id, username, balance, invite_count, blocked = target
    if target_id == OWNER_ID:
        await update.message.reply_text("❌ نمی‌توانید ادمین اصلی را مسدود کنید.")
        return

    if blocked:
        await update.message.reply_text(f"ℹ️ کاربر {target_id} قبلاً مسدود است.")
        return

    conn = db()
    cur = conn.cursor()
    cur.execute("UPDATE users SET blocked=1 WHERE telegram_id=?", (target_id,))
    conn.commit()
    conn.close()
    await update.message.reply_text(f"✅ کاربر {target_id} ({username or 'بدون یوزرنیم'}) مسدود شد.")


async def unblock_user(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    if not is_admin(user.id):
        await update.message.reply_text("⛔ دسترسی ندارید.")
        return

    if not context.args:
        await update.message.reply_text("❗ لطفاً آیدی یا یوزرنیم کاربر را وارد کنید.\nمثال: /unblock 123456789\nیا: /unblock @username")
        return

    identifier = " ".join(context.args)
    target = find_user(identifier)
    if not target:
        await update.message.reply_text("❌ کاربر پیدا نشد.")
        return

    target_id, username, balance, invite_count, blocked = target
    if not blocked:
        await update.message.reply_text(f"ℹ️ کاربر {target_id} مسدود نیست.")
        return

    conn = db()
    cur = conn.cursor()
    cur.execute("UPDATE users SET blocked=0 WHERE telegram_id=?", (target_id,))
    conn.commit()
    conn.close()
    await update.message.reply_text(f"✅ کاربر {target_id} ({username or 'بدون یوزرنیم'}) رفع مسدود شد.")


async def add_admin(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    if not is_admin(user.id):
        await update.message.reply_text("⛔ دسترسی ندارید.")
        return

    if not context.args:
        await update.message.reply_text("❗ لطفاً آیدی یا یوزرنیم کاربر را وارد کنید.\nمثال: /addadmin 123456789")
        return

    identifier = " ".join(context.args)
    target = find_user(identifier)
    if not target:
        await update.message.reply_text("❌ کاربر پیدا نشد.")
        return

    target_id, username, balance, invite_count, blocked = target
    conn = db()
    cur = conn.cursor()
    cur.execute("INSERT OR IGNORE INTO admins (user_id, created) VALUES (?, ?)", (target_id, datetime.now().isoformat()))
    conn.commit()
    conn.close()
    await update.message.reply_text(f"✅ کاربر {target_id} ({username or 'بدون یوزرنیم'}) به ادمین‌ها اضافه شد.")


async def remove_admin(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    if not is_admin(user.id):
        await update.message.reply_text("⛔ دسترسی ندارید.")
        return

    if not context.args:
        await update.message.reply_text("❗ لطفاً آیدی یا یوزرنیم کاربر را وارد کنید.\nمثال: /removeadmin 123456789")
        return

    identifier = " ".join(context.args)
    target = find_user(identifier)
    if not target:
        await update.message.reply_text("❌ کاربر پیدا نشد.")
        return

    target_id, username, balance, invite_count, blocked = target
    if target_id == OWNER_ID:
        await update.message.reply_text("❌ نمی‌توانید ادمین اصلی را حذف کنید.")
        return

    conn = db()
    cur = conn.cursor()
    cur.execute("DELETE FROM admins WHERE user_id=?", (target_id,))
    conn.commit()
    conn.close()
    await update.message.reply_text(f"✅ کاربر {target_id} ({username or 'بدون یوزرنیم'}) از ادمین‌ها حذف شد.")


async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    if not is_admin(user.id):
        await update.message.reply_text("⛔ دسترسی ندارید.")
        return

    context.user_data.pop("balance_step", None)
    context.user_data.pop("balance_target", None)
    context.user_data.pop("balance_action", None)
    context.user_data.pop("withdraw_wait", None)
    context.user_data.pop("withdraw_method", None)
    context.user_data.pop("withdraw_info", None)
    context.user_data.pop("withdraw_step", None)
    context.user_data.pop("broadcast", None)
    context.user_data.pop("phone_wait", None)
    context.user_data.pop("captcha_wait", None)
    context.user_data.pop("temp_phone", None)
    context.user_data.pop("captcha_answer", None)
    context.user_data.pop("captcha_question", None)

    await update.message.reply_text("✅ عملیات جاری لغو شد.", reply_markup=admin_menu())


# ============================================================
# ADMIN BALANCE MANAGEMENT
# ============================================================

async def admin_balance_manage(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    user = query.from_user
    if not is_admin(user.id):
        await query.answer("⛔ دسترسی ندارید.", show_alert=True)
        return

    await query.answer()
    keyboard = [
        [InlineKeyboardButton("➕ افزایش موجودی", callback_data="admin_balance_increase")],
        [InlineKeyboardButton("➖ کاهش موجودی", callback_data="admin_balance_decrease")],
        [InlineKeyboardButton("🔙 بازگشت", callback_data="admin_home")]
    ]
    await query.edit_message_text(
        "💳 مدیریت موجودی\n\nانتخاب کنید:",
        reply_markup=InlineKeyboardMarkup(keyboard)
    )


async def admin_balance_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    user = query.from_user
    if not is_admin(user.id):
        await query.answer("⛔ دسترسی ندارید.", show_alert=True)
        return

    await query.answer()
    action = query.data.split("_")[-1]
    context.user_data["balance_action"] = action
    context.user_data["balance_step"] = "waiting_for_user_id"
    
    logging.info(f"✅ admin_balance_start executed: action={action}, user={user.id}")

    await query.edit_message_text(
        f"📝 لطفاً یوزرنیم (با یا بدون @) یا آیدی عددی کاربر را برای {'افزایش' if action == 'increase' else 'کاهش'} موجودی وارد کنید.\n\n"
        "مثال:\n"
        "• @username\n"
        "• username\n"
        "• 123456789\n\n"
        "برای لغو، /cancel را بزنید."
    )


async def balance_message_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    logging.info(f"📩 balance_message_handler called by {user.id}")
    
    if not is_admin(user.id):
        await update.message.reply_text("⛔ دسترسی ندارید.")
        return

    step = context.user_data.get("balance_step")
    logging.info(f"📩 balance_message_handler step={step}")

    if not step:
        await update.message.reply_text(
            "❌ شما در حالت مدیریت موجودی نیستید.\n"
            "لطفاً ابتدا از پنل ادمین گزینه «مدیریت موجودی» را انتخاب کنید."
        )
        return

    action = context.user_data.get("balance_action")

    try:
        if step == "waiting_for_user_id":
            identifier = update.message.text.strip()
            target = find_user(identifier)
            if not target:
                await update.message.reply_text(
                    "❌ کاربری با این مشخصات یافت نشد.\n"
                    "لطفاً یک یوزرنیم معتبر (با یا بدون @) یا آیدی عددی وارد کنید."
                )
                return

            target_id, username, balance, invite_count, blocked = target
            context.user_data["balance_target"] = target_id
            context.user_data["balance_step"] = "waiting_for_amount"
            
            user_data = get_user(target_id)
            phone = user_data[2] if user_data else None
            payment_method = user_data[8] if user_data else None
            card_number = user_data[9] if user_data else None
            game_id = user_data[10] if user_data else None
            
            phone_text = phone if phone else "ثبت نشده"
            payment_text = "کارت بانکی" if payment_method == "card" else "جم" if payment_method == "game" else "ثبت نشده"
            payment_info = card_number if payment_method == "card" else game_id
            payment_info_text = payment_info if payment_info else "ثبت نشده"
            
            await update.message.reply_text(
                f"✅ کاربر پیدا شد:\n\n"
                f"🆔 آیدی عددی: {target_id}\n"
                f"👤 یوزرنیم: {f'@{username}' if username else 'ندارد'}\n"
                f"📱 شماره تلفن: {phone_text}\n"
                f"💰 موجودی فعلی: {balance:,} تومان\n"
                f"👥 دعوت موفق: {invite_count}\n"
                f"📌 وضعیت: {'🚫 مسدود' if blocked else '✅ فعال'}\n"
                f"💳 روش دریافت: {payment_text}\n"
                f"📝 اطلاعات: {payment_info_text}\n\n"
                f"لطفاً مبلغ مورد نظر را به عدد وارد کنید (مثال: 50000):"
            )

        elif step == "waiting_for_amount":
            try:
                amount = int(update.message.text.replace(",", "").replace(" ", ""))
            except ValueError:
                await update.message.reply_text("❌ مبلغ باید عددی باشد. لطفاً دوباره وارد کنید.")
                return

            if amount <= 0:
                await update.message.reply_text("❌ مبلغ باید بزرگ‌تر از صفر باشد.")
                return

            target_id = context.user_data.get("balance_target")
            if not target_id:
                await update.message.reply_text("❌ خطا: کاربر مشخص نشده. لطفاً دوباره از ابتدا شروع کنید.")
                context.user_data.pop("balance_step", None)
                context.user_data.pop("balance_target", None)
                context.user_data.pop("balance_action", None)
                return

            conn = db()
            cur = conn.cursor()
            cur.execute("SELECT balance, username FROM users WHERE telegram_id=?", (target_id,))
            row = cur.fetchone()
            if not row:
                conn.close()
                await update.message.reply_text("❌ کاربر پیدا نشد.")
                context.user_data.pop("balance_step", None)
                context.user_data.pop("balance_target", None)
                context.user_data.pop("balance_action", None)
                return

            current_balance, username = row
            
            if action not in ["increase", "decrease"]:
                await update.message.reply_text(
                    "❌ نوع عملیات مشخص نیست. لطفاً از دکمه‌های افزایش/کاهش استفاده کنید."
                )
                context.user_data.pop("balance_step", None)
                context.user_data.pop("balance_target", None)
                context.user_data.pop("balance_action", None)
                return

            if action == "increase":
                new_balance = current_balance + amount
                trans_type = "admin_add"
                desc = f"افزایش دستی موجودی به مقدار {amount:,} تومان توسط ادمین"
            else:
                if current_balance < amount:
                    await update.message.reply_text(
                        f"❌ موجودی کاربر ({current_balance:,} تومان) کمتر از مبلغ مورد نظر است."
                    )
                    return
                new_balance = current_balance - amount
                trans_type = "admin_remove"
                desc = f"کاهش دستی موجودی به مقدار {amount:,} تومان توسط ادمین"

            cur.execute("UPDATE users SET balance=? WHERE telegram_id=?", (new_balance, target_id))
            cur.execute("""
                INSERT INTO transactions (user_id, amount, type, description, created)
                VALUES(?,?,?,?,?)
            """, (target_id, amount, trans_type, desc, datetime.now().isoformat()))
            conn.commit()
            conn.close()

            await update.message.reply_text(
                f"✅ عملیات با موفقیت انجام شد.\n\n"
                f"👤 کاربر: {target_id} ({f'@{username}' if username else 'بدون یوزرنیم'})\n"
                f"💰 موجودی قبلی: {current_balance:,} تومان\n"
                f"💰 موجودی جدید: {new_balance:,} تومان"
            )

            context.user_data.pop("balance_step", None)
            context.user_data.pop("balance_target", None)
            context.user_data.pop("balance_action", None)

            await update.message.reply_text(
                f"👑 پنل مدیریت\n\n👤 ادمین: {ADMIN_USERNAME}",
                reply_markup=admin_menu()
            )

    except Exception as e:
        logging.error(f"❌ خطا در balance_message_handler: {e}")
        await update.message.reply_text(
            f"❌ خطایی رخ داد: {str(e)}\nلطفاً دوباره از ابتدا شروع کنید یا با /cancel عملیات را لغو کنید."
        )
        context.user_data.pop("balance_step", None)
        context.user_data.pop("balance_target", None)
        context.user_data.pop("balance_action", None)


# ============================================================
# ADMIN BUTTONS
# ============================================================

async def admin_buttons(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    user = query.from_user
    data = query.data

    if not is_admin(user.id):
        await query.answer("⛔ دسترسی ندارید.", show_alert=True)
        return

    await query.answer()

    if data == "admin_home":
        await query.edit_message_text(
            f"""
👑 پنل مدیریت

👤 ادمین: {ADMIN_USERNAME}

یکی از گزینه‌ها را انتخاب کنید:
""",
            reply_markup=admin_menu()
        )
        return

    if data == "admin_stats":
        conn = db()
        cur = conn.cursor()
        cur.execute("SELECT COUNT(*) FROM users")
        total_users = cur.fetchone()[0]
        cur.execute("SELECT COALESCE(SUM(balance), 0) FROM users")
        total_balance = cur.fetchone()[0]
        cur.execute("SELECT COALESCE(SUM(invite_count), 0) FROM users")
        total_invites = cur.fetchone()[0]
        cur.execute("SELECT COUNT(*) FROM withdrawals WHERE status='pending'")
        pending_withdrawals = cur.fetchone()[0]
        conn.close()

        await query.edit_message_text(
            f"""
📊 آمار ربات

👥 تعداد کاربران:

{total_users:,}

👥 مجموع دعوت‌های موفق:

{total_invites:,}

💰 مجموع موجودی کاربران:

{total_balance:,} تومان

💸 برداشت‌های در انتظار:

{pending_withdrawals:,}
""",
            reply_markup=admin_menu()
        )
        return

    if data == "admin_users":
        await show_users(query, page=0)
        return

    if data.startswith("admin_users_page_"):
        try:
            page = int(data.split("_")[-1])
        except Exception:
            page = 0
        await show_users(query, page)
        return

    if data.startswith("admin_user_detail_"):
        try:
            target_id = int(data.split("_")[3])
        except Exception:
            await query.answer("❌ خطا در داده.", show_alert=True)
            return
        await show_user_detail(query, target_id)
        return

    if data.startswith("admin_toggle_block_"):
        parts = data.split("_")
        try:
            target_id = int(parts[3])
            page = int(parts[4]) if len(parts) > 4 else 0
        except Exception:
            await query.answer("❌ خطا در داده.", show_alert=True)
            return

        if target_id == OWNER_ID:
            await query.answer("❌ نمی‌توانید ادمین اصلی را تغییر دهید.", show_alert=True)
            return

        conn = db()
        cur = conn.cursor()
        cur.execute("SELECT blocked FROM users WHERE telegram_id=?", (target_id,))
        row = cur.fetchone()
        if not row:
            conn.close()
            await query.answer("❌ کاربر پیدا نشد.", show_alert=True)
            return

        new_status = 0 if row[0] == 1 else 1
        cur.execute("UPDATE users SET blocked=? WHERE telegram_id=?", (new_status, target_id))
        conn.commit()
        conn.close()

        await show_users(query, page)
        return

    if data == "admin_finance":
        conn = db()
        cur = conn.cursor()
        cur.execute("SELECT COALESCE(SUM(amount), 0) FROM transactions WHERE type='invite'")
        rewards = cur.fetchone()[0]
        cur.execute("SELECT COALESCE(SUM(actual_amount), 0) FROM withdrawals WHERE status='approved' AND method='card'")
        actual_withdrawals = cur.fetchone()[0]
        conn.close()

        await query.edit_message_text(
            f"""
💰 گزارش مالی

🎁 مجموع پاداش دعوت:

{rewards:,} تومان

💸 مجموع برداشت نقدی تایید شده (پرداخت واقعی):

{actual_withdrawals:,} تومان

⚠️ کارمزد برداشت نقدی: {WITHDRAW_FEE:,} تومان از هر درخواست
""",
            reply_markup=admin_menu()
        )
        return

    if data == "admin_withdraw":
        await show_pending_withdrawals(query)
        return

    if data.startswith("approve_"):
        try:
            wid = int(data.split("_")[1])
        except Exception:
            await query.answer("❌ درخواست نامعتبر است.", show_alert=True)
            return

        result = approve_withdraw(wid, context)
        if result:
            user_id, amount, actual_amount, method, card_number, game_id, gem_count = result
            if method == "card":
                await query.edit_message_text(
                    f"""
✅ برداشت نقدی تایید شد.

🆔 درخواست: #{wid}

👤 کاربر: {user_id}

💰 مبلغ درخواستی: {amount:,} تومان
💳 مبلغ پرداختی: {actual_amount:,} تومان (کارمزد {WITHDRAW_FEE:,} تومان)
📌 روش دریافت: کارت به کارت - {card_number}
""",
                    reply_markup=admin_menu()
                )
            else:  # game
                await query.edit_message_text(
                    f"""
✅ برداشت جم تایید شد.

🆔 درخواست: #{wid}

👤 کاربر: {user_id}

🎮 آیدی بازی: {game_id}
🎁 تعداد جم: {gem_count} جم
""",
                    reply_markup=admin_menu()
                )
        else:
            await query.edit_message_text(
                "❌ این درخواست پیدا نشد یا قبلاً بررسی شده است.",
                reply_markup=admin_menu()
            )
        return

    if data.startswith("reject_"):
        try:
            wid = int(data.split("_")[1])
        except Exception:
            await query.answer("❌ درخواست نامعتبر است.", show_alert=True)
            return

        result = reject_withdraw(wid, context)
        if result:
            user_id, amount, method = result
            await query.edit_message_text(
                f"""
❌ برداشت رد شد.

🆔 درخواست: #{wid}

👤 کاربر: {user_id}
💰 مبلغ: {amount:,} تومان
""",
                reply_markup=admin_menu()
            )
        else:
            await query.edit_message_text(
                "❌ این درخواست پیدا نشد یا قبلاً بررسی شده است.",
                reply_markup=admin_menu()
            )
        return

    if data == "admin_broadcast":
        context.user_data["broadcast"] = True
        keyboard = [[InlineKeyboardButton("❌ لغو", callback_data="cancel_broadcast")]]
        await query.edit_message_text(
            "📢 لطفاً پیامی را که می‌خواهید به همه کاربران ارسال شود، بنویسید یا فوروارد کنید.\n\n"
            "⚠️ توجه: این پیام به تمام کاربران فعال ربات ارسال خواهد شد.\n"
            "کاربرانی که ربات را بلاک کرده‌اند، به‌طور خودکار مسدود می‌شوند.",
            reply_markup=InlineKeyboardMarkup(keyboard)
        )
        return

    if data == "cancel_broadcast":
        context.user_data.pop("broadcast", None)
        await query.edit_message_text(
            "✅ ارسال همگانی لغو شد.",
            reply_markup=admin_menu()
        )
        return

    if data == "admin_manage_admins":
        conn = db()
        cur = conn.cursor()
        cur.execute("SELECT user_id FROM admins ORDER BY user_id")
        admin_rows = cur.fetchall()
        conn.close()

        admin_list = [OWNER_ID] + [row[0] for row in admin_rows]
        text = "👥 لیست ادمین‌ها:\n\n"
        for uid in admin_list:
            user_info = get_user(uid)
            username = user_info[1] if user_info else None
            text += f"🆔 {uid} {f'(@{username})' if username else ''}\n"
        text += "\n❗ برای افزودن/حذف ادمین از دستورات زیر استفاده کنید:\n"
        text += "/addadmin <user_id>\n/removeadmin <user_id>"

        await query.edit_message_text(text, reply_markup=admin_menu())
        return

    if data == "admin_balance_manage":
        await admin_balance_manage(update, context)
        return

    if data == "admin_balance_increase" or data == "admin_balance_decrease":
        logging.info(f"✅ Balance button clicked: {data}")
        await admin_balance_start(update, context)
        return

    if data.startswith("admin_balance_user_"):
        try:
            target_id = int(data.split("_")[3])
        except Exception:
            await query.answer("❌ خطا در داده.", show_alert=True)
            return
        
        logging.info(f"✅ admin_balance_user_ clicked for user {target_id}")
        context.user_data["balance_action"] = "increase"
        context.user_data["balance_target"] = target_id
        context.user_data["balance_step"] = "waiting_for_amount"
        
        user_info = get_user(target_id)
        if not user_info:
            await query.edit_message_text("❌ کاربر پیدا نشد.", reply_markup=admin_menu())
            return
        
        username = user_info[1]
        balance = user_info[3]
        invite_count = user_info[4]
        blocked = user_info[5]
        phone = user_info[2]
        payment_method = user_info[8]
        card_number = user_info[9]
        game_id = user_info[10]
        
        keyboard = [
            [InlineKeyboardButton("➕ افزایش", callback_data="admin_balance_increase"),
             InlineKeyboardButton("➖ کاهش", callback_data="admin_balance_decrease")],
            [InlineKeyboardButton("🔙 بازگشت", callback_data="admin_home")]
        ]
        
        phone_text = phone if phone else "ثبت نشده"
        payment_text = "کارت بانکی" if payment_method == "card" else "جم" if payment_method == "game" else "ثبت نشده"
        payment_info = card_number if payment_method == "card" else game_id
        payment_info_text = payment_info if payment_info else "ثبت نشده"
        
        await query.edit_message_text(
            f"""
💳 مدیریت موجودی کاربر

🆔 آیدی: {target_id}
👤 یوزرنیم: {f'@{username}' if username else 'ندارد'}
📱 تلفن: {phone_text}
💰 موجودی فعلی: {balance:,} تومان
👥 دعوت موفق: {invite_count}
📌 وضعیت: {'🚫 مسدود' if blocked else '✅ فعال'}
💳 روش دریافت: {payment_text}
📝 اطلاعات: {payment_info_text}

لطفاً ابتدا نوع عملیات را انتخاب کنید:
""",
            reply_markup=InlineKeyboardMarkup(keyboard)
        )
        return


# ============================================================
# SHOW USER DETAIL
# ============================================================

async def show_user_detail(query, user_id):
    conn = db()
    cur = conn.cursor()
    cur.execute("""
        SELECT telegram_id, username, phone_number, balance, invite_count, blocked, created, invited_by,
               payment_method, card_number, game_id
        FROM users WHERE telegram_id=?
    """, (user_id,))
    row = cur.fetchone()
    conn.close()

    if not row:
        await query.edit_message_text("❌ کاربر پیدا نشد.", reply_markup=admin_menu())
        return

    telegram_id, username, phone, balance, invite_count, blocked, created, invited_by, payment_method, card_number, game_id = row
    username_text = f"@{username}" if username else "ندارد"
    phone_text = phone if phone else "ثبت نشده"
    status = "🚫 مسدود" if blocked else "✅ فعال"

    inviter_text = "ندارد"
    if invited_by:
        inv = get_user(invited_by)
        if inv:
            inviter_text = f"{invited_by} (@{inv[1]})" if inv[1] else str(invited_by)

    payment_text = "کارت بانکی" if payment_method == "card" else "جم" if payment_method == "game" else "ثبت نشده"
    payment_info = card_number if payment_method == "card" else game_id
    payment_info_text = payment_info if payment_info else "ثبت نشده"

    gem_available = (invite_count // MIN_INVITES_FOR_GEM) * GEM_PER_INVITE

    text = f"""
👤 اطلاعات کاربر

🆔 آیدی عددی:
{telegram_id}

👤 نام کاربری:
{username_text}

📱 شماره تلفن:
{phone_text}

💰 موجودی:
{balance:,} تومان

👥 تعداد دعوت‌های موفق:
{invite_count}

🎮 جم قابل برداشت:
{gem_available} جم

📌 وضعیت:
{status}

📅 تاریخ ثبت‌نام:
{created[:16]}

👤 دعوت‌کننده:
{inviter_text}

💳 روش دریافت:
{payment_text}

📝 اطلاعات:
{payment_info_text}
"""

    keyboard = [
        [
            InlineKeyboardButton("🚫 مسدود" if not blocked else "✅ رفع مسدود",
                                 callback_data=f"admin_toggle_block_{telegram_id}_0"),
            InlineKeyboardButton("💳 مدیریت موجودی", callback_data=f"admin_balance_user_{telegram_id}")
        ],
        [InlineKeyboardButton("🔙 بازگشت به لیست", callback_data="admin_users")]
    ]
    await query.edit_message_text(text, reply_markup=InlineKeyboardMarkup(keyboard))


# ============================================================
# SHOW USERS
# ============================================================

async def show_users(query, page=0):
    conn = db()
    cur = conn.cursor()
    cur.execute("SELECT COUNT(*) FROM users")
    total_users = cur.fetchone()[0]

    offset = page * USERS_PER_PAGE
    cur.execute("""
        SELECT telegram_id, username, phone_number, balance, invite_count, blocked
        FROM users
        ORDER BY id DESC
        LIMIT ? OFFSET ?
    """, (USERS_PER_PAGE, offset))
    rows = cur.fetchall()
    conn.close()

    if not rows:
        await query.edit_message_text(
            "👥 کاربران\n\nکاربری در این صفحه وجود ندارد.",
            reply_markup=admin_menu()
        )
        return

    text = f"👥 لیست کاربران\n\n📊 تعداد کل کاربران: {total_users:,}\n\n"
    keyboard = []

    for telegram_id, username, phone, balance, invite_count, blocked in rows:
        username_text = f"@{username}" if username else "ندارد"
        phone_text = phone if phone else "ندارد"
        status = "🚫" if blocked else "✅"
        gem_available = (invite_count // MIN_INVITES_FOR_GEM) * GEM_PER_INVITE
        text += (
            f"🆔 {telegram_id} | {username_text}\n"
            f"📱 {phone_text}\n"
            f"💰 {balance:,} | 👥 {invite_count} | 🎮{gem_available} | {status}\n"
        )
        keyboard.append([
            InlineKeyboardButton(f"📋 اطلاعات", callback_data=f"admin_user_detail_{telegram_id}"),
            InlineKeyboardButton("🚫" if not blocked else "✅", callback_data=f"admin_toggle_block_{telegram_id}_{page}")
        ])

    text += "━━━━━━━━━━━━━━"

    nav_buttons = []
    if page > 0:
        nav_buttons.append(InlineKeyboardButton("⬅️", callback_data=f"admin_users_page_{page - 1}"))
    if offset + USERS_PER_PAGE < total_users:
        nav_buttons.append(InlineKeyboardButton("➡️", callback_data=f"admin_users_page_{page + 1}"))
    if nav_buttons:
        keyboard.append(nav_buttons)

    keyboard.append([InlineKeyboardButton("🔙 پنل مدیریت", callback_data="admin_home")])

    await query.edit_message_text(text, reply_markup=InlineKeyboardMarkup(keyboard))


# ============================================================
# SHOW PENDING WITHDRAWALS
# ============================================================

async def show_pending_withdrawals(query):
    conn = db()
    cur = conn.cursor()
    cur.execute("""
        SELECT id, user_id, amount, actual_amount, method, card_number, game_id, gem_count, created
        FROM withdrawals
        WHERE status='pending'
        ORDER BY id DESC
        LIMIT 30
    """)
    rows = cur.fetchall()
    conn.close()

    if not rows:
        await query.edit_message_text(
            "💸 برداشت‌ها\n\n✅ هیچ برداشت در انتظاری وجود ندارد.",
            reply_markup=admin_menu()
        )
        return

    text = "💸 برداشت‌های در انتظار:\n\n"
    keyboard = []
    for wid, user_id, amount, actual_amount, method, card_number, game_id, gem_count, created in rows:
        user_info = get_user(user_id)
        username = user_info[1] if user_info else None
        username_text = f"(@{username})" if username else ""
        
        if method == "card":
            method_text = "کارت"
            method_value = card_number
            amount_text = f"درخواست: {amount:,} تومان | پرداخت: {actual_amount:,} تومان"
        else:
            method_text = "جم"
            method_value = game_id
            amount_text = f"{gem_count} جم"
        
        text += (
            f"🆔 درخواست: #{wid}\n"
            f"👤 کاربر: {user_id} {username_text}\n"
            f"💰 {amount_text}\n"
            f"📌 روش: {method_text} - {method_value}\n"
            f"🕐 {created[:16]}\n"
            f"━━━━━━━━━━━━━━\n"
        )
        keyboard.append([
            InlineKeyboardButton(f"✅ تایید #{wid}", callback_data=f"approve_{wid}"),
            InlineKeyboardButton(f"❌ رد #{wid}", callback_data=f"reject_{wid}")
        ])

    keyboard.append([InlineKeyboardButton("🔙 پنل مدیریت", callback_data="admin_home")])
    await query.edit_message_text(text, reply_markup=InlineKeyboardMarkup(keyboard))


# ============================================================
# APPROVE / REJECT WITHDRAW
# ============================================================

def approve_withdraw(wid, context=None):
    conn = db()
    cur = conn.cursor()
    cur.execute("SELECT user_id, amount, actual_amount, method, card_number, game_id, gem_count, status FROM withdrawals WHERE id=?", (wid,))
    row = cur.fetchone()
    if not row or row[7] != "pending":
        conn.close()
        return None

    user_id, amount, actual_amount, method, card_number, game_id, gem_count, status = row
    
    if method == "card":
        cur.execute("SELECT balance FROM users WHERE telegram_id=?", (user_id,))
        user_row = cur.fetchone()
        if not user_row or user_row[0] < amount:
            conn.close()
            return None
        
        cur.execute("UPDATE users SET balance=balance-? WHERE telegram_id=?", (amount, user_id))
        cur.execute("""
            INSERT INTO transactions (user_id, amount, type, description, created)
            VALUES(?,?,?,?,?)
        """, (user_id, actual_amount, "withdraw", f"برداشت نقدی #{wid} - پرداخت {actual_amount:,} تومان", datetime.now().isoformat()))
    else:
        needed_invites = (gem_count // GEM_PER_INVITE) * MIN_INVITES_FOR_GEM
        cur.execute("SELECT invite_count FROM users WHERE telegram_id=?", (user_id,))
        user_row = cur.fetchone()
        if not user_row or user_row[0] < needed_invites:
            conn.close()
            return None
        
        cur.execute("UPDATE users SET invite_count=invite_count-? WHERE telegram_id=?", (needed_invites, user_id))
        cur.execute("""
            INSERT INTO transactions (user_id, amount, type, description, created)
            VALUES(?,?,?,?,?)
        """, (user_id, 0, "withdraw", f"برداشت جم #{wid} - {gem_count} جم", datetime.now().isoformat()))

    cur.execute("UPDATE withdrawals SET status='approved' WHERE id=?", (wid,))
    conn.commit()
    conn.close()

    if context:
        try:
            if method == "card":
                context.bot.send_message(
                    chat_id=user_id,
                    text=f"""
✅ درخواست برداشت نقدی شما تایید شد.

🆔 شماره درخواست: #{wid}
💰 مبلغ درخواستی: {amount:,} تومان
💳 مبلغ پرداختی: {actual_amount:,} تومان (کارمزد {WITHDRAW_FEE:,} تومان)
📌 روش: کارت به کارت - {card_number}

موجودی شما به‌روزرسانی شد.
"""
                )
            else:
                context.bot.send_message(
                    chat_id=user_id,
                    text=f"""
✅ درخواست برداشت جم شما تایید شد.

🆔 شماره درخواست: #{wid}
🎮 آیدی بازی: {game_id}
🎁 تعداد جم: {gem_count} جم

جم شما به حساب بازی واریز خواهد شد.
"""
                )
        except Exception as e:
            logging.error(f"ارسال پیام تایید برداشت به {user_id} ناموفق: {e}")

    return (user_id, amount, actual_amount, method, card_number, game_id, gem_count)


def reject_withdraw(wid, context=None):
    conn = db()
    cur = conn.cursor()
    cur.execute("SELECT user_id, amount, method, status FROM withdrawals WHERE id=?", (wid,))
    row = cur.fetchone()
    if not row or row[3] != "pending":
        conn.close()
        return None

    user_id, amount, method, status = row
    cur.execute("UPDATE withdrawals SET status='rejected' WHERE id=?", (wid,))
    conn.commit()
    conn.close()

    if context:
        try:
            context.bot.send_message(
                chat_id=user_id,
                text=f"""
❌ درخواست برداشت شما رد شد.

🆔 شماره درخواست: #{wid}
💰 مبلغ: {amount:,} تومان

در صورت نیاز با پشتیبانی تماس بگیرید.
"""
            )
        except Exception as e:
            logging.error(f"ارسال پیام رد برداشت به {user_id} ناموفق: {e}")

    return (user_id, amount, method)


# ============================================================
# BROADCAST MESSAGE
# ============================================================

async def broadcast_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    if not is_admin(user.id):
        await update.message.reply_text("⛔ دسترسی ندارید.")
        return

    if update.message.text:
        text = update.message.text
    elif update.message.caption:
        text = update.message.caption
    else:
        await update.message.reply_text("❌ لطفاً یک پیام متنی ارسال کنید.")
        return

    conn = db()
    cur = conn.cursor()
    cur.execute("SELECT telegram_id FROM users WHERE blocked=0")
    users = cur.fetchall()
    conn.close()

    if not users:
        await update.message.reply_text("❌ هیچ کاربر فعالی در دیتابیس وجود ندارد.")
        context.user_data.pop("broadcast", None)
        return

    sent = 0
    failed = 0
    blocked_bot = 0
    total = len(users)
    
    status_msg = await update.message.reply_text(f"⏳ در حال ارسال به {total} کاربر فعال ...")

    for (uid,) in users:
        try:
            await context.bot.send_message(chat_id=uid, text=text)
            sent += 1
            await asyncio.sleep(0.05)
        except Exception as e:
            failed += 1
            error_msg = str(e).lower()
            if "bot was blocked" in error_msg or "user is deactivated" in error_msg:
                blocked_bot += 1
                conn = db()
                cur2 = conn.cursor()
                cur2.execute("UPDATE users SET blocked=1 WHERE telegram_id=?", (uid,))
                conn.commit()
                conn.close()
                logging.info(f"کاربر {uid} به دلیل بلاک کردن ربات، مسدود شد.")
            else:
                logging.warning(f"ارسال به {uid} ناموفق: {e}")

    context.user_data.pop("broadcast", None)
    
    await status_msg.edit_text(
        f"""
✅ گزارش ارسال همگانی

📤 ارسال موفق: {sent}
❌ ارسال ناموفق: {failed}
🚫 کاربرانی که ربات را بلاک کرده‌اند: {blocked_bot}
━━━━━━━━━━━━━━━━━
📊 جمع کل کاربران فعال: {total}
"""
    )


# ============================================================
# MAIN TEXT MESSAGE HANDLER
# ============================================================

async def handle_text_messages(update: Update, context: ContextTypes.DEFAULT_TYPE):
    logging.info("🔔 handle_text_messages called")
    
    if not update.message:
        logging.info("⚠️ No message received")
        return
    
    user = update.effective_user
    if not user:
        return

    # اولویت ۱: ثبت شماره تلفن
    if context.user_data.get("phone_wait"):
        logging.info(f"➡️ Processing phone registration for {user.id}")
        if update.message.contact or update.message.text:
            await phone_message_handler(update, context)
            return
        else:
            await update.message.reply_text(
                "❌ لطفاً شماره تلفن خود را با استفاده از دکمه‌ی مخصوص ارسال کنید."
            )
            return

    # اولویت ۲: کپچا
    if context.user_data.get("captcha_wait"):
        logging.info(f"➡️ Processing captcha for {user.id}")
        if update.message.text:
            await captcha_handler(update, context)
            return
        else:
            await update.message.reply_text("❌ لطفاً عدد را به صورت متن وارد کنید.")
            return

    if not update.message.text:
        logging.info("⚠️ No text message received (ignoring)")
        return

    logging.info(f"📩 Received text from {user.id}: {update.message.text[:50]}")

    # اولویت ۳: دریافت آیدی بازی (برداشت جم)
    if context.user_data.get("withdraw_step") == "game_id":
        logging.info(f"➡️ Processing game ID for {user.id}")
        await withdraw_game_id_handler(update, context)
        return

    # اولویت ۴: دریافت شماره کارت (برداشت نقدی)
    if context.user_data.get("withdraw_wait") and context.user_data.get("withdraw_method") == "card" and context.user_data.get("withdraw_step") is None:
        logging.info(f"➡️ Processing card number for {user.id}")
        await withdraw_card_handler(update, context)
        return

    # اولویت ۵: دریافت مبلغ (برداشت نقدی)
    if context.user_data.get("withdraw_step") == "amount_card":
        logging.info(f"➡️ Processing withdraw amount for {user.id}")
        await withdraw_amount_card_handler(update, context)
        return

    # اولویت ۶: مدیریت موجودی (ادمین)
    if context.user_data.get("balance_step"):
        logging.info(f"➡️ Processing balance management for {user.id}")
        await balance_message_handler(update, context)
        return

    # اولویت ۷: ارسال همگانی (ادمین)
    if context.user_data.get("broadcast"):
        logging.info(f"➡️ Processing broadcast for {user.id}")
        await broadcast_message(update, context)
        return

    logging.info(f"ℹ️ No active state for {user.id}, ignoring message.")


# ============================================================
# ERROR HANDLER
# ============================================================

async def error_handler(update, context):
    logging.error("BOT ERROR", exc_info=context.error)


# ============================================================
# MAIN
# ============================================================

def main():
    if not TOKEN or TOKEN == "YOUR_BOT_TOKEN_HERE":
        print("❌ توکن ربات را در قسمت CONFIG قرار دهید.")
        return

    if PROXY_URL:
        print(f"🌐 استفاده از پروکسی: {PROXY_URL}")
        request = HTTPXRequest(
            proxy=PROXY_URL,
            connect_timeout=120,
            read_timeout=120,
            write_timeout=120,
            pool_timeout=120
        )
    else:
        request = HTTPXRequest(
            connect_timeout=120,
            read_timeout=120,
            write_timeout=120,
            pool_timeout=120
        )

    app = Application.builder().token(TOKEN).request(request).build()

    # ---- Commands ----
    app.add_handler(CommandHandler("start", start))
    app.add_handler(CommandHandler("admin", admin))
    app.add_handler(CommandHandler("block", block_user))
    app.add_handler(CommandHandler("unblock", unblock_user))
    app.add_handler(CommandHandler("addadmin", add_admin))
    app.add_handler(CommandHandler("removeadmin", remove_admin))
    app.add_handler(CommandHandler("cancel", cancel))

    # ---- Callbacks ----
    app.add_handler(CallbackQueryHandler(check_join_button, pattern="^check_join$"))
    app.add_handler(CallbackQueryHandler(user_buttons, pattern="^(balance|invite|withdraw|transactions|profile|home|cancel_withdraw|support|withdraw_card|withdraw_game)$"))
    app.add_handler(CallbackQueryHandler(admin_buttons, pattern="^(admin_|approve_|reject_|cancel_broadcast|admin_toggle_block_|admin_user_detail_|admin_balance_user_|admin_balance_increase|admin_balance_decrease)"))

    # ---- Message handlers ----
    app.add_handler(MessageHandler(filters.UpdateType.MESSAGES, handle_text_messages))

    app.add_error_handler(error_handler)

    async def startup_check():
        await check_bot_channels(app)

    loop = asyncio.get_event_loop()
    loop.run_until_complete(startup_check())

    print("🤖 ربات اجرا شد...")
    print(f"📢 تعداد کانال‌ها: {len([c for c in CHANNEL_IDS if c != 0])}")
    print(f"💰 پاداش دعوت: {INVITE_REWARD}")
    print(f"💳 حداقل درخواست نقدی: {MIN_WITHDRAW:,} تومان")
    print(f"💳 پرداخت واقعی: {REAL_PAYOUT:,} تومان (کارمزد {WITHDRAW_FEE:,} تومان)")
    print(f"🎮 برداشت جم: هر {MIN_INVITES_FOR_GEM} دعوت = {GEM_PER_INVITE} جم")
    print(f"👤 ادمین: {ADMIN_USERNAME}")
    if PROXY_URL:
        print(f"🌐 پروکسی فعال: {PROXY_URL}")
    else:
        print("🌐 بدون پروکسی")

    app.run_polling(drop_pending_updates=True)


if __name__ == "__main__":
    main()