import os
import json
import time
import asyncio
import threading
import subprocess
import sys
from datetime import datetime, timedelta

from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.constants import ChatMemberStatus
from telegram.ext import (
    Application,
    ApplicationBuilder,
    ApplicationHandlerStop,
    CommandHandler,
    CallbackQueryHandler,
    MessageHandler,
    ContextTypes,
    filters,
)
import Bet
import Self

# ========= لیست ادمین‌ها =========
OWNER_ID = 6363665838
ADMINS = {6363665838 ,8348339359 ,8402242682}

# ========= تنظیمات اولیه ربات =========
TOKEN = "8354112445:AAGwk1EsYT68OXCtvcvo5TbylX4GhH6QRTI"  # توکن ربات رو اینجا بذار

# یوزرنیم کانال و گروه (ربات باید ادمین باشه)
CHANNEL_USERNAME = "@selfvidal"
GROUP_USERNAME = "@gpselfvidal"

DATA_FILE = "database.json"

# ========= لود امن دیتا (یکجا، بدون تکرار) =========
if os.path.exists(DATA_FILE) and os.path.getsize(DATA_FILE) > 0:
    try:
        with open(DATA_FILE, "r") as f:
            data = json.load(f)
            coins = data.get("coins", {})
            referrals = data.get("referrals", {})
            self_info = data.get("self_info", {})
            known_users = set(data.get("known_users", []))
            bulk_recipients = set(data.get("bulk_recipients", []))
            banned_users = data.get("banned_users", {})

    except Exception:
        coins = {}
        referrals = {}
        self_info = {}
        known_users = set()
        bulk_recipients = set()
        banned_users = {}
else:
    coins = {}
    referrals = {}
    self_info = {}


def save_data():
    data = {
        "coins": coins,
        "referrals": referrals,
        "self_info": self_info,
        "known_users": list(known_users),
        "bulk_recipients": list(bulk_recipients),
        "banned_users": banned_users,
    }
    with open(DATA_FILE, "w") as f:
        json.dump(data, f, indent=4)


###############################################
#   متغیرهای مورد نیاز
###############################################
user_state = {}
temp_data = {}
running_timers = set()

# این متغیر بعد از ساخته شدن Application ست میشه تا از Thread عادی
# بشه پیام async فرستاد (چون در نسخه‌ی جدید همه چیز async هست)
app_loop: asyncio.AbstractEventLoop | None = None
bot_application: Application | None = None


#======= کم کردن ۲ سکه هر ۲ دقیقه (در یک ترد جدا) ========
def start_coin_timer(user_id):
    """
    این تابع سینک باقی می‌مونه (روی یک Thread جدا اجرا میشه)،
    ولی برای فرستادن پیام از bot، با run_coroutine_threadsafe
    کار رو به event loop اصلی پاس میده.
    """
    uid = str(user_id)
    if uid in running_timers:
        return
    running_timers.add(uid)

    def loop():
        while True:
            time.sleep(3600)
            if not self_info.get(uid, {}).get("active"):
                running_timers.discard(uid)
                break
            if coins.get(uid, 0) <= 0:
                phone = self_info[uid]["phone"]
                Self.stop(phone)
                self_info[uid]["active"] = False
                save_data()
                _send_message_threadsafe(int(uid), "❌ سکه‌هات تموم شد، سلف خاموش شد")
                running_timers.discard(uid)
                break
            coins[uid] -= 2
            save_data()

    threading.Thread(target=loop, daemon=True).start()


def _send_message_threadsafe(chat_id, text):
    """فرستادن پیام از داخل یک Thread عادی (غیر از event loop اصلی)."""
    if bot_application is None or app_loop is None:
        return
    asyncio.run_coroutine_threadsafe(
        bot_application.bot.send_message(chat_id=chat_id, text=text), app_loop
    )


# اگر ربات ریست شد و سلف فعال بود → دوباره ران کن (بدون درخواست کد جدید)
def restore_self_sessions():
    for uid, info in self_info.items():
        if info.get("active") and info.get("phone"):
            try:
                result = Self.restore_session(info["phone"])
                print(f"SELF AUTO RESTORE FOR {info['phone']} → {result}")
                if result == "OK_SESSION":
                    start_coin_timer(uid)
            except Exception as e:
                print(f"FAILED TO AUTO RESTORE SELF FOR {info['phone']}: {e}")


#========= ساخت منوی اصلی =========
def main_menu_markup():
    btn_activate = InlineKeyboardButton("♕فعالسازی♕", callback_data="activate", style="success")
    btn_account = InlineKeyboardButton("♕حساب کاربری♕", callback_data="account", style="primary")
    btn_referral = InlineKeyboardButton("♕زیرمجموعه گیری♕", callback_data="referral", style="primary")
    btn_support = InlineKeyboardButton("♕پشتیبانی♕", callback_data="support", style="success")
    btn_rules = InlineKeyboardButton("♕قوانین♕", callback_data="rules", style="primary")
    btn_buy = InlineKeyboardButton("♕خرید سکه♕", callback_data="buy_coins", style="primary")

    return InlineKeyboardMarkup([
        [btn_activate],
        [btn_account, btn_referral],
        [btn_support],
        [btn_rules, btn_buy],
    ])


#========= دکمه بازگشت =========
def back_markup():
    btn_back = InlineKeyboardButton("🔙 بازگشت", callback_data="main_menu", style="danger")
    return InlineKeyboardMarkup([[btn_back]])


#========= تابع کمکی برای ویرایش =========
async def safe_edit(query, text, markup):
    try:
        await query.edit_message_caption(caption=text, reply_markup=markup)
    except Exception:
        await query.edit_message_text(text=text, reply_markup=markup)


#========= هندلر استارت با عضویت اجباری + جایزه زیرمجموعه =========
async def start_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
    message = update.message
    user_id = str(message.from_user.id)
    username = message.from_user.first_name
    if user_id not in known_users:
        known_users.add(user_id)
        save_data()
    # بررسی اگر کاربر با لینک دعوت اومده
    args = context.args
    if args:
        referrer_id = args[0]
        if referrer_id != user_id:
            referrals.setdefault(referrer_id, [])
            if user_id not in referrals[referrer_id]:
                referrals[referrer_id].append(user_id)
                coins[referrer_id] = coins.get(referrer_id, 0) + 10
                try:
                    await context.bot.send_message(
                        chat_id=int(referrer_id),
                        text=f"🎉 یک نفر با لینک شما عضو شد: @{message.from_user.username or username} و 10 سکه دریافت کردید!"
                    )
                except Exception:
                    pass

    # بررسی عضویت اجباری
    try:
        channel_member = await context.bot.get_chat_member(CHANNEL_USERNAME, user_id)
        group_member = await context.bot.get_chat_member(GROUP_USERNAME, user_id)
        member_ok = (
            channel_member.status != ChatMemberStatus.LEFT
            and group_member.status != ChatMemberStatus.LEFT
        )
    except Exception:
        member_ok = False

    if not member_ok:
        markup = InlineKeyboardMarkup([
            [InlineKeyboardButton("عضو کانال شو", url=f"https://t.me/{CHANNEL_USERNAME[1:]}")],
            [InlineKeyboardButton("عضو گروه شو", url=f"https://t.me/{GROUP_USERNAME[1:]}")],
            [InlineKeyboardButton("✅ عضو شدم", callback_data="check_membership")],
        ])
        await message.reply_text("لطفاً ابتدا عضو کانال و گروه شوید.", reply_markup=markup)
    else:
        panel_file_id = "AgACAgQAAxkBAAMCalrMRjoedczGM5iEU2oyr1LwULwAAvcNaxuGZ9hSz4-aBQKkVlQBAAMCAAN5AAM9BA"
        markup = main_menu_markup()
        await context.bot.send_photo(
            chat_id=message.chat.id,
            photo=panel_file_id,
            caption=f"سلام {username}👋\nبه ربات ویدال خوش اومدی 🌹",
            reply_markup=markup,
        )


#========= بررسی عضویت بعد از کلیک =========
async def check_membership(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    user_id = str(query.from_user.id)
    username = query.from_user.first_name

    try:
        channel_member = await context.bot.get_chat_member(CHANNEL_USERNAME, user_id)
        group_member = await context.bot.get_chat_member(GROUP_USERNAME, user_id)
        member_ok = (
            channel_member.status != ChatMemberStatus.LEFT
            and group_member.status != ChatMemberStatus.LEFT
        )
    except Exception:
        member_ok = False

    if member_ok:
        panel_file_id = "AgACAgQAAxkBAAMCalrMRjoedczGM5iEU2oyr1LwULwAAvcNaxuGZ9hSz4-aBQKkVlQBAAMCAAN5AAM9BA"
        markup = main_menu_markup()
        await query.edit_message_text(text="✅ عضویت شما تأیید شد!")
        await context.bot.send_photo(
            chat_id=query.message.chat.id,
            photo=panel_file_id,
            caption=f"سلام {username}👋\nبه ربات خوش اومدی 🌹",
            reply_markup=markup,
        )
    else:
        await query.answer("❌ هنوز عضو کانال و گروه نیستی!", show_alert=True)


#========= دکمه بازگشت به پنل =========
async def main_menu(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    username = query.from_user.first_name
    markup = main_menu_markup()
    panel_file_id = "AgACAgQAAxkBAAMCalrMRjoedczGM5iEU2oyr1LwULwAAvcNaxuGZ9hSz4-aBQKkVlQBAAMCAAN5AAM9BA"
    try:
        await query.message.delete()
    except Exception:
        pass
    await context.bot.send_photo(
        chat_id=query.message.chat.id,
        photo=panel_file_id,
        caption=f"سلام {username}👋\nبه ربات ویدال خوش اومدی 🌹",
        reply_markup=markup,
    )


###############################################
#                دکمه فعالسازی               #
###############################################
async def activate(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    text = (
        "برای فعالسازی 20 سکه از شما کسر میشود\n"
        "هر 1ساعت  2 سکه از سکه‌های شما کسر میشود"
    )
    markup = InlineKeyboardMarkup([
        [InlineKeyboardButton("⟐ فعالسازی با 20 سکه ⟐", callback_data="activate_with_coin", style="success")],
        [InlineKeyboardButton("🔙 بازگشت", callback_data="main_menu", style="danger")],
    ])
    await safe_edit(query, text, markup)


###############################################
#        کلیک روی «فعالسازی با 20 سکه»       #
###############################################
async def activate_with_coin(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    user_id = str(query.from_user.id)

    if coins.get(user_id, 0) < 20:
        await query.answer("❌ سکه کافی نیست", show_alert=True)
        return

    coins[user_id] -= 20
    save_data()

    user_state[user_id] = "get_phone"

    await safe_edit(query, "●شماره‌تو با + بفرست (مثال: +989123456789)●", back_markup())


###############################################
#               دریافت شماره (فقط PV)        #
###############################################
async def get_phone(update: Update, context: ContextTypes.DEFAULT_TYPE):
    message = update.message
    user_id = str(message.from_user.id)
    phone = message.text.strip()

    if not phone.startswith("+"):
        await message.reply_text("❌ شماره باید با + شروع بشه")
        return

    temp_data[user_id] = {"phone": phone}

    await message.reply_text("●در حال ارسال کد●")

    # توجه: اگر Self.login سینک/بلاک‌کننده هست، بهتره با
    # asyncio.to_thread اجرا بشه تا event loop قفل نشه.
    result = await asyncio.to_thread(Self.login, phone)

    if result == "CODE_SENT":
        user_state[user_id] = "get_code"
        await message.reply_text("●کد را به صورت 1.2.3.4.5 بفرست●")
    elif result in ("OK", "OK_SESSION"):
        self_info[user_id] = {"phone": phone, "active": True}
        save_data()
        start_coin_timer(user_id)
        await message.reply_text("●سلف فعال شد●")
        user_state.pop(user_id, None)
        temp_data.pop(user_id, None)
    else:
        await message.reply_text(f"❌ خطا: {result}")
        user_state.pop(user_id, None)
        temp_data.pop(user_id, None)


###############################################
#                 دریافت کد (فقط PV)         #
###############################################
async def get_code(update: Update, context: ContextTypes.DEFAULT_TYPE):
    message = update.message
    user_id = str(message.from_user.id)
    code = message.text.strip()
    phone = temp_data[user_id]["phone"]

    temp_data[user_id]["code"] = code

    result = await asyncio.to_thread(Self.login, phone, code)

    if result == "INVALID_CODE":
        await message.reply_text("❌ کد اشتباهه")
        return

    if result == "NEED_PASSWORD":
        user_state[user_id] = "get_password"
        await message.reply_text("●رمز دومرحله‌ای را بفرست●")
        return

    if result in ("OK", "OK_SESSION"):
        self_info[user_id] = {"phone": phone, "active": True}
        save_data()
        start_coin_timer(user_id)
        await message.reply_text("●سلف فعال شد●")
        user_state.pop(user_id, None)
        temp_data.pop(user_id, None)
    else:
        await message.reply_text(f"❌ خطا: {result}")
        user_state.pop(user_id, None)
        temp_data.pop(user_id, None)


###############################################
#           دریافت رمز دومرحله‌ای (PV)       #
###############################################
async def get_password(update: Update, context: ContextTypes.DEFAULT_TYPE):
    message = update.message
    user_id = str(message.from_user.id)
    password = message.text.strip()

    phone = temp_data[user_id]["phone"]

    result = await asyncio.to_thread(Self.login_2fa, phone, password)

    if result == "INVALID_PASSWORD":
        await message.reply_text("❌ رمز اشتباهه")
        return

    if result in ("OK", "OK_SESSION"):
        self_info[user_id] = {"phone": phone, "active": True}
        save_data()
        start_coin_timer(user_id)
        await message.reply_text("●سلف فعال شد●")
        user_state.pop(user_id, None)
        temp_data.pop(user_id, None)
    else:
        await message.reply_text(f"❌ خطا: {result}")
        user_state.pop(user_id, None)
        temp_data.pop(user_id, None)


#========= دکمه حساب کاربری =========
async def account_info(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    user = query.from_user
    user_id = str(user.id)
    username = f"@{user.username}" if user.username else user.first_name
    balance = coins.get(user_id, 0)
    toman_value = balance * 30
    num_referrals = len(referrals.get(user_id, []))
    markup = back_markup()
    text = f"""༒𝙎𝙀𝙇𝙁 𝙑𝙞𝙙𝙖𝙡༒
اطلاعات حساب شما :
-◈ آیدی : {username}
-◈ آیدی عددی : {user_id}
-◈ موجودی سکه : {balance} سکه
-◈ معادل تومانی : {toman_value:,} تومان
-◈ تعداد زیر مجموعه : {num_referrals}
☬━━━𝙎𝙀𝙇𝙁 𝙑𝙞𝙙𝙖𝙡━━━☬"""
    await safe_edit(query, text, markup)


#========= دکمه پشتیبانی =========
async def support_info(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    markup = back_markup()
    text = """پشتیبانی :
@Vahab0ne"""
    await safe_edit(query, text, markup)


#========= دکمه قوانین =========
async def rules_info(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    markup = back_markup()
    text = """قوانین :
-◈ فقط از مالک و ادمین ها سکه بخرید
-◈ زیر مجموعه فیک نزنید
-◈ فروش زیر 30 تومن = بن"""
    await safe_edit(query, text, markup)


#========= دکمه زیرمجموعه گیری =========
async def referral_info(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    user_id = str(query.from_user.id)
    referral_link = f"https://t.me/testSelfvidalbot?start={user_id}"
    markup = back_markup()
    text = f"""زیرمجموعه گیری :
-◈ لینک شما » {referral_link}
-◈ با هر دعوت 10 سکه دریافت میکنید"""
    await safe_edit(query, text, markup)


#========= دکمه خرید سکه =========
async def buy_coins_info(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    markup = back_markup()
    text = """خرید سکه :
-◈ برای خرید سکه به این آیدی ها پیام بدین :
@Vahab0ne
-◈ هر هزار سکه 30 هزار تومان است"""
    await safe_edit(query, text, markup)


# ========= چک کردن موجودی کاربر فقط توسط ادمین =========
async def check_user_balance(update: Update, context: ContextTypes.DEFAULT_TYPE):
    message = update.message
    if message.from_user.id not in ADMINS:
        return

    target = message.reply_to_message.from_user
    target_id = str(target.id)
    username = f"@{target.username}" if target.username else target.first_name

    balance = coins.get(target_id, 0)
    toman_value = balance * 30

    await message.reply_text(
        f"༒𝙎𝙀𝙇𝙁 𝙑𝙞𝙙𝙖𝙡༒\n"
        f"-𝙎𝙀𝙇𝙁◈آیدی : {username}\n"
        f"-𝙎𝙀𝙇𝙁◈آیدی عددی : {target_id}\n"
        f"-𝙎𝙀𝙇𝙁◈موجودی سکه : {balance} سکه\n"
        f"-𝙎𝙀𝙇𝙁◈معادل تومانی : {toman_value:,} تومان\n"
        f"☬━━━𝙎𝙀𝙇𝙁 𝙑𝙞𝙙𝙖𝙡━━━☬"
    )


# ========= هندلر موجودی با دکمه‌های آبی =========
async def check_balance(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user_id = str(update.effective_user.id)

    balance = coins.get(user_id, 0)
    tomans = balance * 30

    keyboard = [
        [
            InlineKeyboardButton(
                text=f" {balance} سکه",
                callback_data="noop",
                style="primary"
            )
        ],
        [
            InlineKeyboardButton(
                text=f" {tomans:,} تومان",
                callback_data="noop",
                style="danger"
            )
        ]
    ]

    markup = InlineKeyboardMarkup(keyboard)

    await update.message.reply_text(
        "💎 موجودی شما:",
        reply_markup=markup
    )


# ========= افزودن سکه توسط ادمین =========
async def add_coins(update: Update, context: ContextTypes.DEFAULT_TYPE):
    message = update.message
    parts = message.text.split()

    if len(parts) != 3:
        return

    try:
        amount = int(parts[2])
    except ValueError:
        return

    # باید روی پیام کاربر ریپلای کند
    if not message.reply_to_message:
        await message.reply_text("❌ باید روی پیام کاربر ریپلای کنید")
        return

    # چک ادمین
    if message.from_user.id not in ADMINS:
        await message.reply_text("❌ شما ادمین نیستید")
        return

    # اطلاعات کاربر هدف
    target_user = message.reply_to_message.from_user
    target_id = str(target_user.id)

    # افزودن سکه واقعی
    coins[target_id] = coins.get(target_id, 0) + amount
    save_data()

    admin_id = str(message.from_user.id)

    # دکمه‌های شیشه‌ای رنگی دو ردیفی
    keyboard = [
        [
            InlineKeyboardButton(
                text=f"{amount} سکه",
                callback_data="noop",
                style="primary"   # دکمه اول آبی
            ),
            InlineKeyboardButton(
                text="سکه",
                callback_data="noop",
                style="success"   # دکمه دوم سبز
            )
        ],
        [
            InlineKeyboardButton(
                text=f"{admin_id}",
                callback_data="noop",
                style="primary"   # دکمه سوم آبی
            ),
            InlineKeyboardButton(
                text="ادمین",
                callback_data="noop",
                style="success"   # دکمه چهارم سبز
            )
        ],
        [
            InlineKeyboardButton(
                text=f"{target_id}",
                callback_data="noop",
                style="primary"   # دکمه پنجم آبی
            ),
            InlineKeyboardButton(
                text="کاربر",
                callback_data="noop",
                style="success"   # دکمه ششم سبز
            )
        ]
    ]

    markup = InlineKeyboardMarkup(keyboard)

    await message.reply_text(
        "✔️ سکه اضافه شد",
        reply_markup=markup
    )


# ---------- کسر سکه ----------
async def subtract_coins(update: Update, context: ContextTypes.DEFAULT_TYPE):
    message = update.message
    parts = message.text.split()

    if len(parts) != 3:
        return

    try:
        amount = int(parts[2])
    except ValueError:
        return

    # باید روی پیام کاربر ریپلای کند
    if not message.reply_to_message:
        await message.reply_text("❌ باید روی پیام کاربر ریپلای کنید")
        return

    # چک ادمین
    if message.from_user.id not in ADMINS:
        await message.reply_text("❌ شما ادمین نیستید")
        return

    # اطلاعات کاربر هدف
    target_user = message.reply_to_message.from_user
    target_id = str(target_user.id)

    # موجودی واقعی کاربر
    current_balance = coins.get(target_id, 0)
    if current_balance < amount:
        await message.reply_text("❌ موجودی کاربر کافی نیست")
        return

    # کسر واقعی
    coins[target_id] = current_balance - amount
    save_data()

    admin_id = str(message.from_user.id)

    # دکمه‌های شیشه‌ای رنگی دو ردیفی
    keyboard = [
        [
            InlineKeyboardButton(
                text=f"{amount} سکه",
                callback_data="noop",
                style="primary"   # دکمه اول آبی
            ),
            InlineKeyboardButton(
                text="سکه",
                callback_data="noop",
                style="success"   # دکمه دوم سبز
            )
        ],
        [
            InlineKeyboardButton(
                text=f"{admin_id}",
                callback_data="noop",
                style="primary"   # دکمه سوم آبی
            ),
            InlineKeyboardButton(
                text="ادمین",
                callback_data="noop",
                style="success"   # دکمه چهارم سبز
            )
        ],
        [
            InlineKeyboardButton(
                text=f"{target_id}",
                callback_data="noop",
                style="primary"   # دکمه پنجم آبی
            ),
            InlineKeyboardButton(
                text="کاربر",
                callback_data="noop",
                style="success"   # دکمه ششم سبز
            )
        ]
    ]

    markup = InlineKeyboardMarkup(keyboard)

    await message.reply_text(
        "✔️ سکه کسر شد",
        reply_markup=markup
    )


# ---------- انتقال سکه ----------
async def transfer_done(update: Update, context: ContextTypes.DEFAULT_TYPE):
    message = update.message

    # باید روی پیام کاربر گیرنده ریپلای کند
    if not message.reply_to_message:
        await message.reply_text("❌ باید روی پیام کاربر گیرنده ریپلای کنید")
        return

    sender_id = str(message.from_user.id)
    receiver = message.reply_to_message.from_user
    receiver_id = str(receiver.id)

    # جلوگیری از انتقال به خود
    if sender_id == receiver_id:
        await message.reply_text("❌ نمی‌توانی به خودت سکه منتقل کنی")
        return

    # گرفتن مقدار از پیام کاربر: انتقال سکه 200
    parts = message.text.split()
    if len(parts) != 3:
        await message.reply_text("❌ فرمت درست: انتقال سکه <تعداد>")
        return

    try:
        amount = int(parts[2])
    except:
        await message.reply_text("❌ مقدار باید عدد باشد")
        return

    if amount <= 0:
        await message.reply_text("❌ مقدار باید بیشتر از صفر باشد")
        return

    # موجودی واقعی فرستنده
    sender_balance = coins.get(sender_id, 0)

    tax = 10
    total_cost = amount + tax

    # اگر موجودی کافی نبود
    if sender_balance < total_cost:
        await message.reply_text(f"❌ موجودی کافی نیست (نیاز: {total_cost} سکه)")
        return

    # کم کردن از فرستنده
    coins[sender_id] = sender_balance - total_cost

    # اضافه کردن به گیرنده
    receiver_balance = coins.get(receiver_id, 0)
    coins[receiver_id] = receiver_balance + amount

    # ذخیره دیتابیس
    save_data()

    # دکمه‌های شیشه‌ای رنگی دو ردیفی
    keyboard = [
        [
            InlineKeyboardButton(
                text=f"{amount} سکه",
                callback_data="noop",
                style="primary"   # دکمه اول آبی
            ),
            InlineKeyboardButton(
                text="سکه",
                callback_data="noop",
                style="success"   # دکمه دوم سبز
            )
        ],
        [
            InlineKeyboardButton(
                text=f"{tax} سکه",
                callback_data="noop",
                style="primary"   # دکمه سوم آبی
            ),
            InlineKeyboardButton(
                text="مالیات",
                callback_data="noop",
                style="success"   # دکمه چهارم سبز
            )
        ],
        [
            InlineKeyboardButton(
                text=f"{receiver_id}",
                callback_data="noop",
                style="primary"   # دکمه پنجم آبی
            ),
            InlineKeyboardButton(
                text="کاربر",
                callback_data="noop",
                style="success"   # دکمه ششم سبز
            )
        ]
    ]

    markup = InlineKeyboardMarkup(keyboard)

    await message.reply_text(
        "✔️ سکه انتقال داده شد",
        reply_markup=markup
    )
def get_all_known_user_ids():
    """
    ترکیب known_users با کلیدهای coins، چون کاربرهای قدیمی که قبل از
    اضافه شدن قابلیت known_users با ربات کار کرده بودن، فقط توی coins
    ثبت شدن نه known_users (مگر اینکه دوباره /start بزنن).
    """
    all_ids = set(known_users) | set(coins.keys())
    if all_ids - known_users:
        known_users.update(all_ids)
        save_data()
    return all_ids

###############################################
#      افزایش سکه کلی (فقط مالک - نه ادمین‌ها)   #
###############################################
async def bulk_increase_prompt(update: Update, context: ContextTypes.DEFAULT_TYPE):
    message = update.message
    if message.from_user.id != OWNER_ID:
        return

    parts = message.text.split()
    if len(parts) != 4:
        return

    try:
        amount = int(parts[3])
    except ValueError:
        return

    if amount <= 0:
        return

    markup = InlineKeyboardMarkup([
        [
            InlineKeyboardButton("همه‌ی کاربران", callback_data=f"bulkall_{amount}", style="primary"),
            InlineKeyboardButton("کاربران جدید", callback_data=f"bulknew_{amount}", style="success"),
        ]
    ])

    await message.reply_text("لطفاً کاربران مورد نظر را انتخاب کنید", reply_markup=markup)


async def bulk_all_users(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != OWNER_ID:
        await query.answer("❌ فقط مالک می‌تواند این کار را انجام دهد", show_alert=True)
        return

    try:
        amount = int(query.data.split("_")[1])
    except (IndexError, ValueError):
        await query.answer("خطای داخلی", show_alert=True)
        return

    count = 0
    for uid in get_all_known_user_ids():
        coins[uid] = coins.get(uid, 0) + amount
        bulk_recipients.add(uid)
        count += 1
    save_data()

    await query.answer()

    result_markup = InlineKeyboardMarkup([
        [
            InlineKeyboardButton("سکه", callback_data="noop", style="success"),
            InlineKeyboardButton(f"{amount} سکه", callback_data="noop", style="success"),
        ],
        [
            InlineKeyboardButton("تعداد کاربر", callback_data="noop", style="success"),
            InlineKeyboardButton(f"{count}", callback_data="noop", style="success"),
        ],
    ])

    await query.edit_message_text("تراکنش:", reply_markup=result_markup)


async def bulk_new_users(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    if query.from_user.id != OWNER_ID:
        await query.answer("❌ فقط مالک می‌تواند این کار را انجام دهد", show_alert=True)
        return

    try:
        amount = int(query.data.split("_")[1])
    except (IndexError, ValueError):
        await query.answer("خطای داخلی", show_alert=True)
        return

    target_users = get_all_known_user_ids() - bulk_recipients

    count = 0
    for uid in target_users:
        coins[uid] = coins.get(uid, 0) + amount
        bulk_recipients.add(uid)
        count += 1
    save_data()

    await query.answer()

    result_markup = InlineKeyboardMarkup([
        [
            InlineKeyboardButton("سکه", callback_data="noop", style="success"),
            InlineKeyboardButton(f"{amount} سکه", callback_data="noop", style="success"),
        ],
        [
            InlineKeyboardButton("تعداد کاربر", callback_data="noop", style="success"),
            InlineKeyboardButton(f"{count}", callback_data="noop", style="success"),
        ],
    ])

    await query.edit_message_text("تراکنش:", reply_markup=result_markup)
###############################################
#           قابلیت بن کاربر (ادمین/مالک)       #
###############################################
async def resolve_target_id(message, context):
    """
    کاربر هدف رو از سه راه پیدا می‌کنه: ریپلای، آیدی عددی، یا یوزرنیم (@username)
    """
    if message.reply_to_message:
        return str(message.reply_to_message.from_user.id)

    parts = message.text.split()
    if len(parts) < 3:
        return None

    token = parts[2].strip()

    if token.isdigit():
        return token

    username = token if token.startswith("@") else f"@{token}"
    try:
        chat = await context.bot.get_chat(username)
        return str(chat.id)
    except Exception:
        return None
async def ban_user(update: Update, context: ContextTypes.DEFAULT_TYPE):
    message = update.message

    if message.from_user.id not in ADMINS and message.from_user.id != OWNER_ID:
        return

    parts = message.text.split()
    if len(parts) not in (2, 3):
        return

    try:
        days = int(parts[1])
    except ValueError:
        return

    if days <= 0:
        return

    target_id = await resolve_target_id(message, context)
    if not target_id:
        await message.reply_text("❌ کاربر پیدا نشد؛ ریپلای کنید یا آیدی عددی/یوزرنیم درست بدید")
        return

    ban_until = datetime.now() + timedelta(days=days)
    banned_users[target_id] = ban_until.isoformat()
    save_data()

    markup = InlineKeyboardMarkup([
        [
            InlineKeyboardButton("کاربر", callback_data="noop", style="danger"),
            InlineKeyboardButton(target_id, callback_data="noop", style="danger"),
        ],
        [
            InlineKeyboardButton("ادمین", callback_data="noop", style="danger"),
            InlineKeyboardButton(str(message.from_user.id), callback_data="noop", style="danger"),
        ],
        [
            InlineKeyboardButton("تاریخ", callback_data="noop", style="danger"),
            InlineKeyboardButton(ban_until.strftime("%Y-%m-%d %H:%M"), callback_data="noop", style="danger"),
        ],
    ])

    await message.reply_text("=== SELF Vidal ===\nکاربر بن شد:", reply_markup=markup)
async def unban_user(update: Update, context: ContextTypes.DEFAULT_TYPE):
    message = update.message

    if message.from_user.id not in ADMINS and message.from_user.id != OWNER_ID:
        return

    target_id = await resolve_target_id(message, context)
    if not target_id:
        await message.reply_text("❌ کاربر پیدا نشد؛ ریپلای کنید یا آیدی عددی/یوزرنیم درست بدید")
        return

    if target_id not in banned_users:
        await message.reply_text("❌ این کاربر بن نیست")
        return

    banned_users.pop(target_id, None)
    save_data()

    markup = InlineKeyboardMarkup([
        [
            InlineKeyboardButton("کاربر", callback_data="noop", style="success"),
            InlineKeyboardButton(target_id, callback_data="noop", style="success"),
        ],
        [
            InlineKeyboardButton("ادمین", callback_data="noop", style="success"),
            InlineKeyboardButton(str(message.from_user.id), callback_data="noop", style="success"),
        ],
    ])

    await message.reply_text("=== SELF Vidal ===\nبن کاربر حذف شد:", reply_markup=markup)

async def check_ban(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.message is None or update.message.from_user is None:
        return

    user_id = str(update.message.from_user.id)
    ban_iso = banned_users.get(user_id)
    if not ban_iso:
        return

    ban_until = datetime.fromisoformat(ban_iso)
    now = datetime.now()

    if now >= ban_until:
        banned_users.pop(user_id, None)
        save_data()
        return

    remaining_days = (ban_until - now).days + 1

    # فقط توی پیوی جواب بده؛ توی گروه کاملاً سکوت کن
    if update.message.chat.type == "private":
        await update.message.reply_text(
            f"شما تا {remaining_days} روز بن شده‌اید\n"
            f"روز‌های باقی‌مانده: {remaining_days}"
        )

    raise ApplicationHandlerStop

###############################################
#          فیلترهای سفارشی برای user_state    #
###############################################
class StateFilter(filters.MessageFilter):
    """فیلتر سفارشی که چک می‌کنه کاربر توی چه مرحله‌ای هست
    (جایگزین filters.create که در نسخه‌های جدید حذف شده)."""

    def __init__(self, state: str):
        self.state = state
        super().__init__()

    def filter(self, message):
        return user_state.get(str(message.from_user.id)) == self.state


get_phone_filter = StateFilter("get_phone")
get_code_filter = StateFilter("get_code")
get_password_filter = StateFilter("get_password")


###############################################
#            راه‌اندازی نهایی ربات            #
###############################################
async def post_init(application: Application):
    """بعد از ساخته شدن اپلیکیشن، loop و instance رو ذخیره می‌کنیم
    و سلف‌های فعال قبلی رو ریستور می‌کنیم."""
    global app_loop, bot_application
    app_loop = asyncio.get_running_loop()
    bot_application = application
    restore_self_sessions()

import logging
logging.basicConfig(level=logging.INFO)

async def error_handler(update, context):
    logging.error("Exception while handling an update:", exc_info=context.error)

def main():
    if not TOKEN:
        raise SystemExit("❌ TOKEN خالیه، اول توکن ربات رو ست کن.")

    application = ApplicationBuilder().token(TOKEN).post_init(post_init).build()

    # --- کامندها ---
    application.add_handler(CommandHandler("start", start_message))

    # --- کالبک‌ها ---
    application.add_handler(CallbackQueryHandler(check_membership, pattern="^check_membership$"))
    application.add_handler(CallbackQueryHandler(main_menu, pattern="^main_menu$"))
    application.add_handler(CallbackQueryHandler(activate, pattern="^activate$"))
    application.add_handler(CallbackQueryHandler(activate_with_coin, pattern="^activate_with_coin$"))
    application.add_handler(CallbackQueryHandler(account_info, pattern="^account$"))
    application.add_handler(CallbackQueryHandler(support_info, pattern="^support$"))
    application.add_handler(CallbackQueryHandler(rules_info, pattern="^rules$"))
    application.add_handler(CallbackQueryHandler(referral_info, pattern="^referral$"))
    application.add_handler(CallbackQueryHandler(buy_coins_info, pattern="^buy_coins$"))
    application.add_handler(CallbackQueryHandler(bulk_all_users, pattern=r"^bulkall_"))
    application.add_handler(CallbackQueryHandler(bulk_new_users, pattern=r"^bulknew_"))

    # --- مراحل فعالسازی (فقط پیوی) ---
    application.add_handler(MessageHandler(
        filters.ChatType.PRIVATE & filters.TEXT & get_phone_filter,
        get_phone,
    ))
    application.add_handler(MessageHandler(
        filters.ChatType.PRIVATE & filters.TEXT & get_code_filter,
        get_code,
    ))
    application.add_handler(MessageHandler(
        filters.ChatType.PRIVATE & filters.TEXT & get_password_filter,
        get_password,
    ))

    # --- دستورات متنی مدیریتی ---
    application.add_handler(MessageHandler(
        filters.TEXT & filters.REPLY & filters.Regex(r"^موجودی کاربر$"),
        check_user_balance,
    ))
    application.add_handler(MessageHandler(filters.Regex(r"^موجودی$"), check_balance))
    application.add_handler(MessageHandler(filters.Regex(r"^افزودن سکه \d+$"), add_coins))
    application.add_handler(MessageHandler(filters.Regex(r"^کسر سکه \d+$"), subtract_coins))
    application.add_handler(MessageHandler(filters.Regex(r"^انتقال سکه \d+$"), transfer_done))
    application.add_handler(MessageHandler(filters.Regex(r"^افزایش سکه کلی"), bulk_increase_prompt))
    application.add_handler(MessageHandler(filters.ALL, check_ban), group=-1)
    application.add_handler(MessageHandler(filters.Regex(r"^بن\s+\d+"), ban_user))
    application.add_handler(MessageHandler(filters.Regex(r"^حذف\s+بن"), unban_user))

    application.add_error_handler(error_handler)
    # --- ماژول‌های دیگه (Bet.py هم باید async بشه) ---
    Bet.register_bet_handlers(application, coins, save_data)
    Bet.register_rps_handlers(application, coins, save_data)
    Bet.register_dice_handlers(application, coins, save_data)

    # اجرای Helper.py به صورت جدا
    threading.Thread(
        target=lambda: subprocess.run([sys.executable, "Helper.py"]),
        daemon=True,
    ).start()

    print("🤖 VidalBot started...")
    application.run_polling()


if __name__ == "__main__":
    main()