import logging
import random
import datetime
import sqlite3
import asyncio
import os
import re
import warnings
from collections import defaultdict

# غیرفعال‌سازی هشدارهای غیرضروری PTB مربوط به per_message
from telegram.warnings import PTBUserWarning
warnings.filterwarnings("ignore", category=PTBUserWarning)

from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (
    Application, CommandHandler, CallbackQueryHandler, MessageHandler, 
    filters, ContextTypes, ConversationHandler
)
from telegram.error import BadRequest, TelegramError, RetryAfter

# ---------------- CONFIG & CONSTANTS ----------------
TOKEN = "8787049309:AAEeCGPb512LmHoc2lC2xzuXwAZ4DlcAXJk"  # توکن ربات
ADMIN_ID = 398904388            # آیدی عددی ادمین اصلی
OPERATOR_ID = 8593054646        # آیدی عددی اپراتور تایید واریزی‌ها
LOG_GROUP = -1004419189677      # آیدی کانال/گروه گزارشات (ربات باید ادمین باشد)
DATABASE_DIR = "dataxx2"
DATABASE_FILE = os.path.join(DATABASE_DIR, "Meow2030_Robot2.db")
WITHDRAW_FILE = os.path.join(DATABASE_DIR, "withdrawals2.txt")
LOG_FILE = "bot2.log"

# Async lock & Queue Status
file_lock = asyncio.Lock()
queue_busy = False  # نشان‌دهنده در حال پردازش بودن یک درخواست در گروه

# Anti-Spam Data Structure
user_requests = defaultdict(list)
user_bans = {}

# States for Conversation Handlers
(
    WITHDRAW_AMOUNT, GIFT_CODE_WAITING, SUPPORT_WAITING,
    ADMIN_BC_TEXT, ADMIN_USER_MSG, ADMIN_USER_MSG_TEXT,
    ADMIN_MAKE_GIFT, ADMIN_MANAGE_USER_INPUT, ADMIN_MANAGE_POINT_AMOUNT,
    ADMIN_BLOCK_USER, ADMIN_UNBLOCK_USER,
    USER_CREATE_GIFT_AMOUNT, ADMIN_REPLY_SUPP_INPUT,
    ADMIN_SET_REF_REWARD, ADMIN_ADD_FJ_CHAT,
    ADMIN_TOP_USER, ADMIN_DAILY_PRIZE, ADMIN_NEWS_CHANNEL,
    ADMIN_RESET_HOUR, ADMIN_RESET_MINUTE
) = range(20)

# Logging Setup
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', 
    level=logging.INFO,
    handlers=[
        logging.FileHandler(LOG_FILE, encoding='utf-8'),
        logging.StreamHandler()
    ]
)

# ---------------- SECURITY & HELPER FUNCTIONS ----------------
def escape_html(text: str) -> str:
    if not text:
        return ""
    return str(text).replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")

def sanitize_input(text: str) -> str:
    if not text:
        return ""
    return re.sub(r'[\x00-\x1f\x7f-\x9f]', '', text).strip()

def e(emoji_id: str, fallback: str = "🔸") -> str:
    return f'<tg-emoji emoji-id="{emoji_id}">{fallback}</tg-emoji>'

WELCOME_TEXT = (
    f"╔════════════════════╗\n"
    f"  {e('5845815828364142132')} <b>میوپرانت | پرواز میوپوینت‌ها به سمت تو</b> {e('5929176380460769057')}\n"
    f"╚════════════════════╝\n\n"
    f"{e('5978897683543236228')} به قلمرو میوپرانت خوش اومدی! جایی که با هر کلیک، میوپوینت‌ها به سمتت پرتاب می‌شن.\n"
    f"{e('5816531766382436821')} آماده پروازی؟ از منوی شیک زیر بخش مورد نظرت رو انتخاب کن:"
)

REF_TEXT = (
    f"{e('5845815828364142132')} <b>شبکه پرتاب میوپوینت!</b> {e('5929176380460769057')}\n"
    f"دوستاتو به میوپرانت دعوت کن تا موجی از میوپوینت‌های رایگان به سمت حسابت پرتاب بشه!"
)

SUPPORT_TEXT = (
    f"{e('5883982896326254229')} <b>ارتباط مستقیم با مرکز میوپرانت</b>\n\n"
    f"{e('5911198059676574025')} سوال، نظر یا پیشنهادی داری؟ پیامتم پرتاب کن سمت ما! مستقیم می‌رسه به دست تیم پشتیبانی {e('5845815828364142132')}:"
)

async def delete_safe(context: ContextTypes.DEFAULT_TYPE, chat_id: int, message_id: int):
    try:
        await context.bot.delete_message(chat_id=chat_id, message_id=message_id)
    except Exception:
        pass

# ---------------- DATABASE MANAGEMENT ----------------
def get_db():
    os.makedirs(DATABASE_DIR, exist_ok=True)
    conn = sqlite3.connect(DATABASE_FILE, timeout=20.0)
    conn.row_factory = sqlite3.Row
    return conn

def init_db():
    conn = get_db()
    try:
        cursor = conn.cursor()
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS users (
                user_id INTEGER PRIMARY KEY,
                username TEXT,
                first_name TEXT,
                points INTEGER DEFAULT 0,
                referrals_count INTEGER DEFAULT 0,
                daily_referrals INTEGER DEFAULT 0,
                referred_by INTEGER DEFAULT NULL,
                ref_reward_claimed INTEGER DEFAULT 0,
                last_wheel_claim TEXT DEFAULT NULL,
                is_blocked INTEGER DEFAULT 0
            )
        ''')
        
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS gift_codes (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                code TEXT,
                points INTEGER,
                is_used INTEGER DEFAULT 0,
                created_at TEXT,
                creator_id INTEGER DEFAULT 0
            )
        ''')

        cursor.execute("PRAGMA table_info(gift_codes)")
        columns = [column[1] for column in cursor.fetchall()]
        if 'creator_id' not in columns:
            cursor.execute("ALTER TABLE gift_codes ADD COLUMN creator_id INTEGER DEFAULT 0")

        cursor.execute("PRAGMA table_info(users)")
        user_columns = [column[1] for column in cursor.fetchall()]
        if 'daily_referrals' not in user_columns:
            cursor.execute("ALTER TABLE users ADD COLUMN daily_referrals INTEGER DEFAULT 0")
        
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS force_joins (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT,
                chat_id_or_link TEXT
            )
        ''')

        cursor.execute("PRAGMA table_info(force_joins)")
        fj_columns = [column[1] for column in cursor.fetchall()]
        if 'chat_id_or_link' not in fj_columns:
            cursor.execute("ALTER TABLE force_joins ADD COLUMN chat_id_or_link TEXT")

        cursor.execute('''
            CREATE TABLE IF NOT EXISTS settings (
                key TEXT PRIMARY KEY,
                value TEXT
            )
        ''')
        
        cursor.execute("INSERT OR IGNORE INTO settings (key, value) VALUES ('force_join_status', 'on')")
        cursor.execute("INSERT OR IGNORE INTO settings (key, value) VALUES ('bot_status', 'on')")
        cursor.execute("INSERT OR IGNORE INTO settings (key, value) VALUES ('ref_reward_amount', '50000')")
        cursor.execute("INSERT OR IGNORE INTO settings (key, value) VALUES ('daily_prize_base', '10000')")
        cursor.execute("INSERT OR IGNORE INTO settings (key, value) VALUES ('news_channel_id', '')")
        cursor.execute("INSERT OR IGNORE INTO settings (key, value) VALUES ('daily_reset_time', '00:00')")
        
        conn.commit()
    finally:
        conn.close()

init_db()

# ---------------- LOG CLEANUP TASK ----------------
async def auto_clear_log_task():
    """تسک پاکسازی و خالی کردن فایل bot.log هر یک ساعت یک‌بار"""
    while True:
        await asyncio.sleep(3600)
        try:
            if os.path.exists(LOG_FILE):
                with open(LOG_FILE, "w", encoding="utf-8") as f:
                    f.truncate(0)
                logging.info("فایل لاگ bot.log به صورت خودکار پاک‌سازی گردید.")
        except Exception as err:
            logging.error(f"خطا در پاکسازی فایل لاگ: {err}")

# ---------------- ANTI-SPAM LOGIC ----------------
async def notify_unban_user(app: Application, user_id: int):
    try:
        msg = (
            f"{e('5830144944399981619')} <b>شما از مسدودی آزاد شدید!</b>\n\n"
            f"لطفاً دیگر اسپم نکنید. تکرار مجدد اسپم عواقب بسیار بدی دارد و زمان مسدودی شما سنگین‌تر خواهد شد!"
        )
        await app.bot.send_message(chat_id=user_id, text=msg, parse_mode="HTML")
    except Exception:
        pass

async def unban_timer_task(app: Application, user_id: int, delay_seconds: int):
    await asyncio.sleep(delay_seconds)
    if user_id in user_bans:
        del user_bans[user_id]
        await notify_unban_user(app, user_id)

async def check_anti_spam(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool:
    user = update.effective_user
    if not user:
        return False
    
    user_id = user.id
    if user_id == ADMIN_ID or user_id == OPERATOR_ID:
        return False

    now = datetime.datetime.now()

    if user_id in user_bans:
        ban_info = user_bans[user_id]
        if now < ban_info["ban_until"]:
            if update.callback_query:
                try:
                    await update.callback_query.answer("شما به دلیل اسپم موقتاً مسدود هستید!", show_alert=True)
                except Exception:
                    pass
            return True
        else:
            del user_bans[user_id]

    user_requests[user_id].append(now)
    user_requests[user_id] = [t for t in user_requests[user_id] if (now - t).total_seconds() <= 3]

    if len(user_requests[user_id]) > 3:
        user_requests[user_id].clear()
        
        prev_duration = context.user_data.get("spam_ban_duration", 0)
        new_duration = 1 if prev_duration == 0 else prev_duration * 2
        context.user_data["spam_ban_duration"] = new_duration

        if new_duration >= 720:
            conn = get_db()
            try:
                conn.cursor().execute("UPDATE users SET is_blocked = 1 WHERE user_id = ?", (user_id,))
                conn.commit()
            finally:
                conn.close()

            try:
                await context.bot.send_message(
                    chat_id=user_id,
                    text=f"{e('5873075766748520540')} به دلیل اسپم بیش از حد و بی‌توجهی به اخطارها، حساب شما به طور کامل از ربات مسدود شد.",
                    parse_mode="HTML"
                )
            except Exception:
                pass

            try:
                admin_msg = (
                    f"{e('5873075766748520540')} <b>هشدار مسدودی دائمی اسپم!</b>\n\n"
                    f"کاربر با مشخصات زیر به دلیل اسپم بیش از حد مسدود شد:\n"
                    f"👤 نام: <b>{escape_html(user.first_name)}</b>\n"
                    f"🏷 یوزرنیم: @{user.username if user.username else 'ندارد'}\n"
                    f"🆔 آیدی عددی: <code>{user_id}</code>"
                )
                await context.bot.send_message(chat_id=ADMIN_ID, text=admin_msg, parse_mode="HTML")
            except Exception:
                pass

            return True

        ban_until = now + datetime.timedelta(minutes=new_duration)
        delay_seconds = new_duration * 60
        
        task = asyncio.create_task(unban_timer_task(context.application, user_id, delay_seconds))
        user_bans[user_id] = {
            "ban_until": ban_until,
            "duration_minutes": new_duration,
            "task": task
        }

        ban_msg = (
            f"{e('5873075766748520540')} <b>شما به دلیل اسپم به مدت {new_duration} دقیقه مسدود شدید!</b>\n"
            f"در این مدت هیچ امکانی برای شما فعال نیست. پس از پایان زمان، پیام رفع مسدودی ارسال خواهد شد."
        )

        if update.callback_query:
            try:
                await update.callback_query.answer(f"به دلیل اسپم به مدت {new_duration} دقیقه بلاک شدید!", show_alert=True)
            except Exception:
                pass
            try:
                await update.callback_query.message.reply_text(ban_msg, parse_mode="HTML")
            except Exception:
                pass
        elif update.message:
            try:
                await update.message.reply_text(ban_msg, parse_mode="HTML")
            except Exception:
                pass

        return True

    return False

# ---------------- BOT OFF CHECKER ----------------
async def is_bot_off_for_user(update: Update) -> bool:
    user = update.effective_user
    if not user or user.id == ADMIN_ID:
        return False

    bot_status = get_setting('bot_status', 'on')
    if bot_status == 'off':
        msg_text = f"{e('5873075766748520540')} <b>ربات خاموش است.</b>\nدر حال حاضر ربات توسط مدیریت غیرفعال شده است. لطفاً بعداً مراجعه کنید."
        if update.callback_query:
            try:
                await update.callback_query.answer("ربات خاموش است!", show_alert=True)
            except Exception:
                pass
            try:
                await update.callback_query.edit_message_text(msg_text, parse_mode="HTML")
            except Exception:
                pass
        elif update.message:
            try:
                await update.message.reply_text(msg_text, parse_mode="HTML")
            except Exception:
                pass
        return True
    return False

# ---------------- WITHDRAW FILE QUEUE HELPERS ----------------
async def is_user_in_withdraw_queue(user_id: int) -> bool:
    async with file_lock:
        if not os.path.exists(WITHDRAW_FILE):
            return False
        with open(WITHDRAW_FILE, "r", encoding="utf-8") as f:
            lines = [line.strip() for line in f.readlines() if line.strip()]
        for line in lines:
            parts = line.split()
            if len(parts) == 2 and parts[1].isdigit():
                if int(parts[1]) == user_id:
                    return True
        return False

async def add_withdrawal_to_file(amount: int, user_id: int):
    async with file_lock:
        lines = []
        if os.path.exists(WITHDRAW_FILE):
            with open(WITHDRAW_FILE, "r", encoding="utf-8") as f:
                lines = [line.strip() for line in f.readlines() if line.strip() and line.strip() != "درحال واریز" and line.strip() != "هیچ عملیاتی در حال انجام نیست"]
        lines.append(f"{amount} {user_id}")
        with open(WITHDRAW_FILE, "w", encoding="utf-8") as f:
            f.write("\n".join(lines) + "\n")

async def get_next_withdrawal():
    async with file_lock:
        if not os.path.exists(WITHDRAW_FILE):
            return None
        with open(WITHDRAW_FILE, "r", encoding="utf-8") as f:
            lines = [line.strip() for line in f.readlines() if line.strip()]
        for line in lines:
            parts = line.split()
            if len(parts) == 2 and parts[0].isdigit() and parts[1].isdigit():
                return int(parts[0]), int(parts[1])
        return None

async def remove_withdrawal_from_file(target_user_id: int) -> int:
    removed_amount = 0
    async with file_lock:
        if not os.path.exists(WITHDRAW_FILE):
            return 0
        with open(WITHDRAW_FILE, "r", encoding="utf-8") as f:
            lines = [line.strip() for line in f.readlines() if line.strip()]
        
        new_lines = []
        found = False
        for line in lines:
            parts = line.split()
            if len(parts) == 2 and parts[0].isdigit() and parts[1].isdigit():
                amt, uid = int(parts[0]), int(parts[1])
                if not found and uid == target_user_id:
                    removed_amount = amt
                    found = True
                else:
                    new_lines.append(f"{amt} {uid}")
            else:
                continue
        
        with open(WITHDRAW_FILE, "w", encoding="utf-8") as f:
            if new_lines:
                f.write("\n".join(new_lines) + "\n")
            else:
                f.write("هیچ عملیاتی در حال انجام نیست\n")
                
    return removed_amount

async def update_withdraw_file_status():
    async with file_lock:
        if not os.path.exists(WITHDRAW_FILE):
            with open(WITHDRAW_FILE, "w", encoding="utf-8") as f:
                f.write("هیچ عملیاتی در حال انجام نیست\n")
            return

        with open(WITHDRAW_FILE, "r", encoding="utf-8") as f:
            lines = [line.strip() for line in f.readlines() if line.strip()]

        has_active_withdraw = any(
            len(line.split()) == 2 and line.split()[0].isdigit() and line.split()[1].isdigit()
            for line in lines
        )

        if queue_busy or has_active_withdraw:
            valid_lines = [l for l in lines if l not in ["درحال واریز", "هیچ عملیاتی در حال انجام نیست"]]
            if "درحال واریز" not in valid_lines:
                valid_lines.insert(0, "درحال واریز")
            with open(WITHDRAW_FILE, "w", encoding="utf-8") as f:
                f.write("\n".join(valid_lines) + "\n")
        else:
            with open(WITHDRAW_FILE, "w", encoding="utf-8") as f:
                f.write("هیچ عملیاتی در حال انجام نیست\n")

async def check_withdrawals_status_task(app: Application):
    while True:
        try:
            await update_withdraw_file_status()
            item = await get_next_withdrawal()
            if item:
                await process_next_withdraw_queue(app, force_send=True)
        except Exception as e_err:
            logging.error(f"Error in status task: {e_err}")
        await asyncio.sleep(300)

async def process_next_withdraw_queue(app: Application, force_send: bool = False):
    global queue_busy
    if queue_busy and not force_send:
        return

    item = await get_next_withdrawal()
    if item:
        queue_busy = True
        await update_withdraw_file_status()
        amount, user_id = item
        msg = f"{amount} {user_id}"
        try:
            await app.bot.send_message(chat_id=LOG_GROUP, text=msg)
        except Exception as e_err:
            logging.error(f"Error sending withdrawal queue msg to group: {e_err}")
            queue_busy = False
            await update_withdraw_file_status()
    else:
        queue_busy = False
        await update_withdraw_file_status()

# ---------------- DB HELPER FUNCTIONS ----------------
def get_setting(key: str, default: str = "") -> str:
    conn = get_db()
    try:
        res = conn.cursor().execute("SELECT value FROM settings WHERE key = ?", (key,)).fetchone()
        return res['value'] if res else default
    finally:
        conn.close()

def set_setting(key: str, value: str):
    conn = get_db()
    try:
        conn.cursor().execute("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)", (key, str(value)))
        conn.commit()
    finally:
        conn.close()

def get_user(user_id: int):
    conn = get_db()
    try:
        return conn.cursor().execute("SELECT * FROM users WHERE user_id = ?", (user_id,)).fetchone()
    finally:
        conn.close()

def ensure_user_exists(user_id: int, username: str = "", first_name: str = "کاربر"):
    safe_username = escape_html(sanitize_input(username or ""))
    safe_first_name = escape_html(sanitize_input(first_name or "کاربر"))
    conn = get_db()
    try:
        cursor = conn.cursor()
        cursor.execute(
            "INSERT OR IGNORE INTO users (user_id, username, first_name) VALUES (?, ?, ?)",
            (user_id, safe_username, safe_first_name)
        )
        conn.commit()
    finally:
        conn.close()

def register_user(user_id: int, username: str, first_name: str, referred_by: int = None):
    safe_username = escape_html(sanitize_input(username or ""))
    safe_first_name = escape_html(sanitize_input(first_name or "کاربر"))
    
    conn = get_db()
    is_new = False
    try:
        cursor = conn.cursor()
        user = cursor.execute("SELECT * FROM users WHERE user_id = ?", (user_id,)).fetchone()
        if not user:
            is_new = True
            ref_id = referred_by if referred_by and referred_by != user_id else None
            cursor.execute(
                "INSERT INTO users (user_id, username, first_name, referred_by) VALUES (?, ?, ?, ?)",
                (user_id, safe_username, safe_first_name, ref_id)
            )
        else:
            cursor.execute("UPDATE users SET username = ?, first_name = ? WHERE user_id = ?", (safe_username, safe_first_name, user_id))
        conn.commit()
        return is_new
    finally:
        conn.close()

def spin_wheel_logic() -> int:
    rand = random.random() * 100
    if rand < 5.0:
        return random.randint(500, 5000)
    elif rand < 70.0:
        return random.randint(5000, 25000)
    elif rand < 99.0:
        return random.randint(25000, 50000)
    else:
        return 100000

# ---------------- FORCE JOIN CHECKER ----------------
async def check_user_joined_all(bot, user_id: int) -> tuple[bool, InlineKeyboardMarkup]:
    status = get_setting('force_join_status', 'on')
    if status == 'off':
        return True, None

    conn = get_db()
    try:
        channels = conn.cursor().execute("SELECT * FROM force_joins").fetchall()
    finally:
        conn.close()

    if not channels:
        return True, None

    not_joined_buttons = []
    all_joined = True

    for item in channels:
        target = str(item['chat_id_or_link']).strip()
        display_title = item['title'] or "کانال جوین اجباری"
        
        if (target.startswith("-") and target[1:].isdigit()) or target.isdigit():
            chat_target = int(target)
        else:
            chat_target = target if target.startswith("@") else f"@{target}"

        # به روزرسانی نام واقعی کانال در صورت امکان
        try:
            chat_obj = await bot.get_chat(chat_id=chat_target)
            if chat_obj and chat_obj.title:
                display_title = chat_obj.title
                conn_up = get_db()
                try:
                    conn_up.cursor().execute("UPDATE force_joins SET title = ? WHERE id = ?", (display_title, item['id']))
                    conn_up.commit()
                finally:
                    conn_up.close()
        except Exception:
            pass

        url = None
        
        # ۱. تلاش برای دریافت / ساخت لینک
        if isinstance(chat_target, str) and chat_target.startswith("@"):
            url = f"https://t.me/{chat_target[1:]}"
        elif isinstance(chat_target, str) and chat_target.startswith("http"):
            url = chat_target
        else:
            try:
                invite_link_obj = await bot.create_chat_invite_link(chat_id=chat_target)
                url = invite_link_obj.invite_link
            except Exception as create_err:
                try:
                    url = await bot.export_chat_invite_link(chat_id=chat_target)
                except Exception as export_err:
                    err_msg = (
                        f"⚠️ <b>خطا در سیستم جوین اجباری!</b>\n\n"
                        f"ربات دسترسی ساخت/دریافت لینک دعوت برای کانال/گروه <b>{escape_html(display_title)}</b> (شناسه: <code>{chat_target}</code>) را ندارد.\n"
                        f"لطفاً ربات را در این کانال ادمین کرده و دسترسی Create Invite Link را به آن بدهید.\n\n"
                        f"<i>توضیحات خطا: {escape_html(str(export_err))}</i>"
                    )
                    try:
                        await bot.send_message(chat_id=ADMIN_ID, text=err_msg, parse_mode="HTML")
                    except Exception:
                        pass
                    continue

        # ۲. بررسی عضویت کاربر در کانال/گروه مربوطه
        try:
            member = None
            for attempt in range(2):
                try:
                    member = await bot.get_chat_member(chat_id=chat_target, user_id=user_id)
                    break
                except RetryAfter as r_err:
                    await asyncio.sleep(r_err.retry_after + 1)
                except Exception:
                    break

            if member and member.status in ["left", "kicked"]:
                all_joined = False
                not_joined_buttons.append([InlineKeyboardButton(f"{display_title}", url=url, icon_custom_emoji_id="5816404884458577332", style="primary")])
        
        except Exception:
            continue

    if not all_joined:
        not_joined_buttons.append([InlineKeyboardButton("بررسی و تایید عضویت", callback_data="check_join_btn", icon_custom_emoji_id="5830144944399981619", style="success")])
        return False, InlineKeyboardMarkup(not_joined_buttons)

    return True, None

async def process_referral_reward(bot, user_id: int):
    conn = get_db()
    try:
        cursor = conn.cursor()
        user = cursor.execute("SELECT * FROM users WHERE user_id = ?", (user_id,)).fetchone()
        if user and user['referred_by'] and user['ref_reward_claimed'] == 0:
            ref_id = user['referred_by']
            ref_user = cursor.execute("SELECT * FROM users WHERE user_id = ?", (ref_id,)).fetchone()
            if ref_user and ref_user['is_blocked'] == 0:
                reward_amount = int(get_setting('ref_reward_amount', '50000'))
                cursor.execute(
                    "UPDATE users SET points = points + ?, referrals_count = referrals_count + 1, daily_referrals = daily_referrals + 1 WHERE user_id = ?",
                    (reward_amount, ref_id)
                )
                cursor.execute("UPDATE users SET ref_reward_claimed = 1 WHERE user_id = ? AND ref_reward_claimed = 0", (user_id,))
                conn.commit()

                try:
                    user_name = user['first_name'] or "کاربر جدید"
                    msg = (
                        f"{e('5818866927216369505')} <b>پرتاب موفقیت‌آمیز میوپوینت!</b> {e('5845815828364142132')}\n\n"
                        f"{e('5859432880442187580')} کاربر <b>{user_name}</b> عضویتش رو تأیید کرد.\n"
                        f"{e('5825623013852192219')} تعداد <b>{reward_amount:,}</b> میوپوینت با موفقیت به حسابت پرتاب شد! {e('5978897683543236228')}"
                    )
                    await bot.send_message(chat_id=ref_id, text=msg, parse_mode="HTML")
                except Exception:
                    pass
    finally:
        conn.close()

# ---------------- KEYBOARDS & BUILDERS ----------------
def top_meows_keyboard():
    return InlineKeyboardMarkup([
        [InlineKeyboardButton("میویی‌های پولدار", callback_data="top_rich", icon_custom_emoji_id="5823592920250327036", style="success")],
        [InlineKeyboardButton("برترین‌های دعوت", callback_data="top_ref_all", icon_custom_emoji_id="5859432880442187580", style="primary")],
        [InlineKeyboardButton("دعوت‌های امروز", callback_data="top_ref_daily", icon_custom_emoji_id="5906896396526560494", style="primary")],
        [InlineKeyboardButton("بازگشت به منوی اصلی", callback_data="main_menu", icon_custom_emoji_id="5845815828364142132")]
    ])

def leaderboard_text(title: str, rows, value_key: str, value_label: str) -> str:
    text = f"{e('6014651259057873388')} <b>{title}</b>\n\n"
    if not rows:
        return text + f"{e('5829923384217050622')} هنوز کاربری برای نمایش وجود ندارد."
    for index, row in enumerate(rows, 1):
        name = escape_html(row['first_name'] or "کاربر")
        text += f"<b>{index}.</b> {name}  <b>{row[value_key]:,}</b> {value_label}\n"
    return text

def parse_wheel_claim(value):
    if not value:
        return None
    try:
        return datetime.datetime.fromisoformat(str(value))
    except (TypeError, ValueError):
        try:
            return datetime.datetime.combine(datetime.date.fromisoformat(str(value)), datetime.time())
        except (TypeError, ValueError):
            return None

def wheel_remaining_text(last_claim, now=None) -> str:
    now = now or datetime.datetime.now()
    claim_at = parse_wheel_claim(last_claim)
    next_claim_at = (claim_at + datetime.timedelta(seconds=86400)) if claim_at else now
    total_minutes = max(1, int(max(0, (next_claim_at - now).total_seconds()) // 60))
    hours, minutes = divmod(total_minutes, 60)
    return f"{e('5906896396526560494')} {hours} ساعت و {minutes} دقیقه باقی مانده تا چرخش بعدی"

def get_leaderboard(kind: str):
    queries = {
        "rich": ("points", "points > 0"),
        "ref_all": ("referrals_count", "referrals_count > 0"),
        "ref_daily": ("daily_referrals", "daily_referrals > 0")
    }
    order_column, condition = queries[kind]
    conn = get_db()
    try:
        return conn.cursor().execute(
            f"SELECT user_id, username, first_name, {order_column} FROM users WHERE {condition} ORDER BY {order_column} DESC, user_id ASC LIMIT 10"
        ).fetchall()
    finally:
        conn.close()

def main_keyboard(user_id: int):
    buttons = [
        [InlineKeyboardButton("گردونه میویی", callback_data="wheel", icon_custom_emoji_id="5978897683543236228", style="success")],
        [
            InlineKeyboardButton("حساب من", callback_data="profile", icon_custom_emoji_id="5830338333892418460", style="primary"), 
            InlineKeyboardButton("زیرمجموعه‌گیری", callback_data="referral", icon_custom_emoji_id="5859432880442187580", style="primary")
        ],
        [
            InlineKeyboardButton("برداشت میوپوینت", callback_data="withdraw", icon_custom_emoji_id="6050918177653662060", style="success"), 
            InlineKeyboardButton("کد هدیه", callback_data="gift_code", icon_custom_emoji_id="5929398662198206659", style="success")
        ],
        [InlineKeyboardButton("ساخت کد هدیه اختصاصی", callback_data="user_create_gift", icon_custom_emoji_id="5927029738626359516", style="primary")],
        [InlineKeyboardButton("برترین میویی‌ها", callback_data="top_meows", icon_custom_emoji_id="6014651259057873388", style="success")],
        [InlineKeyboardButton("پشتیبانی و ارتباط", callback_data="support", icon_custom_emoji_id="5883982896326254229")]
    ]
    if user_id == ADMIN_ID:
        buttons.append([InlineKeyboardButton("پنل مدیریت", callback_data="admin_panel", icon_custom_emoji_id="6014651259057873388", style="danger")])
    return InlineKeyboardMarkup(buttons)

def cancel_keyboard():
    return InlineKeyboardMarkup([
        [InlineKeyboardButton("لغو عملیات و بازگشت", callback_data="cancel_action", icon_custom_emoji_id="5819154526816444042", style="danger")]
    ])

def admin_keyboard():
    status = get_setting('force_join_status', 'on')
    fj_status_text = "جوین اجباری: فعال" if status == 'on' else "جوین اجباری: غیرفعال"
    fj_icon = "5830144944399981619" if status == 'on' else "5819154526816444042"
    fj_style = "success" if status == 'on' else "danger"

    bot_st = get_setting('bot_status', 'on')
    bot_st_text = "خاموش کردن ربات" if bot_st == 'on' else "روشن کردن ربات"
    bot_st_icon = "5873075766748520540" if bot_st == 'on' else "5830144944399981619"
    bot_st_style = "danger" if bot_st == 'on' else "success"

    return InlineKeyboardMarkup([
        [
            InlineKeyboardButton(bot_st_text, callback_data="admin_toggle_bot_status", icon_custom_emoji_id=bot_st_icon, style=bot_st_style),
            InlineKeyboardButton(fj_status_text, callback_data="admin_toggle_fj", icon_custom_emoji_id=fj_icon, style=fj_style)
        ],
        [InlineKeyboardButton("مدیریت کانال‌های جوین اجباری", callback_data="admin_manage_fj_channels", icon_custom_emoji_id="5816404884458577332", style="primary")],
        [InlineKeyboardButton("آمار گیری", callback_data="admin_stats", icon_custom_emoji_id="6044084382174552276", style="primary")],
        [InlineKeyboardButton("مدیریت برترین‌ها", callback_data="admin_top_user", icon_custom_emoji_id="6044084382174552276", style="primary")],
        [InlineKeyboardButton("تنظیم جایزه روزانه", callback_data="admin_daily_prize", icon_custom_emoji_id="5929398662198206659", style="success")],
        [InlineKeyboardButton("تنظیم کانال خبرها", callback_data="admin_news_channel", icon_custom_emoji_id="5883982896326254229", style="primary")],
        [InlineKeyboardButton("تنظیم ساعت ریست", callback_data="admin_reset_time", icon_custom_emoji_id="5906896396526560494", style="primary")],
        [
            InlineKeyboardButton("پیام همگانی", callback_data="admin_bc", icon_custom_emoji_id="5883982896326254229", style="primary"), 
            InlineKeyboardButton("فوروارد همگانی", callback_data="admin_fwd", icon_custom_emoji_id="5823664135103061930", style="primary")
        ],
        [
            InlineKeyboardButton("مدیریت کاربر", callback_data="admin_manage_user", icon_custom_emoji_id="5859432880442187580", style="primary"), 
            InlineKeyboardButton("ساخت کد هدیه", callback_data="admin_mk_gift", icon_custom_emoji_id="5929398662198206659", style="success")
        ],
        [
            InlineKeyboardButton("کدهای کاربران", callback_data="admin_manage_user_gifts", icon_custom_emoji_id="5765170391383286478"), 
            InlineKeyboardButton("کدهای ادمین", callback_data="admin_manage_admin_gifts", icon_custom_emoji_id="6014651259057873388")
        ],
        [InlineKeyboardButton("تنظیم پوینت دعوت", callback_data="admin_set_ref_reward", icon_custom_emoji_id="5825623013852192219", style="primary")],
        [
            InlineKeyboardButton("مسدود کردن کاربر", callback_data="admin_block", icon_custom_emoji_id="5873075766748520540", style="danger"), 
            InlineKeyboardButton("رفع مسدودی کاربر", callback_data="admin_unblock", icon_custom_emoji_id="5830144944399981619", style="success")
        ],
        [InlineKeyboardButton("ارسال پیام مستقیم", callback_data="admin_direct_msg", icon_custom_emoji_id="5911198059676574025", style="primary")],
        [InlineKeyboardButton("بازگشت به منوی اصلی", callback_data="main_menu", icon_custom_emoji_id="5823664135103061930")]
    ])

def user_gift_menu_keyboard():
    return InlineKeyboardMarkup([
        [InlineKeyboardButton("ساخت کد هدیه جدید", callback_data="user_start_create_gift", icon_custom_emoji_id="5819032824623144971", style="success")],
        [InlineKeyboardButton("کدهای هدیه من", callback_data="user_my_gifts", icon_custom_emoji_id="5929398662198206659", style="primary")],
        [InlineKeyboardButton("بازگشت به منوی اصلی", callback_data="main_menu", icon_custom_emoji_id="5823664135103061930")]
    ])

# ---------------- GENERAL CANCEL HANDLER BUTTON ----------------
async def cancel_action_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await check_anti_spam(update, context): return ConversationHandler.END
    if await is_bot_off_for_user(update): return ConversationHandler.END

    query = update.callback_query
    await query.answer("عملیات با موفقیت لغو شد.")
    context.user_data.clear()
    user_id = query.from_user.id
    msg_text = f"{e('5978897683543236228')} عملیات لغو شد. برگشتیم به منوی اصلی میوپرانت {e('5845815828364142132')}"
    try:
        await query.edit_message_text(
            msg_text,
            parse_mode="HTML",
            reply_markup=main_keyboard(user_id)
        )
    except BadRequest:
        await query.message.reply_text(
            msg_text,
            parse_mode="HTML",
            reply_markup=main_keyboard(user_id)
        )
    return ConversationHandler.END

# ---------------- START HANDLER ----------------
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await check_anti_spam(update, context): return ConversationHandler.END
    if await is_bot_off_for_user(update): return ConversationHandler.END

    context.user_data.clear()
    user = update.effective_user
    args = context.args
    referred_by = int(args[0]) if args and args[0].isdigit() else None

    is_new = register_user(user.id, user.username, user.first_name, referred_by)
    db_user = get_user(user.id)
    
    if db_user and db_user['is_blocked'] == 1:
        await context.bot.send_message(chat_id=user.id, text=f"{e('5873075766748520540')} متأسفانه دسترسی حساب شما به میوپرانت توسط مدیریت محدود شده است.", parse_mode="HTML")
        return ConversationHandler.END

    if is_new and db_user['referred_by']:
        ref_id = db_user['referred_by']
        try:
            status = get_setting('force_join_status', 'on')
            if status == 'on':
                await context.bot.send_message(
                    chat_id=ref_id,
                    text=f"{e('5883982896326254229')} <b>یک هم‌مسیر جدید با لینک تو وارد میوپرانت شد!</b>\n\nبه‌محض تأیید عضویت در کانال‌ها، میوپوینت‌های جایزه‌ات مستقیم سمتت پرتاب می‌شن {e('5845815828364142132')}",
                    parse_mode="HTML"
                )
        except Exception:
            pass

    is_joined, fj_keyboard = await check_user_joined_all(context.bot, user.id)
    if not is_joined:
        await context.bot.send_message(
            chat_id=user.id,
            text=f"╔════════════════════╗\n  {e('5767342218905919987')} <b>عضویت در کانال‌های میوپرانت</b> {e('5897548735214263769')}\n╚════════════════════╝\n\n{e('5978897683543236228')} برای آزاد شدن پرتاب میوپوینت‌ها و استفاده از امکانات ربات، لطفاً در کانال‌های زیر عضو شو و دکمه بررسی رو بزن:",
            reply_markup=fj_keyboard,
            parse_mode="HTML"
        )
        return ConversationHandler.END

    await process_referral_reward(context.bot, user.id)
    await context.bot.send_message(chat_id=user.id, text=WELCOME_TEXT, reply_markup=main_keyboard(user.id), parse_mode="HTML")
    return ConversationHandler.END

# ---------------- CALLBACK HANDLERS ----------------
async def button_click(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await check_anti_spam(update, context): return
    if await is_bot_off_for_user(update): return

    query = update.callback_query
    await query.answer()
    user_id = query.from_user.id

    ensure_user_exists(user_id, query.from_user.username, query.from_user.first_name)
    db_user = get_user(user_id)

    if not db_user or db_user['is_blocked'] == 1:
        try:
            await query.edit_message_text(f"{e('5873075766748520540')} متأسفانه دسترسی حساب شما به میوپرانت توسط مدیریت محدود شده است.", parse_mode="HTML")
        except BadRequest:
            pass
        return

    data = query.data

    if data != "admin_panel" and not data.startswith("admin_"):
        is_joined, fj_keyboard = await check_user_joined_all(context.bot, user_id)
        if not is_joined:
            try:
                await query.edit_message_text(f"{e('5897548735214263769')} هنوز عضویتت در همه کانال‌ها کامل نشده! بررسی کن و دوباره دکمه رو بزن.", reply_markup=fj_keyboard, parse_mode="HTML")
            except BadRequest:
                pass
            return
        await process_referral_reward(context.bot, user_id)

    if data == "check_join_btn":
        is_joined, fj_keyboard = await check_user_joined_all(context.bot, user_id)
        if is_joined:
            await process_referral_reward(context.bot, user_id)
            try:
                await query.edit_message_text(f"{e('5818866927216369505')} عضویتت تایید شد! به منوی اصلی میوپرانت خوش اومدی {e('5845815828364142132')}", reply_markup=main_keyboard(user_id), parse_mode="HTML")
            except BadRequest:
                pass
        else:
            try:
                await query.edit_message_text(f"{e('5897548735214263769')} هنوز عضویتت در همه کانال‌ها کامل نشده! بررسی کن و دوباره دکمه رو بزن.", reply_markup=fj_keyboard, parse_mode="HTML")
            except BadRequest:
                pass

    elif data == "main_menu":
        try:
            await query.edit_message_text(f"{e('5978897683543236228')} <b>منوی اصلی میوپرانت:</b> {e('5845815828364142132')}", parse_mode="HTML", reply_markup=main_keyboard(user_id))
        except BadRequest:
            pass

    elif data == "profile":
        latest_user = get_user(user_id)
        conn = get_db()
        try:
            active_gifts_count = conn.cursor().execute(
                "SELECT COUNT(*) FROM gift_codes WHERE creator_id = ? AND is_used = 0", (user_id,)
            ).fetchone()[0]
        finally:
            conn.close()

        profile_text = (
            f"╔════════════════════╗\n"
            f"  {e('5830338333892418460')} <b>پروفایل شما در میوپرانت</b> {e('5845815828364142132')}\n"
            f"╚════════════════════╝\n\n"
            f"🆔 آیدی: <code>{latest_user['user_id']}</code>\n"
            f"👤 نام: {latest_user['first_name']}\n"
            f"🏷 نام‌کاربری: @{latest_user['username'] if latest_user['username'] else 'ندارد'}\n"
            f"{e('5825623013852192219')} موجودی ذخیره‌شده: <b>{latest_user['points']:,}</b> میوپوینت\n"
            f"{e('5859432880442187580')} تیم پرتاب شما (زیرمجموعه): <b>{latest_user['referrals_count']}</b> نفر\n"
            f"{e('5906896396526560494')} دعوت‌های امروز شما: <b>{latest_user['daily_referrals']}</b> نفر\n"
            f"{e('5929398662198206659')} کدهای هدیه فعال: <b>{active_gifts_count}</b> عدد\n\n"
            f"{e('6046421205160829795')} دوستات رو بیار تا میوپوینت‌های بیشتری سمتت پرتاب بشن!"
        )
        try:
            await query.edit_message_text(profile_text, parse_mode="HTML", reply_markup=main_keyboard(user_id))
        except BadRequest:
            pass

    elif data == "top_meows":
        try:
            await query.edit_message_text(
                f"{e('6014651259057873388')} <b>برترین میویی‌ها</b>\n\nیکی از فهرست‌های زیر را انتخاب کن:",
                parse_mode="HTML", reply_markup=top_meows_keyboard()
            )
        except BadRequest:
            pass

    elif data in ("top_rich", "top_ref_all", "top_ref_daily"):
        leaderboard_config = {
            "top_rich": ("rich", "میویی‌های پولدار", "موجودی"),
            "top_ref_all": ("ref_all", "برترین‌های دعوت", "کل دعوت موفق"),
            "top_ref_daily": ("ref_daily", "دعوت‌های امروز", "دعوت امروز")
        }
        kind, title, value_label = leaderboard_config[data]
        value_key = {"rich": "points", "ref_all": "referrals_count", "ref_daily": "daily_referrals"}[kind]
        try:
            await query.edit_message_text(
                leaderboard_text(title, get_leaderboard(kind), value_key, value_label),
                parse_mode="HTML", reply_markup=top_meows_keyboard()
            )
        except BadRequest:
            pass

    elif data == "referral":
        bot_info = await context.bot.get_me()
        ref_link = f"https://t.me/{bot_info.username}?start={user_id}"
        reward_amount = int(get_setting('ref_reward_amount', '50000'))

        msg_text = (
            f"{REF_TEXT}\n\n"
            f"{e('5819151717907832367')} <b>لینک پرتاب اختصاصی شما:</b>\n"
            f"<code>{ref_link}</code>\n\n"
            f"{e('5819151717907832367')} جایزه هر پرتاب (دعوت موفق): <b>{reward_amount:,}</b> میوپوینت رایگان"
        )
        try:
            await query.edit_message_text(msg_text, parse_mode="HTML", reply_markup=main_keyboard(user_id))
        except BadRequest:
            pass

    elif data == "wheel":
        now = datetime.datetime.now()
        last_claim = parse_wheel_claim(db_user['last_wheel_claim'])
        if last_claim and now - last_claim < datetime.timedelta(seconds=86400):
            try:
                await query.edit_message_text(f"{e('5897548735214263769')} گردونه امروزت رو چرخوندی!\n{wheel_remaining_text(db_user['last_wheel_claim'], now)}", parse_mode="HTML", reply_markup=main_keyboard(user_id))
            except BadRequest:
                pass
            return
        
        won_points = spin_wheel_logic()
        claim_timestamp = now.isoformat(timespec="seconds")
        cutoff_timestamp = (now - datetime.timedelta(seconds=86400)).isoformat(timespec="seconds")
        conn = get_db()
        try:
            cursor = conn.cursor()
            cursor.execute(
                "UPDATE users SET points = points + ?, last_wheel_claim = ? WHERE user_id = ? AND (last_wheel_claim IS NULL OR last_wheel_claim < ?)",
                (won_points, claim_timestamp, user_id, cutoff_timestamp)
            )
            if cursor.rowcount == 0:
                try:
                    await query.edit_message_text(f"{e('5897548735214263769')} گردونه امروزت رو چرخوندی!\n{wheel_remaining_text(db_user['last_wheel_claim'], now)}", parse_mode="HTML", reply_markup=main_keyboard(user_id))
                except BadRequest:
                    pass
                return
            conn.commit()
        finally:
            conn.close()

        try:
            await query.edit_message_text(
                f"{e('5818866927216369505')} <b>پرتاب شانس موفقیت‌آمیز بود!</b> {e('5978897683543236228')}\n\n"
                f"گردونه چرخید و <b>{won_points:,}</b> میوپوینت مستقیم به حساب تو پرتاب شد! {e('5825623013852192219')}",
                parse_mode="HTML",
                reply_markup=main_keyboard(user_id)
            )
        except BadRequest:
            pass

    elif data == "user_create_gift":
        try:
            await query.edit_message_text(
                f"{e('5929398662198206659')} <b>مرکز ساخت کد هدیه میوپرانت:</b>\n\n"
                f"با موجودی میوپوینتت کد هدیه بساز و برای دوستات بپرون! {e('5845815828364142132')}",
                parse_mode="HTML",
                reply_markup=user_gift_menu_keyboard()
            )
        except BadRequest:
            pass

    elif data == "user_my_gifts":
        conn = get_db()
        try:
            gifts = conn.cursor().execute("SELECT * FROM gift_codes WHERE creator_id = ? AND is_used = 0 ORDER BY id DESC", (user_id,)).fetchall()
        finally:
            conn.close()

        if not gifts:
            try:
                await query.edit_message_text(f"{e('5897548735214263769')} در حال حاضر هیچ کد هدیه فعالی نداری!", parse_mode="HTML", reply_markup=user_gift_menu_keyboard())
            except BadRequest:
                pass
            return

        text = f"{e('5911198059676574025')} <b>کدهای هدیه آماده‌ی پرتاب شما:</b>\n\n"
        for g in gifts:
            text += f"🎫 کد: <code>{g['code']}</code> | {e('5825623013852192219')} مبلغ: <b>{g['points']:,}</b> میوپوینت\n"

        try:
            await query.edit_message_text(text, parse_mode="HTML", reply_markup=user_gift_menu_keyboard())
        except BadRequest:
            pass

# ---------------- USER CREATE GIFT CONVERSATION ----------------
async def user_start_create_gift(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await check_anti_spam(update, context): return ConversationHandler.END
    if await is_bot_off_for_user(update): return ConversationHandler.END

    query = update.callback_query
    await query.answer()
    user_id = query.from_user.id
    ensure_user_exists(user_id, query.from_user.username, query.from_user.first_name)
    
    conn = get_db()
    try:
        active_count = conn.cursor().execute(
            "SELECT COUNT(*) FROM gift_codes WHERE creator_id = ? AND is_used = 0", (user_id,)
        ).fetchone()[0]
    finally:
        conn.close()

    if active_count >= 10:
        try:
            await query.edit_message_text(f"{e('5897548735214263769')} سقف کدهای فعال (۱۰ عدد) پر شده. منتظر بمون تا قبلی‌ها استفاده بشن!", parse_mode="HTML", reply_markup=user_gift_menu_keyboard())
        except BadRequest:
            pass
        return ConversationHandler.END

    try:
        msg = await query.edit_message_text(
            f"{e('6041900013347413437')} <b>مبلغ کد هدیه رو مشخص کن (به عدد انگلیسی):</b>\n"
            f"{e('5816531766382436821')} حداقل میزان پرتاب: <b>۵۰,۰۰۰</b> میوپوینت",
            parse_mode="HTML",
            reply_markup=cancel_keyboard()
        )
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return USER_CREATE_GIFT_AMOUNT

async def user_process_create_gift(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await check_anti_spam(update, context): return ConversationHandler.END
    if await is_bot_off_for_user(update): return ConversationHandler.END

    user_id = update.effective_user.id
    chat_id = update.effective_chat.id
    ensure_user_exists(user_id, update.effective_user.username, update.effective_user.first_name)
    text = sanitize_input(update.message.text)

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    if not text.isdigit():
        msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} لطفاً مبلغ را فقط به صورت عدد انگلیسی وارد کنید:", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
        return USER_CREATE_GIFT_AMOUNT

    amount = int(text)
    if amount < 50000:
        msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} حداقل مبلغ برای ساخت کد هدیه ۵۰,۰۰۰ میوپوینت است!", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
        return USER_CREATE_GIFT_AMOUNT

    conn = get_db()
    try:
        cursor = conn.cursor()
        user = cursor.execute("SELECT points FROM users WHERE user_id = ?", (user_id,)).fetchone()
        
        if not user or user['points'] < amount:
            msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} موجودی میوپوینتت برای ساخت این کد کافی نیست!", parse_mode="HTML", reply_markup=cancel_keyboard())
            context.user_data['last_bot_msg'] = msg.message_id
            return USER_CREATE_GIFT_AMOUNT

        cursor.execute("UPDATE users SET points = points - ? WHERE user_id = ? AND points >= ?", (amount, user_id, amount))
        if cursor.rowcount == 0:
            await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} خطایی رخ داد! مجددا تلاش کنید.", parse_mode="HTML", reply_markup=main_keyboard(user_id))
            return ConversationHandler.END

        code = "MEOW" + str(random.randint(100000, 999999))
        today = datetime.date.today().isoformat()
        
        cursor.execute(
            "INSERT INTO gift_codes (code, points, is_used, created_at, creator_id) VALUES (?, ?, 0, ?, ?)",
            (code, amount, today, user_id)
        )
        conn.commit()
    finally:
        conn.close()

    await context.bot.send_message(
        chat_id=chat_id,
        text=f"{e('5830144944399981619')} <b>کد هدیه میوپرانت با موفقیت ساخته شد!</b> {e('5845815828364142132')}\n\n"
             f"🎫 کد هدیه: <code>{code}</code>\n"
             f"{e('5825623013852192219')} ارزش: <b>{amount:,}</b> میوپوینت\n\n"
             f"مبلغ کد از موجودیت کسر شد. حالا می‌تونی کد رو برای دوستت بپرونی!",
        parse_mode="HTML",
        reply_markup=main_keyboard(user_id)
    )
    return ConversationHandler.END

# ---------------- WITHDRAW CONVERSATION ----------------
async def withdraw_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await check_anti_spam(update, context): return ConversationHandler.END
    if await is_bot_off_for_user(update): return ConversationHandler.END

    query = update.callback_query
    await query.answer()
    user_id = query.from_user.id
    ensure_user_exists(user_id, query.from_user.username, query.from_user.first_name)

    if await is_user_in_withdraw_queue(user_id):
        try:
            await query.edit_message_text(
                f"{e('5897548735214263769')} یک درخواست برداشت در صف پرتاب داری! بعد از اتمام اون می‌تونی درخواست جدید ثبت کنی.",
                parse_mode="HTML",
                reply_markup=main_keyboard(user_id)
            )
        except BadRequest:
            pass
        return ConversationHandler.END

    user = get_user(user_id)

    if not user or user['points'] < 100000:
        try:
            await query.edit_message_text(f"{e('5897548735214263769')} برای ثبت درخواست برداشت، حداقل باید <b>۱۰۰,۰۰۰</b> میوپوینت در حسابت داشته باشی!", parse_mode="HTML", reply_markup=main_keyboard(user_id))
        except BadRequest:
            pass
        return ConversationHandler.END

    try:
        msg = await query.edit_message_text(
            f"{e('6050918177653662060')} <b>مقدار میوپوینت برای خروج از حساب را وارد کن:</b>\n"
            f"{e('5816531766382436821')} (بین ۱۰۰,۰۰۰ تا ۵۰۰,۰۰۰ میوپوینت)",
            parse_mode="HTML",
            reply_markup=cancel_keyboard()
        )
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return WITHDRAW_AMOUNT

async def withdraw_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await check_anti_spam(update, context): return ConversationHandler.END
    if await is_bot_off_for_user(update): return ConversationHandler.END

    user_id = update.effective_user.id
    chat_id = update.effective_chat.id
    ensure_user_exists(user_id, update.effective_user.username, update.effective_user.first_name)
    text = sanitize_input(update.message.text)

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    if await is_user_in_withdraw_queue(user_id):
        await context.bot.send_message(
            chat_id=chat_id,
            text=f"{e('5897548735214263769')} یک درخواست برداشت در صف پرتاب داری! بعد از اتمام اون می‌تونی درخواست جدید ثبت کنی.",
            parse_mode="HTML",
            reply_markup=main_keyboard(user_id)
        )
        return ConversationHandler.END

    if not text.isdigit():
        msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} لطفاً مبلغ را فقط به صورت عدد انگلیسی وارد کنید {e('5845815828364142132')}", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
        return WITHDRAW_AMOUNT

    amount = int(text)
    if amount < 100000 or amount > 500000:
        msg = await context.bot.send_message(
            chat_id=chat_id,
            text=f"{e('5897548735214263769')} مبلغ برداشت باید حداقل ۱۰۰,۰۰۰ و حداکثر ۵۰۰,۰۰۰ میوپوینت باشد! {e('5845815828364142132')}",
            parse_mode="HTML",
            reply_markup=cancel_keyboard()
        )
        context.user_data['last_bot_msg'] = msg.message_id
        return WITHDRAW_AMOUNT

    conn = get_db()
    try:
        cursor = conn.cursor()
        user = cursor.execute("SELECT points FROM users WHERE user_id = ?", (user_id,)).fetchone()
        
        if not user or amount > user['points']:
            msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} مبلغ درخواستی بیشتر از موجودی شماست! {e('5845815828364142132')}", parse_mode="HTML", reply_markup=cancel_keyboard())
            context.user_data['last_bot_msg'] = msg.message_id
            return WITHDRAW_AMOUNT

        cursor.execute("UPDATE users SET points = points - ? WHERE user_id = ? AND points >= ?", (amount, user_id, amount))
        if cursor.rowcount == 0:
            await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} خطایی در ثبت درخواست برداشت رخ داد {e('5845815828364142132')}", parse_mode="HTML", reply_markup=main_keyboard(user_id))
            return ConversationHandler.END
        conn.commit()
    finally:
        conn.close()

    await add_withdrawal_to_file(amount, user_id)
    await context.bot.send_message(chat_id=chat_id, text=f"{e('5830144944399981619')} درخواست برداشتت با موفقیت ثبت شد و در صف پردازش میوپرانت قرار گرفت!", parse_mode="HTML", reply_markup=main_keyboard(user_id))
    await process_next_withdraw_queue(context.application)

    return ConversationHandler.END

# ---------------- OPERATOR WITHDRAWAL RESPONSE HANDLER ----------------
async def operator_delay_task(app: Application, reply_msg):
    global queue_busy
    queue_busy = True
    await update_withdraw_file_status()

    for sec in range(60, 0, -10):
        await asyncio.sleep(10)
        try:
            await reply_msg.edit_text(f"{e('5830144944399981619')} عملیات انجام شد.\n⏳ واریز بعدی تا {sec} ثانیه دیگر انجام می‌شود...", parse_mode="HTML")
        except Exception:
            pass
    
    await asyncio.sleep(1)
    try:
        await reply_msg.edit_text(f"{e('5830144944399981619')} عملیات انجام شد.\n✅ زمان انتظار به پایان رسید، در حال ارسال درخواست بعدی...", parse_mode="HTML")
    except Exception:
        pass

    queue_busy = False
    await update_withdraw_file_status()
    await process_next_withdraw_queue(app)

async def operator_group_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    msg = update.message
    if not msg or not msg.text or msg.chat_id != LOG_GROUP or msg.from_user.id != OPERATOR_ID:
        return

    text = sanitize_input(msg.text)
    
    match_success = re.match(r"^واریز\s+شد\s+(\d+)$", text)
    match_locked = re.match(r"^پروفایل\s+(?:کاربر\s+)?قفل\s+هست?\s+(\d+)$", text)
    match_low_level = re.match(r"^لول\s+پایین\s+(\d+)$", text)

    if match_success:
        target_user_id = int(match_success.group(1))
        removed_amount = await remove_withdrawal_from_file(target_user_id)
        
        if removed_amount > 0:
            try:
                user_msg = f"{e('5830144944399981619')} <b>تسویه با موفقیت انجام شد!</b>\nمبلغ <b>{removed_amount:,}</b> میوپوینت به حسابت منتقل گردید. مباركت باشه! {e('5845815828364142132')}"
                await context.bot.send_message(chat_id=target_user_id, text=user_msg, parse_mode="HTML")
            except Exception as e_err:
                logging.error(f"Error notifying user {target_user_id}: {e_err}")
            
            reply_msg = await msg.reply_text(f"{e('5830144944399981619')} واریزی برای کاربر {target_user_id} تایید شد.\n⏳ واریز بعدی تا ۶۱ ثانیه دیگر انجام می‌شود...", parse_mode="HTML")
            asyncio.create_task(operator_delay_task(context.application, reply_msg))
        else:
            await msg.reply_text(f"{e('5767342218905919987')} درخواستی برای کاربر {target_user_id} در فایل صف یافت نشد.", parse_mode="HTML")

    elif match_locked:
        target_user_id = int(match_locked.group(1))
        removed_amount = await remove_withdrawal_from_file(target_user_id)
        
        if removed_amount > 0:
            conn = get_db()
            try:
                conn.cursor().execute("UPDATE users SET points = points + ? WHERE user_id = ?", (removed_amount, target_user_id))
                conn.commit()
            finally:
                conn.close()
                
            try:
                user_msg = (
                    f"{e('5767342218905919987')} <b>بازگشت میوپوینت به حساب:</b>\n"
                    f"به دلیل قفل بودن پروفایل شما، واریز انجام نشد.\n"
                    f"مبلغ <b>{removed_amount:,}</b> میوپوینت مجدداً به حساب میوپرانت شما بازگردانده شد! {e('5929176380460769057')}"
                )
                await context.bot.send_message(chat_id=target_user_id, text=user_msg, parse_mode="HTML")
            except Exception as e_err:
                logging.error(f"Error notifying user {target_user_id}: {e_err}")

            reply_msg = await msg.reply_text(f"{e('5823664135103061930')} مبلغ {removed_amount:,} میوپوینت به کاربر {target_user_id} بازگردانده شد.\n⏳ واریز بعدی تا ۶۱ ثانیه دیگر انجام می‌شود...", parse_mode="HTML")
            asyncio.create_task(operator_delay_task(context.application, reply_msg))
        else:
            await msg.reply_text(f"{e('5767342218905919987')} درخواستی برای کاربر {target_user_id} در فایل صف یافت نشد.", parse_mode="HTML")

    elif match_low_level:
        target_user_id = int(match_low_level.group(1))
        removed_amount = await remove_withdrawal_from_file(target_user_id)
        
        if removed_amount > 0:
            conn = get_db()
            try:
                conn.cursor().execute("UPDATE users SET points = points + ? WHERE user_id = ?", (removed_amount, target_user_id))
                conn.commit()
            finally:
                conn.close()
                
            try:
                user_msg = (
                    f"{e('5767342218905919987')} <b>بازگشت میوپوینت به حساب:</b>\n"
                    f"سطح (لول) حساب شما در ربات میویی پایین است. لول شما باید حداقل ۲ باشد تا بتوانید درخواست برداشت ثبت کنید.\n"
                    f"مبلغ <b>{removed_amount:,}</b> میوپوینت مجدداً به حساب میوپرانت شما بازگردانده شد! {e('5929176380460769057')}"
                )
                await context.bot.send_message(chat_id=target_user_id, text=user_msg, parse_mode="HTML")
            except Exception as e_err:
                logging.error(f"Error notifying user {target_user_id}: {e_err}")

            reply_msg = await msg.reply_text(f"{e('5823664135103061930')} به علت لول پایین، مبلغ {removed_amount:,} میوپوینت به کاربر {target_user_id} بازگردانده شد.\n⏳ واریز بعدی تا ۶۱ ثانیه دیگر انجام می‌شود...", parse_mode="HTML")
            asyncio.create_task(operator_delay_task(context.application, reply_msg))
        else:
            await msg.reply_text(f"{e('5767342218905919987')} درخواستی برای کاربر {target_user_id} در فایل صف یافت نشد.", parse_mode="HTML")

# ---------------- GIFT CODE CONVERSATION ----------------
async def gift_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await check_anti_spam(update, context): return ConversationHandler.END
    if await is_bot_off_for_user(update): return ConversationHandler.END

    query = update.callback_query
    await query.answer()
    ensure_user_exists(query.from_user.id, query.from_user.username, query.from_user.first_name)
    try:
        msg = await query.edit_message_text(
            f"{e('5929398662198206659')} <b>کد هدیه‌ای که داری رو بفرست تا میوپوینت‌هاش پرتاب بشه سمتت:</b>",
            parse_mode="HTML",
            reply_markup=cancel_keyboard()
        )
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return GIFT_CODE_WAITING

async def gift_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await check_anti_spam(update, context): return ConversationHandler.END
    if await is_bot_off_for_user(update): return ConversationHandler.END

    code = sanitize_input(update.message.text).upper()
    user_id = update.effective_user.id
    chat_id = update.effective_chat.id
    user_first_name = update.effective_user.first_name or "کاربر"
    ensure_user_exists(user_id, update.effective_user.username, update.effective_user.first_name)

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    conn = get_db()
    try:
        cursor = conn.cursor()
        cursor.execute("BEGIN IMMEDIATE")
        gift_row = cursor.execute("SELECT id, code, points, is_used, creator_id FROM gift_codes WHERE code = ? AND is_used = 0", (code,)).fetchone()
        
        if not gift_row:
            conn.rollback()
            msg = await context.bot.send_message(
                chat_id=chat_id, 
                text=f"{e('5897548735214263769')} این کد هدیه اشتباهه یا قبلاً پرتاب و دریافت شده!", 
                parse_mode="HTML",
                reply_markup=cancel_keyboard()
            )
            context.user_data['last_bot_msg'] = msg.message_id
            return GIFT_CODE_WAITING

        gift_points = gift_row['points']
        gift_id = gift_row['id']
        creator_id = gift_row['creator_id']

        cursor.execute("UPDATE gift_codes SET is_used = 1 WHERE id = ?", (gift_id,))
        if cursor.rowcount == 0:
            conn.rollback()
            msg = await context.bot.send_message(
                chat_id=chat_id, 
                text=f"{e('5897548735214263769')} این کد هدیه هم‌زمان توسط کاربر دیگری مصرف شد!", 
                parse_mode="HTML",
                reply_markup=cancel_keyboard()
            )
            context.user_data['last_bot_msg'] = msg.message_id
            return GIFT_CODE_WAITING

        cursor.execute("UPDATE users SET points = points + ? WHERE user_id = ?", (gift_points, user_id))
        conn.commit()
        
        await context.bot.send_message(
            chat_id=chat_id, 
            text=f"{e('5818866927216369505')} <b>کد هدیه فعال شد!</b>\nمقدار <b>{gift_points:,}</b> میوپوینت با موفقیت به حسابت پرتاب شد! {e('5845815828364142132')}", 
            parse_mode="HTML", 
            reply_markup=main_keyboard(user_id)
        )

        if creator_id and creator_id != 0 and creator_id != user_id:
            try:
                creator_msg = (
                    f"{e('5818866927216369505')} <b>کد هدیه شما استفاده شد!</b>\n\n"
                    f"👤 کاربر: <b>{escape_html(user_first_name)}</b> (<code>{user_id}</code>)\n"
                    f"🎫 کد: <code>{code}</code>\n"
                    f"{e('5825623013852192219')} مقدار <b>{gift_points:,}</b> میوپوینت به حساب کاربر واریز شد!"
                )
                await context.bot.send_message(chat_id=creator_id, text=creator_msg, parse_mode="HTML")
            except Exception as e_err:
                logging.error(f"Error sending gift claim notification to creator {creator_id}: {e_err}")

    except Exception as ex:
        conn.rollback()
        logging.error(f"Gift process error: {ex}")
        await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} خطایی در پردازش کد رخ داد. لطفاً مجدداً تلاش کنید.", parse_mode="HTML", reply_markup=main_keyboard(user_id))
    finally:
        conn.close()

    return ConversationHandler.END

# ---------------- SUPPORT SYSTEM ----------------
async def support_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await check_anti_spam(update, context): return ConversationHandler.END
    if await is_bot_off_for_user(update): return ConversationHandler.END

    query = update.callback_query
    await query.answer()
    ensure_user_exists(query.from_user.id, query.from_user.username, query.from_user.first_name)
    try:
        msg = await query.edit_message_text(SUPPORT_TEXT, parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return SUPPORT_WAITING

async def support_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await check_anti_spam(update, context): return ConversationHandler.END
    if await is_bot_off_for_user(update): return ConversationHandler.END

    chat_id = update.effective_chat.id
    user_id = update.effective_user.id
    user_fname = escape_html(update.effective_user.first_name)
    ensure_user_exists(user_id, update.effective_user.username, update.effective_user.first_name)
    
    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    admin_keyboard_supp = InlineKeyboardMarkup([
        [InlineKeyboardButton("دیدن اطلاعات کاربر", callback_data=f"supp_info_{user_id}", icon_custom_emoji_id="5830338333892418460", style="primary")],
        [InlineKeyboardButton("ارسال پیام به کاربر", callback_data=f"supp_reply_{user_id}", icon_custom_emoji_id="5911198059676574025", style="success")]
    ])

    fwd_msg = await update.message.forward(chat_id=ADMIN_ID)
    await context.bot.send_message(
        chat_id=ADMIN_ID,
        text=f"{e('5883982896326254229')} <b>پیام جدید از طرف کاربر:</b> {user_fname} (<code>{user_id}</code>)",
        parse_mode="HTML",
        reply_to_message_id=fwd_msg.message_id,
        reply_markup=admin_keyboard_supp
    )

    await context.bot.send_message(chat_id=chat_id, text=f"{e('5830144944399981619')} پیامت سمت پشتیبانی میوپرانت پرتاب شد! بزودی پاسخت رو می‌فرستیم {e('5845815828364142132')}", parse_mode="HTML", reply_markup=main_keyboard(user_id))
    return ConversationHandler.END

async def support_admin_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID:
        return
    await query.answer()
    data = query.data

    if data.startswith("supp_info_"):
        target_id_str = data.replace("supp_info_", "")
        if target_id_str.isdigit():
            await render_user_profile_admin(context.bot, query.message.chat_id, int(target_id_str))

    elif data.startswith("supp_reply_"):
        target_id_str = data.replace("supp_reply_", "")
        if target_id_str.isdigit():
            context.user_data['supp_target_user'] = int(target_id_str)
            msg = await context.bot.send_message(
                chat_id=ADMIN_ID,
                text=f"{e('5911198059676574025')} <b>پیام خود را ارسال کنید (متن، عکس، استیکر یا هر فایلی):</b>",
                parse_mode="HTML",
                reply_markup=cancel_keyboard()
            )
            context.user_data['last_bot_msg'] = msg.message_id
            return ADMIN_REPLY_SUPP_INPUT

async def admin_support_send_response(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID:
        return ConversationHandler.END
    
    chat_id = update.effective_chat.id
    target_id = context.user_data.get('supp_target_user')

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    if not target_id:
        await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} مشخصات کاربر یافت نشد!", reply_markup=admin_keyboard())
        return ConversationHandler.END

    try:
        await context.bot.copy_message(chat_id=target_id, from_chat_id=ADMIN_ID, message_id=update.message.message_id)
        await context.bot.send_message(chat_id=chat_id, text=f"{e('5830144944399981619')} پاسخ شما با موفقیت برای کاربر <code>{target_id}</code> ارسال شد {e('5845815828364142132')}", parse_mode="HTML", reply_markup=admin_keyboard())
    except Exception as e_err:
        await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} خطا در ارسال پاسخ: {escape_html(str(e_err))}", parse_mode="HTML", reply_markup=admin_keyboard())

    return ConversationHandler.END

async def admin_reply_support(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return
    msg = update.message
    
    if msg.reply_to_message and msg.reply_to_message.forward_from:
        target_user_id = msg.reply_to_message.forward_from.id
        try:
            await context.bot.copy_message(chat_id=target_user_id, from_chat_id=ADMIN_ID, message_id=msg.message_id)
            await msg.reply_text(f"{e('5830144944399981619')} پاسخ مستقیم با موفقیت به کاربر ارسال شد {e('5845815828364142132')}", parse_mode="HTML")
        except Exception as e_err:
            await msg.reply_text(f"{e('5897548735214263769')} خطا در ارسال پاسخ به کاربر: {escape_html(str(e_err))}", parse_mode="HTML")

# ---------------- ADMIN PANEL ----------------
async def admin_panel_open(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return
    await query.answer()
    try:
        await query.edit_message_text(f"{e('6014651259057873388')} <b>مرکز فرماندهی و مدیریت میوپرانت:</b> {e('5845815828364142132')}", parse_mode="HTML", reply_markup=admin_keyboard())
    except BadRequest:
        pass

async def admin_toggle_bot_status(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return
    await query.answer()

    curr_st = get_setting('bot_status', 'on')
    new_st = 'off' if curr_st == 'on' else 'on'
    set_setting('bot_status', new_st)

    try:
        await query.edit_message_reply_markup(reply_markup=admin_keyboard())
    except BadRequest:
        pass

async def admin_manage_user_gifts(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return
    await query.answer()

    conn = get_db()
    try:
        gifts = conn.cursor().execute("SELECT * FROM gift_codes WHERE creator_id != 0 AND is_used = 0 ORDER BY id DESC").fetchall()
    finally:
        conn.close()

    if not gifts:
        try:
            await query.edit_message_text(f"{e('5897548735214263769')} هیچ کد هدیه فعال و استفاده‌نشده‌ای توسط کاربران ساخته نشده است {e('5845815828364142132')}", parse_mode="HTML", reply_markup=admin_keyboard())
        except BadRequest:
            pass
        return

    buttons = []
    for g in gifts:
        buttons.append([InlineKeyboardButton(f"حذف کد {g['code']} ({g['points']:,} میو)", callback_data=f"del_ugift_{g['id']}", icon_custom_emoji_id="5873075766748520540", style="danger")])
    buttons.append([InlineKeyboardButton("بازگشت", callback_data="admin_panel", icon_custom_emoji_id="5823664135103061930")])

    try:
        await query.edit_message_text(f"{e('5929398662198206659')} <b>لیست کدهای ساخته‌شده توسط کاربران (امکان حذف):</b> {e('5845815828364142132')}", parse_mode="HTML", reply_markup=InlineKeyboardMarkup(buttons))
    except BadRequest:
        pass

async def admin_manage_admin_gifts(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return
    await query.answer()

    conn = get_db()
    try:
        gifts = conn.cursor().execute("SELECT * FROM gift_codes WHERE creator_id = 0 AND is_used = 0 ORDER BY id DESC").fetchall()
    finally:
        conn.close()

    if not gifts:
        try:
            await query.edit_message_text(f"{e('5897548735214263769')} هیچ کد هدیه فعالی توسط ادمین ساخته نشده است {e('5845815828364142132')}", parse_mode="HTML", reply_markup=admin_keyboard())
        except BadRequest:
            pass
        return

    buttons = []
    for g in gifts:
        buttons.append([InlineKeyboardButton(f"حذف کد {g['code']} ({g['points']:,} میو)", callback_data=f"del_agift_{g['id']}", icon_custom_emoji_id="5873075766748520540", style="danger")])
    buttons.append([InlineKeyboardButton("بازگشت", callback_data="admin_panel", icon_custom_emoji_id="5823664135103061930")])

    try:
        await query.edit_message_text(f"{e('6014651259057873388')} <b>لیست کدهای فعال ساخته‌شده توسط ادمین:</b> {e('5845815828364142132')}", parse_mode="HTML", reply_markup=InlineKeyboardMarkup(buttons))
    except BadRequest:
        pass

async def admin_delete_user_gift(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return
    await query.answer()

    gift_id_raw = query.data.replace("del_ugift_", "")
    if not gift_id_raw.isdigit():
        return
    gift_id = int(gift_id_raw)

    conn = get_db()
    try:
        gift = conn.cursor().execute("SELECT * FROM gift_codes WHERE id = ?", (gift_id,)).fetchone()
        if gift:
            creator_id = gift['creator_id']
            code_str = gift['code']
            conn.cursor().execute("DELETE FROM gift_codes WHERE id = ?", (gift_id,))
            conn.commit()

            try:
                await context.bot.send_message(
                    chat_id=creator_id,
                    text=f"{e('5767342218905919987')} <b>اطلاعیه میوپرانت:</b>\nکد هدیه <code>{code_str}</code> لغو و توسط مدیریت سیستم غیرفعال شد.",
                    parse_mode="HTML"
                )
            except Exception:
                pass
    finally:
        conn.close()

    await query.answer("کد هدیه کاربر با موفقیت حذف شد.", show_alert=True)
    await admin_manage_user_gifts(update, context)

async def admin_delete_admin_gift(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return
    await query.answer()

    gift_id_raw = query.data.replace("del_agift_", "")
    if not gift_id_raw.isdigit():
        return
    gift_id = int(gift_id_raw)

    conn = get_db()
    try:
        conn.cursor().execute("DELETE FROM gift_codes WHERE id = ?", (gift_id,))
        conn.commit()
    finally:
        conn.close()

    await query.answer("کد هدیه ادمین با موفقیت حذف شد.", show_alert=True)
    await admin_manage_admin_gifts(update, context)

# ---------------- FORCE JOIN TOGGLE ----------------
async def admin_toggle_fj(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return
    await query.answer()

    current = get_setting('force_join_status', 'on')
    new_val = 'off' if current == 'on' else 'on'
    set_setting('force_join_status', new_val)

    try:
        await query.edit_message_reply_markup(reply_markup=admin_keyboard())
    except BadRequest:
        pass

# ---------------- FORCE JOIN MANAGEMENT PANEL ----------------
async def admin_manage_fj_channels(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return
    await query.answer()

    conn = get_db()
    try:
        channels = conn.cursor().execute("SELECT * FROM force_joins").fetchall()
    finally:
        conn.close()

    text = f"{e('5816404884458577332')} <b>مدیریت کانال‌ها و گروه‌های جوین اجباری:</b>\n\n"
    buttons = []

    if channels:
        for idx, ch in enumerate(channels, 1):
            target = str(ch['chat_id_or_link']).strip()
            if (target.startswith("-") and target[1:].isdigit()) or target.isdigit():
                chat_target = int(target)
            else:
                chat_target = target if target.startswith("@") else f"@{target}"
            
            # استخراج نام واقعی و به‌روزرسانی در صورت تغییر
            real_title = ch['title'] or "بدون نام"
            try:
                chat_info = await context.bot.get_chat(chat_id=chat_target)
                if chat_info and chat_info.title:
                    real_title = chat_info.title
                    conn_up = get_db()
                    try:
                        conn_up.cursor().execute("UPDATE force_joins SET title = ? WHERE id = ?", (real_title, ch['id']))
                        conn_up.commit()
                    finally:
                        conn_up.close()
            except Exception:
                pass

            text += f"{idx}. <b>{escape_html(real_title)}</b> | شناسه: <code>{escape_html(ch['chat_id_or_link'])}</code>\n"
            buttons.append([InlineKeyboardButton(f"❌ حذف: {real_title}", callback_data=f"del_fj_{ch['id']}", icon_custom_emoji_id="5873075766748520540", style="danger")])
    else:
        text += "هیچ کانال یا گروهی ثبت نشده است.\n"

    buttons.append([InlineKeyboardButton("➕ افزودن کانال/گروه جدید", callback_data="add_fj_channel", icon_custom_emoji_id="5819032824623144971", style="success")])
    buttons.append([InlineKeyboardButton("بازگشت به پنل مدیریت", callback_data="admin_panel", icon_custom_emoji_id="5823664135103061930")])

    try:
        await query.edit_message_text(text, parse_mode="HTML", reply_markup=InlineKeyboardMarkup(buttons))
    except BadRequest:
        pass

async def admin_delete_fj_channel(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return
    await query.answer()

    fj_id = query.data.replace("del_fj_", "")
    if fj_id.isdigit():
        conn = get_db()
        try:
            conn.cursor().execute("DELETE FROM force_joins WHERE id = ?", (int(fj_id),))
            conn.commit()
        finally:
            conn.close()
        await query.answer("کانال/گروه مورد نظر با موفقیت حذف شد.", show_alert=True)
    
    await admin_manage_fj_channels(update, context)

async def admin_add_fj_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()

    try:
        msg = await query.edit_message_text(
            f"{e('5816404884458577332')} <b>شناسه کانال یا گروه را وارد کنید:</b>\n\n"
            f"می‌توانید <b>آیدی عددی</b> (مثل <code>-1001234567890</code>) یا <b>یوزرنیم عمومی</b> (مثل <code>@MyChannel</code>) را ارسال کنید.\n"
            f"<i>نکته: ربات باید در کانال/گروه مربوطه ادمین باشد تا اسم واقعی آن استخراج شود.</i>",
            parse_mode="HTML",
            reply_markup=cancel_keyboard()
        )
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return ADMIN_ADD_FJ_CHAT

async def admin_add_fj_chat_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    chat_id = update.effective_chat.id
    target_chat = sanitize_input(update.message.text)

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    if (target_chat.startswith("-") and target_chat[1:].isdigit()) or target_chat.isdigit():
        chat_target = int(target_chat)
    else:
        chat_target = target_chat if target_chat.startswith("@") else f"@{target_chat}"

    real_title = "کانال جوین اجباری"
    try:
        chat_info = await context.bot.get_chat(chat_id=chat_target)
        if chat_info and chat_info.title:
            real_title = chat_info.title
    except Exception as err:
        msg = await context.bot.send_message(
            chat_id=chat_id,
            text=f"{e('5897548735214263769')} <b>خطا در دریافت اطلاعات کانال/گروه!</b>\n"
                 f"مطمئن شوید ربات در این کانال/گروه عضو و ادمین است، سپس دوباره آیدی یا شناسه را بفرستید.\n\n"
                 f"<i>جزئیات خطا: {escape_html(str(err))}</i>",
            parse_mode="HTML",
            reply_markup=cancel_keyboard()
        )
        context.user_data['last_bot_msg'] = msg.message_id
        return ADMIN_ADD_FJ_CHAT

    conn = get_db()
    try:
        conn.cursor().execute("INSERT INTO force_joins (title, chat_id_or_link) VALUES (?, ?)", (real_title, target_chat))
        conn.commit()
    finally:
        conn.close()

    await context.bot.send_message(
        chat_id=chat_id,
        text=f"{e('5830144944399981619')} کانال/گروه با عنوان واقعی <b>{escape_html(real_title)}</b> و شناسه <code>{escape_html(target_chat)}</code> با موفقیت اضافه شد.",
        parse_mode="HTML",
        reply_markup=admin_keyboard()
    )
    return ConversationHandler.END

# ---------------- DAILY LEADERBOARD & REWARDS ----------------
def daily_reset_keyboard():
    buttons = []
    for hour in range(24):
        buttons.append([
            InlineKeyboardButton(f"{hour:02d}:00", callback_data=f"daily_time_{hour:02d}:00", icon_custom_emoji_id="5906896396526560494"),
            InlineKeyboardButton(f"{hour:02d}:15", callback_data=f"daily_time_{hour:02d}:15", icon_custom_emoji_id="5906896396526560494"),
            InlineKeyboardButton(f"{hour:02d}:30", callback_data=f"daily_time_{hour:02d}:30", icon_custom_emoji_id="5906896396526560494"),
            InlineKeyboardButton(f"{hour:02d}:45", callback_data=f"daily_time_{hour:02d}:45", icon_custom_emoji_id="5906896396526560494")
        ])
    buttons.append([InlineKeyboardButton("بازگشت", callback_data="admin_panel", icon_custom_emoji_id="5845815828364142132")])
    return InlineKeyboardMarkup(buttons)

async def daily_reset_job(app: Application):
    while True:
        try:
            reset_time = get_setting('daily_reset_time', '00:00')
            now = datetime.datetime.now()
            try:
                reset_hour, reset_minute = (int(part) for part in reset_time.split(':', 1))
                scheduled_reset = now.replace(hour=reset_hour, minute=reset_minute, second=0, microsecond=0)
            except (AttributeError, TypeError, ValueError):
                scheduled_reset = now.replace(hour=0, minute=0, second=0, microsecond=0)
            last_reset = parse_daily_reset(get_setting('daily_last_reset', ''))
            if now >= scheduled_reset and (last_reset is None or last_reset < scheduled_reset):
                await distribute_daily_rewards(app)
                set_setting('daily_last_reset', scheduled_reset.isoformat(timespec="seconds"))
        except Exception as err:
            logging.error(f"خطا در ریست روزانه: {err}")
        await asyncio.sleep(20)

def parse_daily_reset(value):
    if not value:
        return None
    try:
        return datetime.datetime.fromisoformat(str(value))
    except (TypeError, ValueError):
        try:
            return datetime.datetime.combine(datetime.date.fromisoformat(str(value)), datetime.time())
        except (TypeError, ValueError):
            return None

async def distribute_daily_rewards(app: Application):
    conn = get_db()
    try:
        rows = conn.cursor().execute(
            "SELECT user_id, username, first_name, daily_referrals FROM users WHERE daily_referrals > 0 ORDER BY daily_referrals DESC, user_id ASC LIMIT 3"
        ).fetchall()
        base = max(0, int(get_setting('daily_prize_base', '10000')))
        rewards = [base, int(base * 0.7), int(base * 0.7 * 0.7)]
        winner_rewards = []
        if len(rows) >= 3:
            winner_rewards = [(rows[index]['user_id'], rewards[index]) for index in range(3)]
        elif len(rows) == 2:
            half = rewards[2] // 2
            winner_rewards = [(rows[0]['user_id'], rewards[0] + half + rewards[2] % 2), (rows[1]['user_id'], rewards[1] + half)]
        elif len(rows) == 1:
            winner_rewards = [(rows[0]['user_id'], sum(rewards))]

        for user_id, amount in winner_rewards:
            conn.cursor().execute("UPDATE users SET points = points + ? WHERE user_id = ?", (amount, user_id))
        conn.cursor().execute("UPDATE users SET daily_referrals = 0")
        conn.commit()
    finally:
        conn.close()

    if not winner_rewards:
        message = f"{e('5906896396526560494')} زیرمجموعه‌گیری روزانه ریست شد و برنده‌ای امروز نداشتیم."
        news_channel = get_setting('news_channel_id', '').strip()
        if news_channel:
            try:
                await app.bot.send_message(chat_id=int(news_channel), text=message, parse_mode="HTML")
            except Exception as err:
                logging.error(f"خطا در ارسال خبر ریست روزانه: {err}")
        return

    winner_lines = []
    winner_lookup = {row["user_id"]: row for row in rows}
    for index, (user_id, amount) in enumerate(winner_rewards, 1):
        row = winner_lookup.get(user_id, {})
        winner_name = escape_html(row.get("first_name") or row.get("username") or "کاربر")
        winner_lines.append(f"{index}. <b>{winner_name}</b> - <b>{amount:,}</b> {e('5825623013852192219')} میوپوینت")
        try:
            await app.bot.send_message(
                chat_id=user_id,
                text=f"{e('5818866927216369505')} <b>تبریک!</b>\n\nبه دلیل کسب رتبه در دعوت‌های امروز، <b>{amount:,}</b> میوپوینت جایزه گرفتی.",
                parse_mode="HTML"
            )
        except Exception:
            pass

    news_channel = get_setting('news_channel_id', '').strip()
    if news_channel:
        try:
            await app.bot.send_message(
                chat_id=int(news_channel),
                text=f"{e('6014651259057873388')} <b>برندگان زیرمجموعه‌گیری روزانه</b>\n\n" + "\n".join(winner_lines),
                parse_mode="HTML"
            )
        except Exception as err:
            logging.error(f"خطا در ارسال برندگان روزانه: {err}")

async def admin_top_user_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()
    await query.edit_message_text(f"{e('6044084382174552276')} آیدی عددی کاربر حاضر در برترین‌ها را وارد کنید:", reply_markup=cancel_keyboard())
    return ADMIN_TOP_USER

async def admin_top_user_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    text = sanitize_input(update.message.text)
    if not text.isdigit():
        await update.message.reply_text("لطفاً فقط آیدی عددی معتبر وارد کنید:", reply_markup=cancel_keyboard())
        return ADMIN_TOP_USER
    await render_user_profile_admin(context.bot, update.effective_chat.id, int(text))
    return ConversationHandler.END

async def admin_daily_prize_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()
    current = int(get_setting('daily_prize_base', '10000'))
    await query.edit_message_text(f"{e('5929398662198206659')} مبلغ پایه فعلی: <b>{current:,}</b>\nمبلغ پایه جدید را به عدد انگلیسی وارد کنید:", parse_mode="HTML", reply_markup=cancel_keyboard())
    return ADMIN_DAILY_PRIZE

async def admin_daily_prize_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    text = sanitize_input(update.message.text)
    if not text.isdigit():
        await update.message.reply_text("لطفاً فقط عدد انگلیسی وارد کنید:", reply_markup=cancel_keyboard())
        return ADMIN_DAILY_PRIZE
    set_setting('daily_prize_base', text)
    await update.message.reply_text(f"{e('5929398662198206659')} مبلغ پایه جایزه روزانه روی <b>{int(text):,}</b> تنظیم شد.", parse_mode="HTML", reply_markup=admin_keyboard())
    return ConversationHandler.END

async def admin_news_channel_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()
    current = get_setting('news_channel_id', '') or 'تنظیم نشده'
    await query.edit_message_text(f"{e('5883982896326254229')} آیدی فعلی کانال خبرها: <code>{escape_html(current)}</code>\nآیدی عددی جدید را وارد کنید:", parse_mode="HTML", reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("حذف آیدی کانال", callback_data="admin_news_channel_delete", icon_custom_emoji_id="5873075766748520540")], [InlineKeyboardButton("لغو", callback_data="cancel_action", icon_custom_emoji_id="5819154526816444042")]]))
    return ADMIN_NEWS_CHANNEL

async def admin_news_channel_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    text = sanitize_input(update.message.text)
    if not re.fullmatch(r"-?\d+", text):
        await update.message.reply_text("لطفاً آیدی عددی کانال را وارد کنید:", reply_markup=cancel_keyboard())
        return ADMIN_NEWS_CHANNEL
    set_setting('news_channel_id', text)
    await update.message.reply_text(f"{e('5830144944399981619')} کانال خبرها با موفقیت تنظیم شد.", parse_mode="HTML", reply_markup=admin_keyboard())
    return ConversationHandler.END

async def admin_news_channel_delete(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return
    await query.answer("کانال خبرها حذف شد.")
    set_setting('news_channel_id', '')
    await query.edit_message_text(f"{e('5830144944399981619')} آیدی کانال خبرها حذف شد.", parse_mode="HTML", reply_markup=admin_keyboard())

async def admin_reset_time_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()
    await query.edit_message_text(f"{e('5906896396526560494')} ساعت و دقیقه ریست روزانه را انتخاب کنید:", reply_markup=daily_reset_keyboard())
    return ADMIN_RESET_HOUR

async def admin_reset_time_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    if not query.data.startswith("daily_time_"): return ADMIN_RESET_HOUR
    reset_time = query.data.replace("daily_time_", "")
    set_setting('daily_reset_time', reset_time)
    set_setting('daily_last_reset', '')
    await query.answer("زمان ریست ذخیره شد.")
    await query.edit_message_text(f"{e('5830144944399981619')} زمان ریست روزانه روی <b>{reset_time}</b> تنظیم شد.", parse_mode="HTML", reply_markup=admin_keyboard())
    return ConversationHandler.END

# ---------------- SET REFERRAL REWARD ----------------
async def admin_set_ref_reward_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()

    curr_val = get_setting('ref_reward_amount', '50000')
    try:
        msg = await query.edit_message_text(
            f"{e('5825623013852192219')} <b>تنظیم مقدار میوپوینت پاداش زیرمجموعه‌گیری:</b>\n\n"
            f"مقدار فعلی پاداش: <b>{int(curr_val):,}</b> میوپوینت\n\n"
            f"لطفاً مقدار جدید پاداش را به عدد انگلیسی وارد کنید:",
            parse_mode="HTML",
            reply_markup=cancel_keyboard()
        )
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return ADMIN_SET_REF_REWARD

async def admin_set_ref_reward_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    chat_id = update.effective_chat.id
    text = sanitize_input(update.message.text)

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    if not text.isdigit():
        msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} لطفاً فقط عدد انگلیسی وارد کنید:", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
        return ADMIN_SET_REF_REWARD

    new_amount = int(text)
    set_setting('ref_reward_amount', str(new_amount))

    await context.bot.send_message(
        chat_id=chat_id,
        text=f"{e('5830144944399981619')} مقدار پاداش زیرمجموعه‌گیری با موفقیت به <b>{new_amount:,}</b> میوپوینت تغییر یافت.",
        parse_mode="HTML",
        reply_markup=admin_keyboard()
    )
    return ConversationHandler.END

# ---------------- STATS & BROADCAST ----------------
async def admin_stats(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return
    await query.answer()

    conn = get_db()
    try:
        cursor = conn.cursor()
        users_count = cursor.execute("SELECT COUNT(*) FROM users").fetchone()[0]
        blocked_count = cursor.execute("SELECT COUNT(*) FROM users WHERE is_blocked = 1").fetchone()[0]
        user_points_sum = cursor.execute("SELECT SUM(points) FROM users").fetchone()[0] or 0
        gifts_points_sum = cursor.execute("SELECT SUM(points) FROM gift_codes WHERE is_used = 0").fetchone()[0] or 0
        active_gifts_count = cursor.execute("SELECT COUNT(*) FROM gift_codes WHERE is_used = 0").fetchone()[0]
        total_circulating = user_points_sum + gifts_points_sum
    finally:
        conn.close()

    stats_msg = (
        f"{e('6044084382174552276')} <b>آمار کل قلمرو میوپرانت:</b>\n\n"
        f"{e('5859432880442187580')} کل کاربران ثبت‌نامی: <b>{users_count:,}</b> نفر\n"
        f"{e('5873075766748520540')} کاربران مسدود شده: <b>{blocked_count:,}</b> نفر\n\n"
        f"{e('5825623013852192219')} میوپوینت در موجودی حساب‌ها: <b>{user_points_sum:,}</b> میو\n"
        f"{e('5929398662198206659')} میوپوینت در کدهای فعال: <b>{gifts_points_sum:,}</b> میو ({active_gifts_count} کد)\n"
        f"{e('6041900013347413437')} <b>مجموع میوپوینت‌های فعال و در حال پرواز:</b> <b>{total_circulating:,}</b> میو"
    )
    try:
        await query.edit_message_text(stats_msg, parse_mode="HTML", reply_markup=admin_keyboard())
    except BadRequest:
        pass

async def admin_bc_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()
    context.user_data['is_fwd'] = False
    try:
        msg = await query.edit_message_text(
            f"{e('5883982896326254229')} <b>پیام همگانی خود را برای ارسال ارسال کنید:</b> {e('5845815828364142132')}", 
            parse_mode="HTML", 
            reply_markup=cancel_keyboard()
        )
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return ADMIN_BC_TEXT

async def admin_fwd_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()
    context.user_data['is_fwd'] = True
    try:
        msg = await query.edit_message_text(
            f"{e('5823664135103061930')} <b>پست مورد نظر جهت فوروارد همگانی را بفرستید:</b> {e('5845815828364142132')}", 
            parse_mode="HTML", 
            reply_markup=cancel_keyboard()
        )
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return ADMIN_BC_TEXT

async def admin_broadcast_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    chat_id = update.effective_chat.id
    msg = update.message
    is_fwd = context.user_data.get('is_fwd', False)
    
    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    conn = get_db()
    try:
        users = conn.cursor().execute("SELECT user_id FROM users WHERE is_blocked = 0").fetchall()
    finally:
        conn.close()

    status_msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5816531766382436821')} ارسال همگانی به {len(users)} کاربر آغاز شد... {e('5845815828364142132')}", parse_mode="HTML")
    success, failed = 0, 0

    for idx, u in enumerate(users):
        try:
            if is_fwd:
                await context.bot.forward_message(chat_id=u['user_id'], from_chat_id=ADMIN_ID, message_id=msg.message_id)
            else:
                await context.bot.copy_message(chat_id=u['user_id'], from_chat_id=ADMIN_ID, message_id=msg.message_id)
            success += 1
        except Exception:
            failed += 1
        
        if (idx + 1) % 25 == 0:
            await asyncio.sleep(1.0)
        else:
            await asyncio.sleep(0.04)

    try:
        await status_msg.edit_text(f"{e('5830144944399981619')} <b>عملیات ارسال همگانی به پایان رسید!</b> {e('5845815828364142132')}\n\n{e('5830144944399981619')} موفق: {success}\n{e('5819154526816444042')} ناموفق: {failed}", parse_mode="HTML", reply_markup=admin_keyboard())
    except BadRequest:
        pass
    return ConversationHandler.END

# ---------------- ADVANCED USER MANAGEMENT ----------------
async def admin_manage_user_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()
    try:
        msg = await query.edit_message_text(
            f"{e('5859432880442187580')} <b>آیدی عددی کاربر مورد نظر را برای مدیریت وارد کنید:</b> {e('5845815828364142132')}", 
            parse_mode="HTML", 
            reply_markup=cancel_keyboard()
        )
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return ADMIN_MANAGE_USER_INPUT

async def render_user_profile_admin(bot, admin_chat_id: int, target_user_id: int, edit_message_id: int = None):
    conn = get_db()
    try:
        cursor = conn.cursor()
        user = cursor.execute("SELECT * FROM users WHERE user_id = ?", (target_user_id,)).fetchone()
        if not user:
            msg_text = f"{e('5897548735214263769')} کاربری با این آیدی عددی در ربات پیدا نشد!"
            if edit_message_id:
                try:
                    await bot.edit_message_text(chat_id=admin_chat_id, message_id=edit_message_id, text=msg_text, parse_mode="HTML", reply_markup=admin_keyboard())
                except BadRequest:
                    pass
            else:
                await bot.send_message(chat_id=admin_chat_id, text=msg_text, parse_mode="HTML", reply_markup=admin_keyboard())
            return

        gifts = cursor.execute("SELECT * FROM gift_codes WHERE creator_id = ? AND is_used = 0", (target_user_id,)).fetchall()
    finally:
        conn.close()

    status_str = f"مسدود {e('5873075766748520540')}" if user['is_blocked'] == 1 else f"فعال {e('5830144944399981619')}"
    
    text = (
        f"{e('5859432880442187580')} <b>اطلاعات و مرکز مدیریت کاربر:</b> {e('5845815828364142132')}\n\n"
        f"🆔 آیدی عددی: <code>{user['user_id']}</code>\n"
        f"👤 نام: <b>{user['first_name']}</b>\n"
        f"🏷 یوزرنیم: @{user['username'] if user['username'] else 'ندارد'}\n"
        f"📊 وضعیت حساب: <b>{status_str}</b>\n"
        f"{e('5825623013852192219')} موجودی: <b>{user['points']:,}</b> میوپوینت\n"
        f"{e('5859432880442187580')} زیرمجموعه‌ها: <b>{user['referrals_count']}</b> نفر\n"
        f"{e('5929398662198206659')} کدهای هدیه فعال: <b>{len(gifts)}</b> عدد"
    )

    block_text = "رفع مسدودی" if user['is_blocked'] == 1 else "مسدود کردن"
    block_icon = "5830144944399981619" if user['is_blocked'] == 1 else "5873075766748520540"
    block_style = "success" if user['is_blocked'] == 1 else "danger"

    buttons = [
        [
            InlineKeyboardButton("افزایش میوپوینت", callback_data=f"usr_addp_{target_user_id}", icon_custom_emoji_id="5819032824623144971", style="success"),
            InlineKeyboardButton("کاهش میوپوینت", callback_data=f"usr_subp_{target_user_id}", icon_custom_emoji_id="5819154526816444042", style="danger")
        ],
        [
            InlineKeyboardButton(block_text, callback_data=f"usr_toggleblock_{target_user_id}", icon_custom_emoji_id=block_icon, style=block_style),
            InlineKeyboardButton("ارسال پیام مستقیم", callback_data=f"usr_msg_{target_user_id}", icon_custom_emoji_id="5911198059676574025", style="primary")
        ],
        [InlineKeyboardButton("بازگشت به پنل مدیریت", callback_data="admin_panel", icon_custom_emoji_id="5823664135103061930")]
    ]

    if edit_message_id:
        try:
            await bot.edit_message_text(chat_id=admin_chat_id, message_id=edit_message_id, text=text, parse_mode="HTML", reply_markup=InlineKeyboardMarkup(buttons))
        except BadRequest:
            pass
    else:
        await bot.send_message(chat_id=admin_chat_id, text=text, parse_mode="HTML", reply_markup=InlineKeyboardMarkup(buttons))

async def admin_manage_user_input_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    chat_id = update.effective_chat.id
    text = sanitize_input(update.message.text)

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    if not text.isdigit():
        msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} لطفاً آیدی عددی را به صورت عدد انگلیسی وارد کنید:", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
        return ADMIN_MANAGE_USER_INPUT

    target_user_id = int(text)
    await render_user_profile_admin(context.bot, chat_id, target_user_id)
    return ConversationHandler.END

async def admin_user_action_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return
    await query.answer()

    data = query.data

    if data.startswith("usr_toggleblock_"):
        target_id = int(data.replace("usr_toggleblock_", ""))
        conn = get_db()
        try:
            user = conn.cursor().execute("SELECT is_blocked FROM users WHERE user_id = ?", (target_id,)).fetchone()
            if user:
                new_st = 0 if user['is_blocked'] == 1 else 1
                conn.cursor().execute("UPDATE users SET is_blocked = ? WHERE user_id = ?", (new_st, target_id))
                conn.commit()
        finally:
            conn.close()

        await render_user_profile_admin(context.bot, query.message.chat_id, target_id, edit_message_id=query.message.message_id)

    elif data.startswith("usr_addp_") or data.startswith("usr_subp_"):
        is_add = data.startswith("usr_addp_")
        target_id = int(data.replace("usr_addp_", "") if is_add else data.replace("usr_subp_", ""))
        context.user_data['manage_p_target'] = target_id
        context.user_data['manage_p_is_add'] = is_add

        action_name = "افزایش" if is_add else "کاهش"
        try:
            msg = await query.edit_message_text(
                f"{e('5825623013852192219')} <b>مقدار میوپوینت جهت {action_name} برای کاربر {target_id} را وارد کنید:</b>",
                parse_mode="HTML",
                reply_markup=cancel_keyboard()
            )
            context.user_data['last_bot_msg'] = msg.message_id
        except BadRequest:
            pass
        return ADMIN_MANAGE_POINT_AMOUNT

    elif data.startswith("usr_msg_"):
        target_id = int(data.replace("usr_msg_", ""))
        context.user_data['admin_msg_target'] = target_id
        try:
            msg = await query.edit_message_text(
                f"{e('5911198059676574025')} <b>پیام مستقیم برای کاربر {target_id} را وارد کنید:</b>\n"
                f"می‌توانید متن، عكس یا هر نوع مدیا ارسال کنید.",
                parse_mode="HTML",
                reply_markup=cancel_keyboard()
            )
            context.user_data['last_bot_msg'] = msg.message_id
        except BadRequest:
            pass
        return ADMIN_USER_MSG_TEXT

async def admin_process_point_amount(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    chat_id = update.effective_chat.id
    text = sanitize_input(update.message.text)

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    if not text.isdigit():
        msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} لطفاً مبلغ را فقط به عدد انگلیسی وارد کنید:", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
        return ADMIN_MANAGE_POINT_AMOUNT

    amount = int(text)
    target_id = context.user_data.get('manage_p_target')
    is_add = context.user_data.get('manage_p_is_add', True)

    conn = get_db()
    try:
        cursor = conn.cursor()
        if is_add:
            cursor.execute("UPDATE users SET points = points + ? WHERE user_id = ?", (amount, target_id))
        else:
            cursor.execute("UPDATE users SET points = MAX(0, points - ?) WHERE user_id = ?", (amount, target_id))
        conn.commit()
    finally:
        conn.close()

    act_str = "افزایش یافت" if is_add else "کاهش یافت"
    await context.bot.send_message(chat_id=chat_id, text=f"{e('5830144944399981619')} موجودی کاربر {target_id} با موفقیت به میزان {amount:,} میوپوینت {act_str}.", parse_mode="HTML")
    await render_user_profile_admin(context.bot, chat_id, target_id)
    return ConversationHandler.END

# ---------------- ADMIN BLOCK / UNBLOCK DIRECT ----------------
async def admin_block_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()
    try:
        msg = await query.edit_message_text(f"{e('5873075766748520540')} <b>آیدی عددی کاربر جهت مسدودسازی را وارد کنید:</b>", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return ADMIN_BLOCK_USER

async def admin_block_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    chat_id = update.effective_chat.id
    text = sanitize_input(update.message.text)

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    if not text.isdigit():
        msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} آیدی عددی نامعتبر است:", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
        return ADMIN_BLOCK_USER

    target_id = int(text)
    conn = get_db()
    try:
        conn.cursor().execute("UPDATE users SET is_blocked = 1 WHERE user_id = ?", (target_id,))
        conn.commit()
    finally:
        conn.close()

    await context.bot.send_message(chat_id=chat_id, text=f"{e('5873075766748520540')} کاربر {target_id} با موفقیت مسدود شد.", parse_mode="HTML", reply_markup=admin_keyboard())
    return ConversationHandler.END

async def admin_unblock_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()
    try:
        msg = await query.edit_message_text(f"{e('5830144944399981619')} <b>آیدی عددی کاربر جهت رفع مسدودی را وارد کنید:</b>", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return ADMIN_UNBLOCK_USER

async def admin_unblock_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    chat_id = update.effective_chat.id
    text = sanitize_input(update.message.text)

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    if not text.isdigit():
        msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} آیدی عددی نامعتبر است:", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
        return ADMIN_UNBLOCK_USER

    target_id = int(text)
    conn = get_db()
    try:
        conn.cursor().execute("UPDATE users SET is_blocked = 0 WHERE user_id = ?", (target_id,))
        conn.commit()
    finally:
        conn.close()

    await context.bot.send_message(chat_id=chat_id, text=f"{e('5830144944399981619')} کاربر {target_id} با موفقیت رفع مسدودی شد.", parse_mode="HTML", reply_markup=admin_keyboard())
    return ConversationHandler.END

# ---------------- ADMIN MAKE GIFT CODE ----------------
async def admin_mk_gift_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()
    try:
        msg = await query.edit_message_text(f"{e('5929398662198206659')} <b>مقدار میوپوینت کد هدیه جدید را وارد کنید:</b>", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return ADMIN_MAKE_GIFT

async def admin_mk_gift_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    chat_id = update.effective_chat.id
    text = sanitize_input(update.message.text)

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    if not text.isdigit():
        msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} لطفاً فقط عدد انگلیسی وارد کنید:", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
        return ADMIN_MAKE_GIFT

    amount = int(text)
    code = "MEOW" + str(random.randint(100000, 999999))
    today = datetime.date.today().isoformat()

    conn = get_db()
    try:
        conn.cursor().execute(
            "INSERT INTO gift_codes (code, points, is_used, created_at, creator_id) VALUES (?, ?, 0, ?, 0)",
            (code, amount, today)
        )
        conn.commit()
    finally:
        conn.close()

    await context.bot.send_message(
        chat_id=chat_id,
        text=f"{e('5830144944399981619')} <b>کد هدیه ادمین با موفقیت ساخته شد!</b>\n\n"
             f"🎫 کد هدیه: <code>{code}</code>\n"
             f"{e('5825623013852192219')} مقدار: <b>{amount:,}</b> میوپوینت",
        parse_mode="HTML",
        reply_markup=admin_keyboard()
    )
    return ConversationHandler.END

# ---------------- ADMIN DIRECT MESSAGE TO USER ----------------
async def admin_direct_msg_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != ADMIN_ID: return ConversationHandler.END
    await query.answer()
    try:
        msg = await query.edit_message_text(f"{e('5911198059676574025')} <b>آیدی عددی کاربر دریافت‌کننده پیام را وارد کنید:</b>", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
    except BadRequest:
        pass
    return ADMIN_USER_MSG

async def admin_direct_msg_user_input(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    chat_id = update.effective_chat.id
    text = sanitize_input(update.message.text)

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    if not text.isdigit():
        msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} آیدی عددی نامعتبر است:", parse_mode="HTML", reply_markup=cancel_keyboard())
        context.user_data['last_bot_msg'] = msg.message_id
        return ADMIN_USER_MSG

    context.user_data['admin_msg_target'] = int(text)
    msg = await context.bot.send_message(chat_id=chat_id, text=f"{e('5911198059676574025')} <b>پست یا پیام مورد نظر جهت ارسال به کاربر را بفرستید:</b>", parse_mode="HTML", reply_markup=cancel_keyboard())
    context.user_data['last_bot_msg'] = msg.message_id
    return ADMIN_USER_MSG_TEXT

async def admin_direct_msg_send_process(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_user.id != ADMIN_ID: return ConversationHandler.END
    chat_id = update.effective_chat.id
    target_id = context.user_data.get('admin_msg_target')

    if 'last_bot_msg' in context.user_data:
        await delete_safe(context, chat_id, context.user_data['last_bot_msg'])

    if not target_id:
        await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} مشخصات کاربر یافت نشد!", parse_mode="HTML", reply_markup=admin_keyboard())
        return ConversationHandler.END

    try:
        await context.bot.copy_message(chat_id=target_id, from_chat_id=ADMIN_ID, message_id=update.message.message_id)
        await context.bot.send_message(chat_id=chat_id, text=f"{e('5830144944399981619')} پیام با موفقیت به کاربر <code>{target_id}</code> ارسال گردید.", parse_mode="HTML", reply_markup=admin_keyboard())
    except Exception as err:
        await context.bot.send_message(chat_id=chat_id, text=f"{e('5897548735214263769')} خطا در ارسال پیام به کاربر: {escape_html(str(err))}", parse_mode="HTML", reply_markup=admin_keyboard())

    return ConversationHandler.END

# ---------------- MAIN APPLICATION SETUP ----------------
async def conversation_switch_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    context.user_data.clear()
    data = update.callback_query.data
    routes = {
        "user_start_create_gift": user_start_create_gift,
        "withdraw": withdraw_start,
        "gift_code": gift_start,
        "support": support_start,
        "admin_manage_user": admin_manage_user_start,
        "admin_block": admin_block_start,
        "admin_unblock": admin_unblock_start,
        "admin_mk_gift": admin_mk_gift_start,
        "admin_direct_msg": admin_direct_msg_start,
        "admin_bc": admin_bc_start,
        "admin_fwd": admin_fwd_start,
        "admin_add_fj": admin_add_fj_start,
        "add_fj_channel": admin_add_fj_start,
        "admin_set_ref_reward": admin_set_ref_reward_start,
        "admin_top_user": admin_top_user_start,
        "admin_daily_prize": admin_daily_prize_start,
        "admin_news_channel": admin_news_channel_start,
        "admin_reset_time": admin_reset_time_start,
        "admin_panel": admin_panel_open,
        "main_menu": button_click
    }
    handler = routes.get(data)
    if handler:
        return await handler(update, context)
    if data.startswith(("usr_addp_", "usr_subp_", "usr_msg_")):
        return await admin_user_action_callback(update, context)
    return await button_click(update, context)

def main():
    app = Application.builder().token(TOKEN).build()

    # Cancel Handlers
    cancel_btn_handler = CallbackQueryHandler(cancel_action_callback, pattern="^cancel_action$")
    switch_fallback = CallbackQueryHandler(conversation_switch_callback)

    # Conversation Handlers
    user_create_gift_conv = ConversationHandler(
        entry_points=[CallbackQueryHandler(user_start_create_gift, pattern="^user_start_create_gift$")],
        states={
            USER_CREATE_GIFT_AMOUNT: [MessageHandler(filters.TEXT & ~filters.COMMAND, user_process_create_gift)]
        },
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    withdraw_conv = ConversationHandler(
        entry_points=[CallbackQueryHandler(withdraw_start, pattern="^withdraw$")],
        states={
            WITHDRAW_AMOUNT: [MessageHandler(filters.TEXT & ~filters.COMMAND, withdraw_process)]
        },
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    gift_conv = ConversationHandler(
        entry_points=[CallbackQueryHandler(gift_start, pattern="^gift_code$")],
        states={
            GIFT_CODE_WAITING: [MessageHandler(filters.TEXT & ~filters.COMMAND, gift_process)]
        },
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    support_conv = ConversationHandler(
        entry_points=[
            CallbackQueryHandler(support_start, pattern="^support$"),
            CallbackQueryHandler(support_admin_callback, pattern="^supp_reply_")
        ],
        states={
            SUPPORT_WAITING: [MessageHandler(filters.ALL & ~filters.COMMAND, support_process)],
            ADMIN_REPLY_SUPP_INPUT: [MessageHandler(filters.ALL & ~filters.COMMAND, admin_support_send_response)]
        },
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    admin_add_fj_conv = ConversationHandler(
        entry_points=[CallbackQueryHandler(admin_add_fj_start, pattern="^add_fj_channel$")],
        states={
            ADMIN_ADD_FJ_CHAT: [MessageHandler(filters.TEXT & ~filters.COMMAND, admin_add_fj_chat_process)]
        },
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    admin_set_ref_reward_conv = ConversationHandler(
        entry_points=[CallbackQueryHandler(admin_set_ref_reward_start, pattern="^admin_set_ref_reward$")],
        states={
            ADMIN_SET_REF_REWARD: [MessageHandler(filters.TEXT & ~filters.COMMAND, admin_set_ref_reward_process)]
        },
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    admin_top_user_conv = ConversationHandler(
        entry_points=[CallbackQueryHandler(admin_top_user_start, pattern="^admin_top_user$")],
        states={ADMIN_TOP_USER: [MessageHandler(filters.TEXT & ~filters.COMMAND, admin_top_user_process)]},
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    admin_daily_prize_conv = ConversationHandler(
        entry_points=[CallbackQueryHandler(admin_daily_prize_start, pattern="^admin_daily_prize$")],
        states={ADMIN_DAILY_PRIZE: [MessageHandler(filters.TEXT & ~filters.COMMAND, admin_daily_prize_process)]},
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    admin_news_channel_conv = ConversationHandler(
        entry_points=[CallbackQueryHandler(admin_news_channel_start, pattern="^admin_news_channel$")],
        states={ADMIN_NEWS_CHANNEL: [
            MessageHandler(filters.TEXT & ~filters.COMMAND, admin_news_channel_process),
            CallbackQueryHandler(admin_news_channel_delete, pattern="^admin_news_channel_delete$")
        ]},
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    admin_reset_time_conv = ConversationHandler(
        entry_points=[CallbackQueryHandler(admin_reset_time_start, pattern="^admin_reset_time$")],
        states={ADMIN_RESET_HOUR: [CallbackQueryHandler(admin_reset_time_process, pattern="^daily_time_")]},
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    admin_bc_conv = ConversationHandler(
        entry_points=[
            CallbackQueryHandler(admin_bc_start, pattern="^admin_bc$"),
            CallbackQueryHandler(admin_fwd_start, pattern="^admin_fwd$")
        ],
        states={
            ADMIN_BC_TEXT: [MessageHandler(filters.ALL & ~filters.COMMAND, admin_broadcast_process)]
        },
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    admin_manage_user_conv = ConversationHandler(
        entry_points=[
            CallbackQueryHandler(admin_manage_user_start, pattern="^admin_manage_user$"),
            CallbackQueryHandler(admin_user_action_callback, pattern="^usr_addp_|^usr_subp_")
        ],
        states={
            ADMIN_MANAGE_USER_INPUT: [MessageHandler(filters.TEXT & ~filters.COMMAND, admin_manage_user_input_process)],
            ADMIN_MANAGE_POINT_AMOUNT: [MessageHandler(filters.TEXT & ~filters.COMMAND, admin_process_point_amount)]
        },
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    admin_block_conv = ConversationHandler(
        entry_points=[CallbackQueryHandler(admin_block_start, pattern="^admin_block$")],
        states={
            ADMIN_BLOCK_USER: [MessageHandler(filters.TEXT & ~filters.COMMAND, admin_block_process)]
        },
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    admin_unblock_conv = ConversationHandler(
        entry_points=[CallbackQueryHandler(admin_unblock_start, pattern="^admin_unblock$")],
        states={
            ADMIN_UNBLOCK_USER: [MessageHandler(filters.TEXT & ~filters.COMMAND, admin_unblock_process)]
        },
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    admin_mk_gift_conv = ConversationHandler(
        entry_points=[CallbackQueryHandler(admin_mk_gift_start, pattern="^admin_mk_gift$")],
        states={
            ADMIN_MAKE_GIFT: [MessageHandler(filters.TEXT & ~filters.COMMAND, admin_mk_gift_process)]
        },
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    admin_direct_msg_conv = ConversationHandler(
        entry_points=[
            CallbackQueryHandler(admin_direct_msg_start, pattern="^admin_direct_msg$"),
            CallbackQueryHandler(admin_user_action_callback, pattern="^usr_msg_")
        ],
        states={
            ADMIN_USER_MSG: [MessageHandler(filters.TEXT & ~filters.COMMAND, admin_direct_msg_user_input)],
            ADMIN_USER_MSG_TEXT: [MessageHandler(filters.ALL & ~filters.COMMAND, admin_direct_msg_send_process)]
        },
        fallbacks=[cancel_btn_handler, CommandHandler('start', start), switch_fallback]
    )

    # Command & Message Handlers
    app.add_handler(MessageHandler(filters.Chat(LOG_GROUP) & filters.User(OPERATOR_ID) & filters.TEXT, operator_group_handler))
    app.add_handler(MessageHandler(filters.ChatType.PRIVATE & filters.User(ADMIN_ID) & filters.REPLY, admin_reply_support))

    # Add Conversations
    app.add_handler(user_create_gift_conv)
    app.add_handler(withdraw_conv)
    app.add_handler(gift_conv)
    app.add_handler(support_conv)
    app.add_handler(admin_add_fj_conv)
    app.add_handler(admin_set_ref_reward_conv)
    app.add_handler(admin_top_user_conv)
    app.add_handler(admin_daily_prize_conv)
    app.add_handler(admin_news_channel_conv)
    app.add_handler(admin_reset_time_conv)
    app.add_handler(admin_bc_conv)
    app.add_handler(admin_manage_user_conv)
    app.add_handler(admin_block_conv)
    app.add_handler(admin_unblock_conv)
    app.add_handler(admin_mk_gift_conv)
    app.add_handler(admin_direct_msg_conv)
    app.add_handler(CommandHandler("start", start))

    # General Callbacks
    app.add_handler(CallbackQueryHandler(admin_panel_open, pattern="^admin_panel$"))
    app.add_handler(CallbackQueryHandler(admin_toggle_bot_status, pattern="^admin_toggle_bot_status$"))
    app.add_handler(CallbackQueryHandler(admin_toggle_fj, pattern="^admin_toggle_fj$"))
    app.add_handler(CallbackQueryHandler(admin_manage_fj_channels, pattern="^admin_manage_fj_channels$"))
    app.add_handler(CallbackQueryHandler(admin_delete_fj_channel, pattern="^del_fj_"))
    app.add_handler(CallbackQueryHandler(admin_stats, pattern="^admin_stats$"))
    app.add_handler(CallbackQueryHandler(admin_manage_user_gifts, pattern="^admin_manage_user_gifts$"))
    app.add_handler(CallbackQueryHandler(admin_manage_admin_gifts, pattern="^admin_manage_admin_gifts$"))
    app.add_handler(CallbackQueryHandler(admin_delete_user_gift, pattern="^del_ugift_"))
    app.add_handler(CallbackQueryHandler(admin_delete_admin_gift, pattern="^del_agift_"))
    app.add_handler(CallbackQueryHandler(admin_user_action_callback, pattern="^usr_toggleblock_"))
    app.add_handler(CallbackQueryHandler(support_admin_callback, pattern="^supp_info_"))
    app.add_handler(CallbackQueryHandler(admin_news_channel_delete, pattern="^admin_news_channel_delete$"))

    app.add_handler(CallbackQueryHandler(button_click))

    # Post Init Async Loop Tasks
    async def post_init(application: Application):
        asyncio.create_task(check_withdrawals_status_task(application))
        asyncio.create_task(auto_clear_log_task())
        asyncio.create_task(daily_reset_job(application))

    app.post_init = post_init

    logging.info("ربات میوپرانت با موفقیت روشن شد.")
    app.run_polling(drop_pending_updates=True)

if __name__ == '__main__':
    main()
