import os
import re
import html
import sys
sys.stdout.reconfigure(encoding='utf-8')
import sqlite3
import logging

logging.basicConfig(level=logging.ERROR)

# لاگ‌های اضافی کتابخونه‌ها رو هم کم کن
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("telegram").setLevel(logging.ERROR)
from datetime import datetime, date

import jdatetime
import requests
from dotenv import load_dotenv
from telegram import (
    Update,
    ReplyKeyboardMarkup,
    InlineKeyboardMarkup,
    InlineKeyboardButton,
)
from telegram.constants import ParseMode, ChatMemberStatus
from telegram.ext import (
    Application,
    CommandHandler,
    MessageHandler,
    CallbackQueryHandler,
    ContextTypes,
    filters,
)

from deposit_handlers import DepositManager
from sharz import SharzManager


load_dotenv()

BOT_TOKEN = os.getenv("BOT_TOKEN", "8824655958:AAEhAriH36sB2aW5wpk0MDfLB_9UlsIVUIM").strip()
OWNER_ID = int(os.getenv("OWNER_ID", "7961417575"))
OWNER_ID_2 = int(os.getenv("OWNER_ID_2", "1462327991"))
OWNER_IDS = {OWNER_ID, OWNER_ID_2}

REPORT_CHANNEL_ID = int(os.getenv("REPORT_CHANNEL_ID", "-1003785220969"))

SUPPORT_USERNAME = os.getenv("SUPPORT_USERNAME", "King_VPN1_Bof").replace("@", "King_VPN1_Bof").strip()
DB_NAME = os.getenv("DB_NAME", "bot.db").strip()

TRONSCAN_API_KEY = os.getenv("TRONSCAN_API_KEY", "").strip() or "PUT_YOUR_TRONSCAN_API_KEY_HERE"
NOBITEX_API_KEY = os.getenv("NOBITEX_API_KEY", "8116082002:mwrz6ytgvFSNPha@Api_ManagerRoBot").strip() or "PUT_YOUR_NOBITEX_API_KEY_HERE"

TRON_WALLET_ADDRESS = os.getenv("TRON_WALLET_ADDRESS", "TTx7iZCVALgPddVFCUaNupsTNL3ntN1xBa").strip()
TON_WALLET_ADDRESS = os.getenv("TON_WALLET_ADDRESS", "UQA2an6AsbuoWbR4nIqPjPKPceihZpnK7WlIC-BdgeYxfHw5").strip()

REQUEST_TIMEOUT = 20

# =========================================================
# پرمیوم ایموجی‌ها
# =========================================================
P_BUY = "5312361253610475399"
P_CARD = "5445353829304387411"
P_SUPPORT = "5789918778921850035"
P_ACCOUNT = "5296369303661067030"
P_HELP = "5444856076954520455"
P_CROWN = "5217822164362739968"

P_EYE = "5792131172410594168"
P_LINK = "5271604874419647061"
P_X = "4994791839895651680"
P_WARN = "4996823372311561500"

P_COIN = "6032713293049633080"
P_MONEY = "5965097893491642896"

# 👇 ایموجی اختصاصی ترون (مهم)
P_TRX = "5312361253610475399"

P_DIAMOND = "6032952342339395168"
P_MAIL = "5013050643519112149"
P_FIRE = "5424972470023104089"
P_PIN = "5397782960512444700"
P_PLUS = "5397916757333654639"
P_OK = "4997091399745668102"
P_LEAF = "5870778972857438051"
P_BACK = "5816717549487788887"

# 🔥 اپراتورها
P_MCI = "5965297742614894172"
P_IRANCELL = "5963110689433195255"
P_RIGHTEL = "5965519088049460281"
P_CHECK = "5206607081334906820"


def pemoji(emoji_id: str, fallback: str) -> str:
    return f"<tg-emoji emoji-id='{emoji_id}'>{fallback}</tg-emoji>"


def make_btn(text: str, callback_data: str = None, emoji_id: str = None, style: str = "primary", url: str = None):
    kwargs = {}

    if callback_data:
        kwargs["callback_data"] = callback_data

    if url:
        kwargs["url"] = url

    if emoji_id:
        kwargs["api_kwargs"] = {
            "icon_custom_emoji_id": emoji_id,
            "style": style,
        }

    return InlineKeyboardButton(text=text, **kwargs)


if not BOT_TOKEN:
    raise ValueError("BOT_TOKEN تنظیم نشده.")
if not OWNER_IDS:
    raise ValueError("OWNER_IDS تنظیم نشده.")
if not REPORT_CHANNEL_ID:
    raise ValueError("REPORT_CHANNEL_ID تنظیم نشده.")

logging.basicConfig(
    format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
    level=logging.INFO
)
logger = logging.getLogger(__name__)

http = requests.Session()
http.headers.update({
    "User-Agent": "Mozilla/5.0",
    "Accept": "application/json",
})


conn = sqlite3.connect(DB_NAME, check_same_thread=False, timeout=30)
conn.execute("PRAGMA journal_mode=WAL")
conn.execute("PRAGMA busy_timeout=30000")
conn.row_factory = sqlite3.Row
cur = conn.cursor()

cur.execute("""
CREATE TABLE IF NOT EXISTS users (
    user_id INTEGER PRIMARY KEY,
    username TEXT,
    first_name TEXT,
    joined_at TEXT,
    balance INTEGER DEFAULT 0,
    is_blocked INTEGER DEFAULT 0,
    blocked_reason TEXT DEFAULT '',
    forced_join_msg_id INTEGER DEFAULT NULL
)
""")

try:
    cur.execute("ALTER TABLE users ADD COLUMN bot_blocked INTEGER DEFAULT 0")
except Exception:
    pass

cur.execute("""
CREATE TABLE IF NOT EXISTS admins (
    user_id INTEGER PRIMARY KEY,
    added_by INTEGER,
    added_at TEXT
)
""")

cur.execute("""
CREATE TABLE IF NOT EXISTS transactions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    admin_id INTEGER NOT NULL,
    amount INTEGER NOT NULL,
    type TEXT NOT NULL,
    created_at TEXT NOT NULL,
    description TEXT DEFAULT ''
)
""")

cur.execute("""
CREATE TABLE IF NOT EXISTS settings (
    key TEXT PRIMARY KEY,
    value TEXT
)
""")

cur.execute("""
CREATE TABLE IF NOT EXISTS orders (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    operator TEXT NOT NULL,
    amount INTEGER NOT NULL,
    created_at TEXT NOT NULL
)
""")

cur.execute("""
CREATE TABLE IF NOT EXISTS used_tron_hashes (
    tx_hash TEXT PRIMARY KEY,
    user_id INTEGER NOT NULL,
    trx_amount TEXT NOT NULL,
    rate_irt INTEGER NOT NULL,
    charged_amount INTEGER NOT NULL,
    created_at TEXT NOT NULL
)
""")

cur.execute("""
CREATE TABLE IF NOT EXISTS pending_ton_hashes (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    username TEXT,
    first_name TEXT,
    tx_hash TEXT NOT NULL,
    status TEXT NOT NULL DEFAULT 'pending',
    reviewed_by INTEGER DEFAULT NULL,
    created_at TEXT NOT NULL,
    reviewed_at TEXT DEFAULT NULL
)
""")

cur.execute("""
CREATE TABLE IF NOT EXISTS ton_hash_notifications (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    pending_id INTEGER NOT NULL,
    target_chat_id INTEGER NOT NULL,
    message_id INTEGER NOT NULL,
    created_at TEXT NOT NULL
)
""")

conn.commit()


WEEKDAY_MAP = {
    "Saturday": "شنبه",
    "Sunday": "یکشنبه",
    "Monday": "دوشنبه",
    "Tuesday": "سه‌شنبه",
    "Wednesday": "چهارشنبه",
    "Thursday": "پنجشنبه",
    "Friday": "جمعه",
}


def now_gregorian_str() -> str:
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")


def jalali_datetime_str() -> str:
    now = jdatetime.datetime.now()
    return f"{now.year:04d}/{now.month:02d}/{now.day:02d} {now.hour:02d}:{now.minute:02d}:{now.second:02d}"


def jalali_date_str() -> str:
    now = jdatetime.datetime.now()
    return f"{now.year}/{now.month}/{now.day}"


def jalali_time_str() -> str:
    now = jdatetime.datetime.now()
    return f"{now.hour:02d}:{now.minute:02d}:{now.second:02d}"


def persian_weekday_today() -> str:
    return WEEKDAY_MAP.get(datetime.now().strftime("%A"), datetime.now().strftime("%A"))


def gregorian_to_jalali_date_str(dt_str: str) -> str:
    try:
        dt = datetime.strptime(dt_str, "%Y-%m-%d %H:%M:%S")
        jdt = jdatetime.datetime.fromgregorian(datetime=dt)
        return f"{jdt.year}/{jdt.month}/{jdt.day}"
    except Exception:
        return "نامشخص"


def gregorian_to_jalali_datetime_str(dt_str: str) -> str:
    try:
        dt = datetime.strptime(dt_str, "%Y-%m-%d %H:%M:%S")
        jdt = jdatetime.datetime.fromgregorian(datetime=dt)
        return f"{jdt.hour:02d}:{jdt.minute:02d}:{jdt.second:02d}-{jdt.year}/{jdt.month:02d}/{jdt.day:02d}"
    except Exception:
        return "نامشخص"


def days_since(joined_at: str) -> int:
    try:
        dt = datetime.strptime(joined_at, "%Y-%m-%d %H:%M:%S").date()
        return (date.today() - dt).days
    except Exception:
        return 0


def esc(text: str) -> str:
    return html.escape(str(text or ""))


def format_username(username: str | None) -> str:
    if not username or username == "ندارد":
        return "ندارد"
    return username if username.startswith("@") else f"@{username}"


def format_money(value) -> str:
    try:
        return f"{int(value):,}"
    except Exception:
        return "0"


def set_setting(key: str, value: str):
    cur.execute("""
        INSERT INTO settings (key, value)
        VALUES (?, ?)
        ON CONFLICT(key) DO UPDATE SET value = excluded.value
    """, (key, value))
    conn.commit()


def get_setting(key: str, default: str = "") -> str:
    cur.execute("SELECT value FROM settings WHERE key = ?", (key,))
    row = cur.fetchone()
    return row["value"] if row else default


def delete_setting(key: str):
    cur.execute("DELETE FROM settings WHERE key = ?", (key,))
    conn.commit()


def get_user(user_id: int):
    cur.execute("SELECT * FROM users WHERE user_id = ?", (user_id,))
    return cur.fetchone()


def create_or_update_user(user_id: int, username: str, first_name: str):
    row = get_user(user_id)
    if row:
        cur.execute("""
            UPDATE users
            SET username = ?, first_name = ?
            WHERE user_id = ?
        """, (username, first_name, user_id))
    else:
        cur.execute("""
            INSERT INTO users (
                user_id, username, first_name, joined_at, balance,
                is_blocked, blocked_reason, forced_join_msg_id
            )
            VALUES (?, ?, ?, ?, 0, 0, '', NULL)
        """, (user_id, username, first_name, now_gregorian_str()))
    conn.commit()


def update_forced_join_msg_id(user_id: int, msg_id):
    cur.execute("UPDATE users SET forced_join_msg_id = ? WHERE user_id = ?", (msg_id, user_id))
    conn.commit()


def get_forced_join_msg_id(user_id: int):
    row = get_user(user_id)
    return row["forced_join_msg_id"] if row else None


def is_owner(user_id: int) -> bool:
    return user_id in OWNER_IDS


def is_admin(user_id: int) -> bool:
    if is_owner(user_id):
        return True
    cur.execute("SELECT 1 FROM admins WHERE user_id = ?", (user_id,))
    return cur.fetchone() is not None


def get_all_admin_ids() -> list[int]:
    ids = list(OWNER_IDS)

    cur.execute("SELECT user_id FROM admins")
    rows = cur.fetchall()

    for row in rows:
        uid = int(row["user_id"])
        if uid not in ids:
            ids.append(uid)

    return ids


def add_admin_db(new_admin_id: int, added_by: int):
    cur.execute("""
        INSERT OR REPLACE INTO admins (user_id, added_by, added_at)
        VALUES (?, ?, ?)
    """, (new_admin_id, added_by, now_gregorian_str()))
    conn.commit()


def remove_admin_db(admin_id: int):
    cur.execute("DELETE FROM admins WHERE user_id = ?", (admin_id,))
    conn.commit()


def set_block_status(user_id: int, blocked: int, reason: str = ""):
    cur.execute("""
        UPDATE users
        SET is_blocked = ?, blocked_reason = ?
        WHERE user_id = ?
    """, (blocked, reason, user_id))
    conn.commit()


def change_balance(user_id: int, amount: int, admin_id: int, tx_type: str, description: str = ""):
    user = get_user(user_id)
    if not user:
        return False, "کاربر پیدا نشد."

    current_balance = int(user["balance"])
    new_balance = current_balance + amount

    if new_balance < 0:
        return False, "موجودی کاربر کافی نیست."

    cur.execute("UPDATE users SET balance = ? WHERE user_id = ?", (new_balance, user_id))
    cur.execute("""
        INSERT INTO transactions (user_id, admin_id, amount, type, created_at, description)
        VALUES (?, ?, ?, ?, ?, ?)
    """, (user_id, admin_id, amount, tx_type, now_gregorian_str(), description))
    conn.commit()
    return True, new_balance


def get_total_shop_purchases(user_id: int) -> int:
    cur.execute("SELECT COALESCE(SUM(amount), 0) AS total FROM orders WHERE user_id = ?", (user_id,))
    row = cur.fetchone()
    return int(row["total"] or 0)


def get_total_users_count() -> int:
    cur.execute("SELECT COUNT(*) AS total FROM users")
    row = cur.fetchone()
    return int(row["total"] or 0)


def get_users_stats():
    cur.execute("SELECT COUNT(*) AS total FROM users")
    total_users = int(cur.fetchone()["total"] or 0)

    cur.execute("SELECT COUNT(*) AS total FROM users WHERE is_blocked = 1")
    blocked_users = int(cur.fetchone()["total"] or 0)

    today = datetime.now().strftime("%Y-%m-%d")
    cur.execute("SELECT COUNT(*) AS total FROM users WHERE joined_at LIKE ?", (f"{today}%",))
    active_today = int(cur.fetchone()["total"] or 0)

    cur.execute("SELECT COUNT(*) AS total FROM orders")
    total_orders = int(cur.fetchone()["total"] or 0)

    cur.execute("SELECT COUNT(*) AS total FROM users WHERE bot_blocked = 1")
    bot_blocked = int(cur.fetchone()["total"] or 0)

    return total_users, blocked_users, active_today, total_orders, bot_blocked


def set_user_bot_blocked(user_id: int, blocked: int):
    cur.execute("UPDATE users SET bot_blocked = ? WHERE user_id = ?", (blocked, user_id))
    conn.commit()


def tron_hash_used(tx_hash: str) -> bool:
    cur.execute("SELECT 1 FROM used_tron_hashes WHERE tx_hash = ?", (tx_hash.lower(),))
    return cur.fetchone() is not None


def save_used_tron_hash(tx_hash: str, user_id: int, trx_amount: str, rate_irt: int, charged_amount: int):
    cur.execute("""
        INSERT INTO used_tron_hashes (tx_hash, user_id, trx_amount, rate_irt, charged_amount, created_at)
        VALUES (?, ?, ?, ?, ?, ?)
    """, (tx_hash.lower(), user_id, trx_amount, rate_irt, charged_amount, now_gregorian_str()))
    conn.commit()


def save_pending_ton_hash(user_id: int, username: str, first_name: str, tx_hash: str) -> int:
    cur.execute("""
        INSERT INTO pending_ton_hashes (user_id, username, first_name, tx_hash, status, created_at)
        VALUES (?, ?, ?, ?, 'pending', ?)
    """, (user_id, username, first_name, tx_hash, now_gregorian_str()))
    conn.commit()
    return cur.lastrowid


def get_pending_ton_hash(pending_id: int):
    cur.execute("SELECT * FROM pending_ton_hashes WHERE id = ?", (pending_id,))
    return cur.fetchone()


def update_pending_ton_hash_status(pending_id: int, status: str, reviewed_by: int):
    cur.execute("""
        UPDATE pending_ton_hashes
        SET status = ?, reviewed_by = ?, reviewed_at = ?
        WHERE id = ?
    """, (status, reviewed_by, now_gregorian_str(), pending_id))
    conn.commit()


def save_ton_notification_message(pending_id: int, target_chat_id: int, message_id: int):
    cur.execute("""
        INSERT INTO ton_hash_notifications (pending_id, target_chat_id, message_id, created_at)
        VALUES (?, ?, ?, ?)
    """, (pending_id, target_chat_id, message_id, now_gregorian_str()))
    conn.commit()


def get_ton_notification_messages(pending_id: int):
    cur.execute("SELECT * FROM ton_hash_notifications WHERE pending_id = ?", (pending_id,))
    return cur.fetchall()


def clear_ton_notification_messages(pending_id: int):
    cur.execute("DELETE FROM ton_hash_notifications WHERE pending_id = ?", (pending_id,))
    conn.commit()


def extract_channel_username(value: str) -> str | None:
    value = value.strip()
    if value.startswith("@"):
        u = value[1:].strip()
        return u if u else None

    m = re.match(r"^https?://t\.me/([A-Za-z0-9_]{5,})/?$", value)
    if m:
        return m.group(1)

    m = re.match(r"^t\.me/([A-Za-z0-9_]{5,})/?$", value)
    if m:
        return m.group(1)

    return None


def forced_join_enabled() -> bool:
    return get_setting("forced_join_enabled", "0") == "1"


def get_forced_join_username() -> str:
    return get_setting("forced_join_username", "").strip()


def get_forced_join_link() -> str:
    return get_setting("forced_join_link", "").strip()


async def is_user_joined_required_channel(user_id: int, context: ContextTypes.DEFAULT_TYPE) -> bool:
    if not forced_join_enabled():
        return True

    username = get_forced_join_username()
    if not username:
        return True

    try:
        member = await context.bot.get_chat_member(chat_id=f"@{username}", user_id=user_id)
        return member.status in {
            ChatMemberStatus.MEMBER,
            ChatMemberStatus.ADMINISTRATOR,
            ChatMemberStatus.OWNER,
        }
    except Exception as e:
        logger.warning("forced join check failed: %s", e)
        return False


async def send_forced_join_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    if not user:
        return

    old_msg_id = get_forced_join_msg_id(user.id)
    chat_id = update.effective_chat.id if update.effective_chat else user.id

    if old_msg_id:
        try:
            await context.bot.delete_message(chat_id=chat_id, message_id=old_msg_id)
        except Exception:
            pass

    link = get_forced_join_link() or f"https://t.me/{get_forced_join_username()}"
    text = (
        f"{pemoji(P_WARN, '⚠️')} <b>برای استفاده از ربات، اول در چنل عضو شو.</b>\n\n"
        f"{pemoji(P_LINK, '🔗')} بعد از عضویت، روی دکمه «عضو شدم» بزن."
    )
    kb = InlineKeyboardMarkup([
        [make_btn("عضویت در چنل", url=link, emoji_id=P_LINK, style="primary")],
        [make_btn("عضو شدم", callback_data="forced_join_check", emoji_id=P_OK, style="success")]
    ])
    sent = await context.bot.send_message(
        chat_id=chat_id,
        text=text,
        parse_mode=ParseMode.HTML,
        reply_markup=kb
    )
    update_forced_join_msg_id(user.id, sent.message_id)


async def ensure_forced_join(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool:
    user = update.effective_user
    if not user:
        return False

    if not forced_join_enabled():
        return True

    joined = await is_user_joined_required_channel(user.id, context)
    if joined:
        old_msg_id = get_forced_join_msg_id(user.id)
        if old_msg_id:
            try:
                await context.bot.delete_message(chat_id=update.effective_chat.id, message_id=old_msg_id)
            except Exception:
                pass
            update_forced_join_msg_id(user.id, None)
        return True

    await send_forced_join_message(update, context)
    return False


def user_main_keyboard():
    return ReplyKeyboardMarkup(
        [
            ["💳 افزایش موجودی", "🛒 خرید شارژ"],
            ["🔒 حساب کاربری", "💻 پشتیبانی"],
            ["🧾 راهنما"],
        ],
        resize_keyboard=True
    )


def admin_main_keyboard():
    return ReplyKeyboardMarkup(
        [
            ["💳 افزایش موجودی", "🛒 خرید شارژ"],
            ["🔒 حساب کاربری", "💻 پشتیبانی"],
            ["🧾 راهنما"],
            ["👑 پنل مدیریت"],
        ],
        resize_keyboard=True
    )


def get_home_keyboard(user_id: int):
    return admin_main_keyboard() if is_admin(user_id) else user_main_keyboard()


def owner_panel_keyboard():
    return ReplyKeyboardMarkup(
        [
            ["💰 افزایش موجودی کاربر", "💸 کاهش موجودی کاربر"],
            ["⛔ بلاک کاربر", "✅ آن‌بلاک کاربر"],
            ["📦 افزودن شارژ", "📢 فور همگانی"],
            ["➕ افزودن جوین اجباری", "➖ حذف جوین اجباری"],
            ["➕ افزودن ادمین", "➖ حذف ادمین"],
            ["🔎 جستجوی کاربر", "📊 آمار کاربران"],
            ["🏠 بازگشت به پنل کاربر"],
        ],
        resize_keyboard=True
    )


def admin_panel_keyboard():
    return ReplyKeyboardMarkup(
        [
            ["💰 افزایش موجودی کاربر", "💸 کاهش موجودی کاربر"],
            ["⛔ بلاک کاربر", "✅ آن‌بلاک کاربر"],
            ["📦 افزودن شارژ"],
            ["🔎 جستجوی کاربر", "📊 آمار کاربران"],
            ["🏠 بازگشت به پنل کاربر"],
        ],
        resize_keyboard=True
    )


def get_admin_panel_keyboard(user_id: int):
    return owner_panel_keyboard() if is_owner(user_id) else admin_panel_keyboard()


def only_back_keyboard():
    return ReplyKeyboardMarkup([["🔙 بازگشت"]], resize_keyboard=True)


def deposit_methods_keyboard():
    return ReplyKeyboardMarkup(
        [
            ["از طریق تون"],
            ["از طریق ترون"],
            ["🔙 بازگشت"],
        ],
        resize_keyboard=True
    )


def buy_operator_inline_keyboard():
    return InlineKeyboardMarkup([
        [make_btn("همراه اول", callback_data="buy_mci", emoji_id=P_MCI, style="success")],
        [make_btn("ایرانسل", callback_data="buy_irancell", emoji_id=P_IRANCELL, style="primary")],
        [make_btn("رایتل", callback_data="buy_rightel", emoji_id=P_RIGHTEL, style="primary")],
        [make_btn("بازگشت", callback_data="charge_back_home", emoji_id=P_BACK, style="danger")]
    ])


async def delete_last_user_panel_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
    msg_id = context.user_data.get("last_user_panel_msg_id")
    if not msg_id:
        return

    chat_id = update.effective_chat.id if update.effective_chat else None
    if not chat_id:
        return

    try:
        await context.bot.delete_message(chat_id=chat_id, message_id=msg_id)
    except Exception:
        pass

    context.user_data.pop("last_user_panel_msg_id", None)


async def send_tracked_user_message(update: Update, context: ContextTypes.DEFAULT_TYPE, text: str, **kwargs):
    await delete_last_user_panel_message(update, context)

    if "reply_markup" not in kwargs:
        kwargs["reply_markup"] = only_back_keyboard()

    if "parse_mode" not in kwargs:
        kwargs["parse_mode"] = ParseMode.HTML

    sent = await update.message.reply_text(text, **kwargs)
    context.user_data["last_user_panel_msg_id"] = sent.message_id
    return sent


async def send_start_report(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    args = context.args or []
    inviter_text = "⭕️ بدون دعوت"
    if args:
        inviter_text = f"🔗 دعوت: {args[0]}"

    username = format_username(user.username)

    text = (
        f"#کاربر_{user.id}\n\n"
        f"🔑 استارت\n\n"
        f"🆔 کاربر: {user.id}\n\n"
        f"👤 یوزرنیم: {username}\n\n"
        f"{inviter_text}\n"
        f"⏰ زمان: {jalali_datetime_str()}"
    )
    try:
        await context.bot.send_message(chat_id=REPORT_CHANNEL_ID, text=text)
    except Exception as e:
        logger.warning("start report failed: %s", e)


async def send_new_admin_report(context, added_by_id, added_by_username, new_admin_id, new_admin_username):
    text = (
        f"👑 ادمین جدید اضافه شد\n"
        f"👤 ادمین اضافه‌کننده:\n{added_by_id}\n{added_by_username}\n\n"
        f"👤 ادمین جدید:\n{new_admin_id}\n{new_admin_username}\n\n"
        f"⏰ زمان: {jalali_datetime_str()}"
    )
    try:
        await context.bot.send_message(chat_id=REPORT_CHANNEL_ID, text=text)
    except Exception as e:
        logger.warning("new admin report failed: %s", e)


async def send_block_report(context, action_by_id, action_by_username, target_id, target_username, action_text):
    text = (
        f"{action_text}\n\n"
        f"👤 انجام‌دهنده:\n{action_by_id}\n{action_by_username}\n\n"
        f"👤 کاربر:\n{target_id}\n{target_username}\n\n"
        f"⏰ زمان: {jalali_datetime_str()}"
    )
    try:
        await context.bot.send_message(chat_id=REPORT_CHANNEL_ID, text=text)
    except Exception as e:
        logger.warning("block report failed: %s", e)
        
async def send_balance_change_report(context, admin_user, target_user, target_id: int, amount: int, new_balance: int, action: str):
    admin_username = format_username(admin_user.username)
    target_username = target_user["username"] if target_user and target_user["username"] else "ندارد"

    if action == "increase":
        title = "💹 افزایش موجودی کاربر"
        amount_line = f"💰 مبلغ اضافه شده: {format_money(amount)} تومان"
    else:
        title = "📉 کاهش موجودی کاربر"
        amount_line = f"💰 مبلغ کم شده: {format_money(amount)} تومان"

    text = (
        f"{title}\n\n"
        f"👤 ادمین انجام‌دهنده: {admin_username}\n\n"
        f"🆔 آیدی عددی ادمین: {admin_user.id}\n\n"
        f"👤 کاربر: {target_username}\n\n"
        f"🆔 آیدی عددی کاربر: {target_id}\n\n"
        f"{amount_line}\n\n"
        f"💳 موجودی جدید: {format_money(new_balance)} تومان\n\n"
        f"⏰ زمان: {jalali_datetime_str()}"
    )

    try:
        await context.bot.send_message(chat_id=REPORT_CHANNEL_ID, text=text)
    except Exception as e:
        logger.warning("balance change report failed: %s", e)

async def blocked_guard(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool:
    user = update.effective_user
    if not user:
        return False

    row = get_user(user.id)
    if row and int(row["is_blocked"]) == 1:
        if update.message:
            await update.message.reply_text(
                f"{pemoji(P_X, '❌')} شما توسط مدیریت مسدود شده‌اید.",
                parse_mode=ParseMode.HTML
            )
        elif update.callback_query:
            await update.callback_query.answer("⛔ شما مسدود شده‌اید.", show_alert=True)
        return True
    return False


deposit_manager = DepositManager(
    owner_id=OWNER_ID,
    report_channel_id=REPORT_CHANNEL_ID,
    tron_wallet_address=TRON_WALLET_ADDRESS,
    ton_wallet_address=TON_WALLET_ADDRESS,
    request_timeout=REQUEST_TIMEOUT,
    http_session=http,
    tronscan_api_key=TRONSCAN_API_KEY,
    nobitex_api_key=NOBITEX_API_KEY,
    get_user=get_user,
    change_balance=change_balance,
    tron_hash_used=tron_hash_used,
    save_used_tron_hash=save_used_tron_hash,
    now_gregorian_str=now_gregorian_str,
    format_money=format_money,
    format_username=format_username,
    logger=logger,
    get_all_admin_ids=get_all_admin_ids,
    save_pending_ton_hash=save_pending_ton_hash,
    get_pending_ton_hash=get_pending_ton_hash,
    update_pending_ton_hash_status=update_pending_ton_hash_status,
    save_ton_notification_message=save_ton_notification_message,
    get_ton_notification_messages=get_ton_notification_messages,
    clear_ton_notification_messages=clear_ton_notification_messages,
    esc=esc,
)

sharz_manager = SharzManager(
    conn=conn,
    cur=cur,
    report_channel_id=REPORT_CHANNEL_ID,
    logger=logger,
    now_gregorian_str=now_gregorian_str,
    jalali_datetime_str=jalali_datetime_str,
    format_money=format_money,
    format_username=format_username,
    is_admin=is_admin,
    get_admin_panel_keyboard=get_admin_panel_keyboard,
    get_user=get_user,
    change_balance=change_balance,
    owner_id=OWNER_ID,
)


async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_chat and update.effective_chat.type != "private":
        return

    user = update.effective_user
    username = format_username(user.username)
    first_name = user.first_name or "کاربر"

    create_or_update_user(user.id, username, first_name)

    if await blocked_guard(update, context):
        return

    if not await ensure_forced_join(update, context):
        return

    await send_start_report(update, context)

    text = (
        f"{pemoji(P_CROWN, '👑')} <b>{esc(first_name)} جان، به ربات ما خوش اومدی</b>\n\n"
        f"{pemoji(P_LEAF, '🍃')} این ربات با خدمات ویژه و امکانات اختصاصی آماده استفاده شماست.\n\n"
        f"{pemoji(P_EYE, '👀')} برای استفاده از امکانات، از منوی زیر اقدام کن.\n\n"
        f"{pemoji(P_FIRE, '🔥')} پشتیبانی سریع و مستقیم توسط مالک ربات."
    )

    context.user_data.clear()
    await update.message.reply_text(
        text,
        parse_mode=ParseMode.HTML,
        reply_markup=get_home_keyboard(user.id)
    )


async def show_buy_menu(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await blocked_guard(update, context):
        return
    if not await ensure_forced_join(update, context):
        return

    await delete_last_user_panel_message(update, context)

    context.user_data.clear()
    context.user_data["flow"] = "user_buy_operator_menu"

    text = (
        f"{pemoji(P_BUY, '🛒')} <b>خرید شارژ</b>\n\n"
        f"{pemoji(P_PIN, '📌')} اپراتور موردنظر خودت رو انتخاب کن:"
    )

    sent = await update.message.reply_text(
        text,
        parse_mode=ParseMode.HTML,
        reply_markup=buy_operator_inline_keyboard()
    )
    context.user_data["last_user_panel_msg_id"] = sent.message_id


async def handle_buy_callbacks(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query

    if not query:
        return

    if await blocked_guard(update, context):
        return

    if not await ensure_forced_join(update, context):
        return

    op_map = {
        "buy_mci": "همراه اول",
        "buy_irancell": "ایرانسل",
        "buy_rightel": "رایتل",
    }

    operator = op_map.get(query.data)

    if not operator:
        await query.answer("اپراتور نامعتبر است.", show_alert=True)
        return

    await sharz_manager.show_user_charge_packs(update, context, operator)


async def charge_back_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query

    if not query:
        return

    await query.answer()

    flow = context.user_data.get("flow")

    if flow == "user_buy_charge_packs":
        context.user_data.clear()
        context.user_data["flow"] = "user_buy_operator_menu"

        text = (
            f"{pemoji(P_BUY, '🛒')} <b>خرید شارژ</b>\n\n"
            f"{pemoji(P_PIN, '📌')} اپراتور موردنظر خودت رو انتخاب کن:"
        )

        try:
            await query.message.edit_text(
                text,
                parse_mode=ParseMode.HTML,
                reply_markup=buy_operator_inline_keyboard()
            )
            context.user_data["last_user_panel_msg_id"] = query.message.message_id
        except Exception:
            sent = await query.message.reply_text(
                text,
                parse_mode=ParseMode.HTML,
                reply_markup=buy_operator_inline_keyboard()
            )
            context.user_data["last_user_panel_msg_id"] = sent.message_id

        return

    user_id = update.effective_user.id
    await sharz_manager.charge_back_callback(update, context, get_home_keyboard(user_id))


async def charge_back_home_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    await query.answer()

    user_id = update.effective_user.id

    try:
        await query.message.delete()
    except Exception:
        pass

    await sharz_manager.delete_buy_messages(context, query.message.chat_id)

    context.user_data.clear()

    await query.message.reply_text(
        f"{pemoji(P_OK, '✅')} <b>منوی کاربر</b>",
        parse_mode=ParseMode.HTML,
        reply_markup=get_home_keyboard(user_id)
    )


async def buy_charge_pack_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user_id = update.effective_user.id
    await sharz_manager.buy_charge_pack(update, context, get_home_keyboard(user_id))


async def show_deposit_menu(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await blocked_guard(update, context):
        return
    if not await ensure_forced_join(update, context):
        return

    await delete_last_user_panel_message(update, context)

    context.user_data.clear()
    context.user_data["flow"] = "user_deposit_menu"
    sent = await update.message.reply_text(
        f"{pemoji(P_CARD, '💳')} <b>افزایش موجودی</b>\n\n"
        f"{pemoji(P_PLUS, '➕')} یکی از روش‌های افزایش موجودی را انتخاب کن:",
        parse_mode=ParseMode.HTML,
        reply_markup=deposit_methods_keyboard()
    )
    context.user_data["last_user_panel_msg_id"] = sent.message_id


async def show_account(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_chat and update.effective_chat.type != "private":
        return

    if await blocked_guard(update, context):
        return
    if not await ensure_forced_join(update, context):
        return

    user = update.effective_user
    row = get_user(user.id)
    if not row:
        return

    joined_jalali = gregorian_to_jalali_date_str(row["joined_at"])
    active_days = days_since(row["joined_at"])
    balance = int(row["balance"])

    text = (
        f"{pemoji(P_ACCOUNT, '🔒')} <b>اطلاعات حساب کاربری</b>\n\n"
        f"{pemoji(P_PIN, '📌')} <b>{persian_weekday_today()}:</b> <b>{jalali_date_str()}</b>\n\n"
        f"{pemoji(P_LEAF, '🍃')} <b>ساعت:</b> <b>{jalali_time_str()}</b>\n\n"
        f"━━━━━━━━━━━━━━━━━━━━\n\n"
        f"{pemoji(P_ACCOUNT, '🔒')} <b>شماره کاربری:</b> <b>{user.id}</b>\n\n"
        f"{pemoji(P_MAIL, '✉')} <b>آغاز فعالیت:</b> <b>{joined_jalali}</b>\n\n"
        f"{pemoji(P_EYE, '👀')} <b>فعالیت در ربات:</b> <b>{active_days}</b> روز\n\n"
        f"{pemoji(P_MONEY, '💸')} <b>موجودی فعلی:</b> <b>{format_money(balance)}</b> تومان\n\n"
    )

    await send_tracked_user_message(update, context, text)


async def show_support(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await blocked_guard(update, context):
        return
    if not await ensure_forced_join(update, context):
        return

    text = (
        f"{pemoji(P_SUPPORT, '💻')} <b>پشتیبانی ربات</b>\n\n"
        f"{pemoji(P_EYE, '👀')} برای ارتباط مستقیم با مالک ربات اقدام کن.\n\n"
        f"{pemoji(P_LINK, '🔗')} آیدی پشتیبانی:\n\n"
        f"<a href='tg://resolve?domain={SUPPORT_USERNAME}'>@{esc(SUPPORT_USERNAME)}</a>\n\n"
        f"{pemoji(P_FIRE, '🔥')} پاسخگویی سریع."
    )

    kb = InlineKeyboardMarkup([
        [make_btn("ورود به پشتیبانی", url=f"https://t.me/{SUPPORT_USERNAME}", emoji_id=P_SUPPORT, style="success")]
    ])

    await send_tracked_user_message(update, context, text, reply_markup=kb)


async def show_help(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await blocked_guard(update, context):
        return
    if not await ensure_forced_join(update, context):
        return

    text = (
        f"{pemoji(P_HELP, '🧾')} <b>راهنمای کامل ربات</b>\n\n"
        f"━━━━━━━━━━━━━━━━━━━━\n\n"
        f"{pemoji(P_EYE, '👀')} <b>معرفی ربات</b>\n\n"
        f"{pemoji(P_BUY, '🛒')} خرید شارژ\n"
        f"{pemoji(P_CARD, '💳')} افزایش موجودی\n"
        f"{pemoji(P_ACCOUNT, '🔒')} مدیریت حساب\n"
        f"{pemoji(P_SUPPORT, '💻')} ارتباط با پشتیبانی\n\n"
        f"━━━━━━━━━━━━━━━━━━━━\n\n"
        f"{pemoji(P_BUY, '🛒')} <b>خرید شارژ</b>\n\n"
        f"{pemoji(P_PIN, '📌')} انتخاب اپراتور\n"
        f"{pemoji(P_PIN, '📌')} انتخاب پک\n"
        f"{pemoji(P_PIN, '📌')} پرداخت از موجودی\n"
        f"{pemoji(P_PIN, '📌')} دریافت کد شارژ\n\n"
        f"{pemoji(P_OK, '✅')} تحویل آنی بعد از خرید\n\n"
        f"━━━━━━━━━━━━━━━━━━━━\n\n"
        f"{pemoji(P_PLUS, '➕')} <b>افزایش موجودی</b>\n\n"
        f"{pemoji(P_PIN, '📌')} انتخاب روش پرداخت\n"
        f"{pemoji(P_PIN, '📌')} ارسال ارز (TON / TRX)\n"
        f"{pemoji(P_PIN, '📌')} ثبت هش تراکنش\n\n"
        f"{pemoji(P_OK, '✅')} شارژ خودکار یا بررسی توسط ادمین\n\n"
        f"━━━━━━━━━━━━━━━━━━━━\n\n"
        f"{pemoji(P_ACCOUNT, '🔒')} <b>حساب کاربری</b>\n\n"
        f"{pemoji(P_OK, '✔️')} مشاهده موجودی\n\n"
        f"{pemoji(P_OK, '✔️')} اطلاعات حساب\n\n"
        f"{pemoji(P_OK, '✔️')} سابقه فعالیت\n\n"
        f"━━━━━━━━━━━━━━━━━━━━\n\n"
        f"{pemoji(P_SUPPORT, '💻')} <b>پشتیبانی</b>\n\n"
        f"{pemoji(P_PIN, '📌')} در صورت مشکل پیام بده:\n\n"
        f"<b>@{esc(SUPPORT_USERNAME)}</b>\n\n"
        f"━━━━━━━━━━━━━━━━━━━━\n\n"
        f"{pemoji(P_FIRE, '🔥')} <b>نکات مهم</b>\n\n"
        f"{pemoji(P_X, '❌')} اطلاعات اشتباه وارد نکن\n"
        f"{pemoji(P_WARN, '⚠️')} فقط از دکمه‌ها استفاده کن\n"
        f"{pemoji(P_OK, '✔️')} خریدها غیرقابل بازگشت هستند\n\n"
        f"━━━━━━━━━━━━━━━━━━━━\n\n"
        f"{pemoji(P_DIAMOND, '💎')} <b>موفق باشی 🚀</b>"
    )

    await send_tracked_user_message(update, context, text)


# 👇 اینو اضافه کردی (مهم)
async def show_users_stats(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user_id = update.effective_user.id

    if not is_admin(user_id):
        await update.message.reply_text("⛔ دسترسی ندارید.")
        return

    total_users, blocked_users, active_today, total_orders, bot_blocked = get_users_stats()

    text = (
        f"📙همه کاربران ربات: {format_money(total_users)}\n\n"
        f"⛔️کاربران مسدود شده: {format_money(blocked_users)}\n\n"
        f"🔮کاربران فعال امروز: {format_money(active_today)}\n\n"
        f"✈️سفارشات کاربران: {format_money(total_orders)}\n\n"
        f"⭕️ربات را بلاک کرده اند: {format_money(bot_blocked)}"
    )

    await update.message.reply_text(
        text,
        reply_markup=get_admin_panel_keyboard(user_id)
    )


async def open_admin_panel(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user_id = update.effective_user.id

    if not is_admin(user_id):
        await update.message.reply_text(
            f"{pemoji(P_X, '❌')} شما دسترسی به پنل مدیریت ندارید.",
            parse_mode=ParseMode.HTML
        )
        return

    context.user_data.clear()
    await update.message.reply_text(
        f"{pemoji(P_CROWN, '👑')} <b>به پنل مدیریت خوش اومدی</b>\n\n"
        f"{pemoji(P_PIN, '📌')} از دکمه‌های زیر استفاده کن.",
        parse_mode=ParseMode.HTML,
        reply_markup=get_admin_panel_keyboard(user_id)
    )


async def back_to_user_panel(update: Update, context: ContextTypes.DEFAULT_TYPE):
    context.user_data.clear()
    await update.message.reply_text(
        f"{pemoji(P_OK, '✅')} <b>منوی کاربر</b>",
        parse_mode=ParseMode.HTML,
        reply_markup=get_home_keyboard(update.effective_user.id)
    )


async def begin_admin_action(update: Update, context: ContextTypes.DEFAULT_TYPE, action: str):
    user_id = update.effective_user.id
    if not is_admin(user_id):
        await update.message.reply_text(
            f"{pemoji(P_X, '❌')} دسترسی ندارید.",
            parse_mode=ParseMode.HTML
        )
        return

    if action in {"add_admin", "remove_admin", "set_forced_join", "remove_forced_join"} and not is_owner(user_id):
        await update.message.reply_text(
            f"{pemoji(P_WARN, '⚠️')} فقط مالک می‌تواند این عملیات را انجام دهد.",
            parse_mode=ParseMode.HTML
        )
        return

    if action == "add_charge_menu":
        await sharz_manager.start_add_charge(update, context)
        return

    context.user_data.clear()
    context.user_data["flow"] = "admin"
    context.user_data["admin_action"] = action

    prompts = {
        "increase_balance": f"{pemoji(P_PLUS, '➕')} آیدی عددی کاربر را برای افزایش موجودی ارسال کن:",
        "decrease_balance": f"{pemoji(P_COIN, '➕')} آیدی عددی کاربر را برای کاهش موجودی ارسال کن:",
        "add_admin": f"{pemoji(P_CROWN, '👑')} آیدی عددی کاربری که می‌خواهی ادمین شود را ارسال کن:",
        "remove_admin": f"{pemoji(P_X, '❌')} آیدی عددی ادمینی که می‌خواهی حذف شود را ارسال کن:",
        "block_user": f"{pemoji(P_WARN, '⚠️')} آیدی عددی کاربری که می‌خواهی بلاک شود را ارسال کن:",
        "unblock_user": f"{pemoji(P_OK, '✅')} آیدی عددی کاربری که می‌خواهی آن‌بلاک شود را ارسال کن:",
        "search_user": f"{pemoji(P_EYE, '👀')} آیدی عددی کاربر موردنظر را ارسال کن:",
        "set_forced_join": f"{pemoji(P_LINK, '🔗')} لینک چنل عمومی را بفرست.",
        "remove_forced_join": f"{pemoji(P_WARN, '⚠️')} برای حذف جوین اجباری، کلمه حذف را بفرست.",
    }

    if action == "set_forced_join":
        context.user_data["step"] = "ask_channel_link"
        await update.message.reply_text(prompts[action], parse_mode=ParseMode.HTML, reply_markup=only_back_keyboard())
        return

    if action == "remove_forced_join":
        context.user_data["step"] = "confirm_remove_forced_join"
        await update.message.reply_text(prompts[action], parse_mode=ParseMode.HTML, reply_markup=only_back_keyboard())
        return

    context.user_data["step"] = "ask_user_id"
    await update.message.reply_text(prompts[action], parse_mode=ParseMode.HTML, reply_markup=only_back_keyboard())


async def process_admin_steps(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool:
    user_id = update.effective_user.id
    text = (update.message.text or "").strip()

    if not is_admin(user_id):
        return False

    action = context.user_data.get("admin_action")
    step = context.user_data.get("step")
    if not action or not step:
        return False

    if text == "🔙 بازگشت":
        context.user_data.clear()
        await update.message.reply_text(
            f"{pemoji(P_OK, '✅')} به پنل مدیریت برگشتی.",
            parse_mode=ParseMode.HTML,
            reply_markup=get_admin_panel_keyboard(user_id)
        )
        return True

    if step == "ask_channel_link":
        username = extract_channel_username(text)
        if not username:
            await update.message.reply_text(
                f"{pemoji(P_X, '❌')} فقط چنل عمومی بفرست.",
                parse_mode=ParseMode.HTML
            )
            return True

        set_setting("forced_join_enabled", "1")
        set_setting("forced_join_username", username)
        set_setting("forced_join_link", f"https://t.me/{username}")

        context.user_data.clear()
        await update.message.reply_text(
            f"{pemoji(P_OK, '✅')} جوین اجباری فعال شد.\n"
            f"{pemoji(P_LINK, '🔗')} چنل: <b>@{esc(username)}</b>",
            parse_mode=ParseMode.HTML,
            reply_markup=get_admin_panel_keyboard(user_id)
        )
        return True

    if step == "confirm_remove_forced_join":
        if text != "حذف":
            await update.message.reply_text(
                f"{pemoji(P_WARN, '⚠️')} برای حذف جوین اجباری فقط کلمه حذف را بفرست.",
                parse_mode=ParseMode.HTML
            )
            return True

        delete_setting("forced_join_enabled")
        delete_setting("forced_join_username")
        delete_setting("forced_join_link")

        context.user_data.clear()
        await update.message.reply_text(
            f"{pemoji(P_OK, '✅')} جوین اجباری حذف شد.",
            parse_mode=ParseMode.HTML,
            reply_markup=get_admin_panel_keyboard(user_id)
        )
        return True

    if step == "ask_user_id":
        if not text.isdigit():
            await update.message.reply_text(
                f"{pemoji(P_X, '❌')} فقط آیدی عددی بفرست.",
                parse_mode=ParseMode.HTML
            )
            return True

        target_id = int(text)
        context.user_data["target_user_id"] = target_id
    if step == "ask_user_id":
        if not text.isdigit():
            await update.message.reply_text(
                f"{pemoji(P_X, '❌')} فقط آیدی عددی بفرست.",
                parse_mode=ParseMode.HTML
            )
            return True

        target_id = int(text)
        context.user_data["target_user_id"] = target_id

        if action in {"increase_balance", "decrease_balance"}:
            target_user = get_user(target_id)

            if not target_user:
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} کاربر پیدا نشد. آیدی عددی اشتباه است یا کاربر هنوز ربات را استارت نکرده.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=get_admin_panel_keyboard(user_id)
                )
                context.user_data.clear()
                return True

            context.user_data["step"] = "ask_amount"
            await update.message.reply_text(
                f"{pemoji(P_MONEY, '💸')} مبلغ را به تومان بفرست:",
                parse_mode=ParseMode.HTML,
                reply_markup=only_back_keyboard()
            )
            return True

        if action == "add_admin":
            if target_id in OWNER_IDS:
                await update.message.reply_text(
                    f"{pemoji(P_WARN, '⚠️')} مالک از قبل دسترسی کامل دارد.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=get_admin_panel_keyboard(user_id)
                )
                context.user_data.clear()
                return True

            target_user = get_user(target_id)
            if not target_user:
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} این کاربر هنوز ربات را استارت نکرده.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=get_admin_panel_keyboard(user_id)
                )
                context.user_data.clear()
                return True

            if is_admin(target_id):
                await update.message.reply_text(
                    f"{pemoji(P_WARN, '⚠️')} این کاربر از قبل ادمین است.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=get_admin_panel_keyboard(user_id)
                )
                context.user_data.clear()
                return True

            add_admin_db(target_id, user_id)

            await send_new_admin_report(
                context=context,
                added_by_id=user_id,
                added_by_username=format_username(update.effective_user.username),
                new_admin_id=target_id,
                new_admin_username=target_user["username"] or "ندارد",
            )

            try:
                await context.bot.send_message(
                    chat_id=target_id,
                    text=f"{pemoji(P_CROWN, '👑')} شما توسط مالک ربات ادمین شدید.",
                    parse_mode=ParseMode.HTML
                )
            except Exception:
                pass

            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} ادمین با موفقیت اضافه شد.",
                parse_mode=ParseMode.HTML,
                reply_markup=get_admin_panel_keyboard(user_id)
            )
            context.user_data.clear()
            return True
        
        if action == "remove_admin":
            if target_id in OWNER_IDS:
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} مالک قابل حذف نیست.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=get_admin_panel_keyboard(user_id)
                )
                context.user_data.clear()
                return True

            if not is_admin(target_id):
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} این کاربر ادمین نیست.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=get_admin_panel_keyboard(user_id)
                )
                context.user_data.clear()
                return True

            remove_admin_db(target_id)
            try:
                await context.bot.send_message(
                    chat_id=target_id,
                    text=f"{pemoji(P_WARN, '⚠️')} دسترسی مدیریتی شما حذف شد.",
                    parse_mode=ParseMode.HTML
                )
            except Exception:
                pass

            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} ادمین حذف شد.",
                parse_mode=ParseMode.HTML,
                reply_markup=get_admin_panel_keyboard(user_id)
            )
            context.user_data.clear()
            return True

        if action == "block_user":
            target_user = get_user(target_id)
            if not target_user:
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} کاربر پیدا نشد.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=get_admin_panel_keyboard(user_id)
                )
                context.user_data.clear()
                return True

            if target_id in OWNER_IDS:
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} مالک قابل بلاک نیست.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=get_admin_panel_keyboard(user_id)
                )
                context.user_data.clear()
                return True

            if is_admin(target_id):
                await update.message.reply_text(
                    f"{pemoji(P_WARN, '⚠️')} کاربر ادمینه.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=get_admin_panel_keyboard(user_id)
                )
                context.user_data.clear()
                return True

            set_block_status(target_id, 1, "مسدود توسط مدیریت")

            await send_block_report(
                context=context,
                action_by_id=user_id,
                action_by_username=format_username(update.effective_user.username),
                target_id=target_id,
                target_username=target_user["username"] or "ندارد",
                action_text="⛔ کاربر بلاک شد"
            )

            try:
                await context.bot.send_message(
                    chat_id=target_id,
                    text=f"{pemoji(P_X, '❌')} حساب شما توسط مدیریت مسدود شد.",
                    parse_mode=ParseMode.HTML
                )
            except Exception:
                pass

            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} کاربر بلاک شد.",
                parse_mode=ParseMode.HTML,
                reply_markup=get_admin_panel_keyboard(user_id)
            )
            context.user_data.clear()
            return True

        if action == "unblock_user":
            target_user = get_user(target_id)
            if not target_user:
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} کاربر پیدا نشد.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=get_admin_panel_keyboard(user_id)
                )
                context.user_data.clear()
                return True

            set_block_status(target_id, 0, "")

            await send_block_report(
                context=context,
                action_by_id=user_id,
                action_by_username=format_username(update.effective_user.username),
                target_id=target_id,
                target_username=target_user["username"] or "ندارد",
                action_text="✅ کاربر آن‌بلاک شد"
            )

            try:
                await context.bot.send_message(
                    chat_id=target_id,
                    text=f"{pemoji(P_OK, '✅')} حساب شما از مسدودی خارج شد.",
                    parse_mode=ParseMode.HTML
                )
            except Exception:
                pass

            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} کاربر آن‌بلاک شد.",
                parse_mode=ParseMode.HTML,
                reply_markup=get_admin_panel_keyboard(user_id)
            )
            context.user_data.clear()
            return True

        if action == "search_user":
            target_user = get_user(target_id)
            if not target_user:
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} کاربر پیدا نشد.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=get_admin_panel_keyboard(user_id)
                )
                context.user_data.clear()
                return True

            joined_jalali_dt = gregorian_to_jalali_datetime_str(target_user["joined_at"])
            active_days = days_since(target_user["joined_at"])
            total_purchases = get_total_shop_purchases(target_id)
            balance = int(target_user["balance"])
            username = target_user["username"] or "ندارد"

            text_out = (
                f"{pemoji(P_EYE, '👀')} <b>جستجوی کاربر</b>\n\n"
                f"{pemoji(P_ACCOUNT, '🔒')} <b>آیدی:</b> <b>{target_id}</b>\n\n"
                f"{pemoji(P_LINK, '🔗')} <b>لینک:</b> tg://openmessage?user_id={target_id}\n\n"
                f"{pemoji(P_MAIL, '✉')} <b>یوزرنیم:</b> <b>{esc(username)}</b>\n\n"
                f"{pemoji(P_PIN, '📌')} <b>آغاز فعالیت:</b> <b>{joined_jalali_dt}</b>\n\n"
                f"{pemoji(P_EYE, '👀')} <b>تعداد روزهای فعال:</b> <b>{active_days}</b>\n\n"
                f"{pemoji(P_BUY, '🛒')} <b>مجموع خرید:</b> <b>{format_money(total_purchases)}</b> تومان\n\n"
                f"{pemoji(P_COIN, '🪙')} <b>موجودی فعلی:</b> <b>{format_money(balance)}</b> تومان"
            )

            await update.message.reply_text(
                text_out,
                parse_mode=ParseMode.HTML,
                reply_markup=get_admin_panel_keyboard(user_id)
            )
            context.user_data.clear()
            return True

    if step == "ask_amount":
        if not text.isdigit():
            await update.message.reply_text(
                f"{pemoji(P_X, '❌')} فقط مبلغ عددی بفرست.",
                parse_mode=ParseMode.HTML
            )
            return True

        amount = int(text)
        if amount <= 0:
            await update.message.reply_text(
                f"{pemoji(P_X, '❌')} مبلغ باید بیشتر از صفر باشد.",
                parse_mode=ParseMode.HTML
            )
            return True

        target_id = context.user_data.get("target_user_id")
        if not target_id:
            context.user_data.clear()
            await update.message.reply_text(
                f"{pemoji(P_X, '❌')} خطا.",
                parse_mode=ParseMode.HTML,
                reply_markup=get_admin_panel_keyboard(user_id)
            )
            return True

        if action == "increase_balance":
            ok, result = change_balance(
                user_id=target_id,
                amount=amount,
                admin_id=user_id,
                tx_type="increase",
                description="افزایش موجودی توسط ادمین"
            )
            if not ok:
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} {esc(result)}",
                    parse_mode=ParseMode.HTML
                )
                return True

            try:
                await context.bot.send_message(
                    chat_id=target_id,
                    text=(
                        f"{pemoji(P_PLUS, '➕')} مبلغ <b>{format_money(amount)}</b> تومان به موجودی شما اضافه شد.\n\n"
                        f"{pemoji(P_MONEY, '💸')} موجودی جدید: <b>{format_money(result)}</b> تومان"
                    ),
                    parse_mode=ParseMode.HTML
                )
            except Exception:
                pass

            target_user = get_user(target_id)

            await send_balance_change_report(
                context=context,
                admin_user=update.effective_user,
                target_user=target_user,
                target_id=target_id,
                amount=amount,
                new_balance=result,
                action="increase"
            )

            context.user_data.clear()
            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} موجودی کاربر افزایش یافت.\n\n"
                f"{pemoji(P_MONEY, '💸')} موجودی جدید: <b>{format_money(result)}</b> تومان",
                parse_mode=ParseMode.HTML,
                reply_markup=get_admin_panel_keyboard(user_id)
            )
            return True

        if action == "decrease_balance":
            ok, result = change_balance(
                user_id=target_id,
                amount=-amount,
                admin_id=user_id,
                tx_type="decrease",
                description="کاهش موجودی توسط ادمین"
            )
            if not ok:
                await update.message.reply_text(
                    f"{pemoji(P_X, '❌')} {esc(result)}",
                    parse_mode=ParseMode.HTML
                )
                return True

            try:
                await context.bot.send_message(
                    chat_id=target_id,
                    text=(
                        f"{pemoji(P_MONEY, '💸')} مبلغ <b>{format_money(amount)}</b> تومان از موجودی شما کسر شد.\n\n"
                        f"{pemoji(P_MONEY, '💸')} موجودی جدید: <b>{format_money(result)}</b> تومان"
                    ),
                    parse_mode=ParseMode.HTML
                )
            except Exception:
                pass

            target_user = get_user(target_id)

            await send_balance_change_report(
                context=context,
                admin_user=update.effective_user,
                target_user=target_user,
                target_id=target_id,
                amount=amount,
                new_balance=result,
                action="decrease"
            )

            context.user_data.clear()
            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} موجودی کاربر کاهش یافت.\n\n"
                f"{pemoji(P_MONEY, '💸')} موجودی جدید: <b>{format_money(result)}</b> تومان",
                parse_mode=ParseMode.HTML,
                reply_markup=get_admin_panel_keyboard(user_id)
            )
            return True

    return False


async def forced_join_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    await query.answer()
    user = query.from_user

    if await blocked_guard(update, context):
        return

    if not forced_join_enabled():
        try:
            await query.message.delete()
        except Exception:
            pass
        update_forced_join_msg_id(user.id, None)
        await query.message.reply_text(
            f"{pemoji(P_OK, '✅')} جوین اجباری غیرفعال است.",
            parse_mode=ParseMode.HTML,
            reply_markup=get_home_keyboard(user.id)
        )
        return

    joined = await is_user_joined_required_channel(user.id, context)
    if not joined:
        try:
            await query.message.delete()
        except Exception:
            pass
        await query.answer("❌ هنوز عضو نشدی.", show_alert=True)
        fake_update = Update(update.update_id, message=query.message)
        await send_forced_join_message(fake_update, context)
        return

    try:
        await query.message.delete()
    except Exception:
        pass

    update_forced_join_msg_id(user.id, None)
    await query.message.reply_text(
        f"{pemoji(P_OK, '✅')} عضویت شما تأیید شد.",
        parse_mode=ParseMode.HTML,
        reply_markup=get_home_keyboard(user.id)
    )


async def user_send_tron_hash_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await blocked_guard(update, context):
        return
    if not await ensure_forced_join(update, context):
        return
    await deposit_manager.start_waiting_for_tron_hash(update, context)


async def user_send_ton_hash_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if await blocked_guard(update, context):
        return
    if not await ensure_forced_join(update, context):
        return
    await deposit_manager.start_waiting_for_ton_hash(update, context)


async def deposit_back_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user_id = update.effective_user.id
    await deposit_manager.deposit_back_callback(update, context, get_home_keyboard(user_id))


async def ton_review_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user_id = update.effective_user.id
    if not is_admin(user_id):
        await update.callback_query.answer("⛔ دسترسی ندارید.", show_alert=True)
        return
    await deposit_manager.handle_ton_review_callback(update, context)

async def start_broadcast(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user_id = update.effective_user.id

    if not is_owner(user_id):
        await update.message.reply_text("⛔ فقط مالک می‌تواند فور همگانی بزند.")
        return

    context.user_data.clear()
    context.user_data["flow"] = "broadcast_wait"

    await update.message.reply_text(
        "📢 لطفاً پیام همگانی را ارسال کنید:",
        reply_markup=only_back_keyboard()
    )


async def process_broadcast(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user_id = update.effective_user.id

    if not is_owner(user_id):
        return False

    if context.user_data.get("flow") != "broadcast_wait":
        return False

    text = (update.message.text or "").strip()

    if text == "🔙 بازگشت":
        context.user_data.clear()
        await update.message.reply_text(
            "↩️ به پنل مدیریت برگشتی.",
            reply_markup=get_admin_panel_keyboard(user_id)
        )
        return True

    cur.execute("SELECT user_id FROM users")
    users = cur.fetchall()

    sent_count = 0
    blocked_count = 0

    for row in users:
        target_id = int(row["user_id"])
        try:
            await context.bot.copy_message(
                chat_id=target_id,
                from_chat_id=update.effective_chat.id,
                message_id=update.message.message_id
            )
            set_user_bot_blocked(target_id, 0)
            sent_count += 1
        except Exception:
            set_user_bot_blocked(target_id, 1)
            blocked_count += 1

    context.user_data.clear()

    await update.message.reply_text(
        f"✅ فور همگانی انجام شد.\n\n"
        f"📤 ارسال موفق: {format_money(sent_count)}\n\n"
        f"⭕️ بلاک/ناموفق: {format_money(blocked_count)}",
        reply_markup=get_admin_panel_keyboard(user_id)
    )

    return True

async def message_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_chat and update.effective_chat.type != "private":
        return

    if not update.message:
        return

    user = update.effective_user
    text = (update.message.text or "").strip()
    username = format_username(user.username)
    first_name = user.first_name or "کاربر"

    create_or_update_user(user.id, username, first_name)

    if await blocked_guard(update, context):
        return

    if text != "/start":
        ok = await ensure_forced_join(update, context)
        if not ok:
            return

    if await sharz_manager.handle_charge_steps(update, context):
        return

    if await process_admin_steps(update, context):
        return

    if await process_broadcast(update, context):
        return

    if text == "🔙 بازگشت":
        flow = context.user_data.get("flow")

        if flow in {"user_buy_operator_menu", "user_buy_charge_packs"}:
            await sharz_manager.delete_buy_messages(context, update.effective_chat.id)
            await delete_last_user_panel_message(update, context)
            context.user_data.clear()
            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} <b>منوی کاربر</b>",
                parse_mode=ParseMode.HTML,
                reply_markup=get_home_keyboard(user.id)
            )
            return

        if flow == "user_buy_charge_result":
            context.user_data.clear()
            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} <b>منوی کاربر</b>",
                parse_mode=ParseMode.HTML,
                reply_markup=get_home_keyboard(user.id)
            )
            return

        if flow in {
            "user_deposit_menu",
            "user_tron_deposit",
            "user_tron_hash_wait",
            "user_ton_deposit",
            "user_ton_hash_wait",
        }:
            await deposit_manager.delete_deposit_info_message(update, context)
            context.user_data.clear()
            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} <b>منوی کاربر</b>",
                parse_mode=ParseMode.HTML,
                reply_markup=get_home_keyboard(user.id)
            )
            return

        if flow == "admin":
            context.user_data.clear()
            await update.message.reply_text(
                f"{pemoji(P_OK, '✅')} به پنل مدیریت برگشتی.",
                parse_mode=ParseMode.HTML,
                reply_markup=get_admin_panel_keyboard(user.id)
            )
            return

        await delete_last_user_panel_message(update, context)
        context.user_data.clear()
        await update.message.reply_text(
            f"{pemoji(P_OK, '✅')} <b>منوی اصلی</b>",
            parse_mode=ParseMode.HTML,
            reply_markup=get_home_keyboard(user.id)
        )
        return

    if context.user_data.get("flow") == "user_tron_hash_wait":
        await deposit_manager.process_user_tron_hash(
            update,
            context,
            text,
            get_home_keyboard(user.id)
        )
        return

    if context.user_data.get("flow") == "user_ton_hash_wait":
        await deposit_manager.process_user_ton_hash(update, context)
        return

    if text == "از طریق تون":
        await delete_last_user_panel_message(update, context)
        await deposit_manager.show_ton_deposit_info(update, context)
        return

    if text == "از طریق ترون":
        await delete_last_user_panel_message(update, context)
        await deposit_manager.show_tron_deposit_info(update, context)
        return

    if text == "🛒 خرید شارژ":
        await show_buy_menu(update, context)
        return

    if text == "💳 افزایش موجودی":
        await show_deposit_menu(update, context)
        return

    if text == "🔒 حساب کاربری" or text == "👤 حساب کاربری":
        await show_account(update, context)
        return

    if text == "💻 پشتیبانی" or text == "📞 پشتیبانی":
        await show_support(update, context)
        return

    if text == "🧾 راهنما" or text == "📚 راهنما":
        await show_help(update, context)
        return

    if text == "👑 پنل مدیریت":
        await open_admin_panel(update, context)
        return

    if text == "🏠 بازگشت به پنل کاربر":
        await back_to_user_panel(update, context)
        return

    if text == "📢 فور همگانی":
        await start_broadcast(update, context)
        return

    action_map = {
        "💰 افزایش موجودی کاربر": "increase_balance",
        "💸 کاهش موجودی کاربر": "decrease_balance",
        "➕ افزودن ادمین": "add_admin",
        "➖ حذف ادمین": "remove_admin",
        "⛔ بلاک کاربر": "block_user",
        "✅ آن‌بلاک کاربر": "unblock_user",
        "🔎 جستجوی کاربر": "search_user",
        "➕ افزودن جوین اجباری": "set_forced_join",
        "➖ حذف جوین اجباری": "remove_forced_join",
        "📦 افزودن شارژ": "add_charge_menu",
    }

    if text == "📊 آمار کاربران":
        await show_users_stats(update, context)
        return

    if text in action_map:
        await begin_admin_action(update, context, action_map[text])
        return

    await update.message.reply_text(
        f"{pemoji(P_WARN, '⚠️')} از دکمه‌های ربات استفاده کن.",
        parse_mode=ParseMode.HTML,
        reply_markup=get_home_keyboard(user.id)
    )

async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE):
    logger.error("Unhandled exception:", exc_info=context.error)


def main():
    app = Application.builder().token(BOT_TOKEN).build()

    app.add_handler(CommandHandler("start", start))

    app.add_handler(CallbackQueryHandler(charge_back_callback, pattern=r"^charge_back$"))
    app.add_handler(CallbackQueryHandler(charge_back_home_callback, pattern=r"^charge_back_home$"))
    app.add_handler(CallbackQueryHandler(handle_buy_callbacks, pattern=r"^buy_"))
    app.add_handler(CallbackQueryHandler(buy_charge_pack_callback, pattern=r"^(buycharge:|charge_unavailable$)"))

    app.add_handler(CallbackQueryHandler(forced_join_callback, pattern=r"^forced_join_check$"))
    app.add_handler(CallbackQueryHandler(user_send_tron_hash_callback, pattern=r"^user_send_tron_hash$"))
    app.add_handler(CallbackQueryHandler(user_send_ton_hash_callback, pattern=r"^user_send_ton_hash$"))
    app.add_handler(CallbackQueryHandler(deposit_back_callback, pattern=r"^deposit_back$"))
    app.add_handler(CallbackQueryHandler(ton_review_callback, pattern=r"^(ton_approve|ton_reject):\d+$"))

    app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, message_handler))
    app.add_error_handler(error_handler)

    logger.info("Bot is running...")

    app.run_polling(
        drop_pending_updates=False,
        allowed_updates=Update.ALL_TYPES
    )


if __name__ == "__main__":
    main()
