import os
import json
import logging
import telebot
from telebot import types
from telebot.types import Message, CallbackQuery
from datetime import datetime, timedelta
import time
import requests.exceptions

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, "data")
LOG_DIR = os.path.join(BASE_DIR, "log")

LANG_FILE = os.path.join(DATA_DIR, "lang.json")
DEFAULT_LANG_FILE = os.path.join(DATA_DIR, "default_lang.json")
USERS_FILE = os.path.join(DATA_DIR, "users.json")
CONFIG_FILE = os.path.join(BASE_DIR, "config.json")
GUIDES_FILE = os.path.join(DATA_DIR, "guides.json")
PRODUCTS_FILE = os.path.join(DATA_DIR, "products.json")
TRANSACTIONS_FILE = os.path.join(DATA_DIR, "transactions.json")
LOG_FILE = os.path.join(LOG_DIR, "bot.log")

os.makedirs(DATA_DIR, exist_ok=True)
os.makedirs(LOG_DIR, exist_ok=True)

logging.basicConfig(filename=LOG_FILE, level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")

def safe_send_message(chat_id, text, **kwargs):
    try:
        def escape_markdown(text):
            if not text:
                return ""
            chars = ["_", "*", "[", "]", "(", ")", "~", "`", ">", "#", "+", "-", "=", "|", "{", "}", ".", "!"]
            for char in chars:
                text = text.replace(char, f"\\{char}")
            return text

        text = escape_markdown(text) if kwargs.get("parse_mode") == "Markdown" else text
        for attempt in range(3):
            try:
                bot.send_message(chat_id, text, **kwargs)
                return True
            except Exception as e:
                if "message is too long" in str(e):
                    return False  # برای پیام‌های طولانی بدون تلاش مجدد خطا برگردون
                logging.error(f"safe_send_message error: {e}")
                time.sleep(20)
        bot.send_message(chat_id, get_lang("user_message_failed"))
        return False
    except Exception as e:
        logging.error(f"safe_send_message error: {e}")
        return False
        
def safe_send_photo(chat_id, photo, caption=None, **kwargs):
    try:
        def escape_markdown(text):
            if not text:
                return ""
            chars = ["_", "*", "[", "]", "(", ")", "~", "`", ">", "#", "+", "-", "=", "|", "{", "}", ".", "!"]
            for char in chars:
                text = text.replace(char, f"\\{char}")
            return text

        caption = escape_markdown(caption) if caption and kwargs.get("parse_mode") == "Markdown" else caption
        for attempt in range(3):
            try:
                bot.send_photo(chat_id, photo, caption=caption, **kwargs)
                return True
            except (requests.exceptions.RequestException, Exception) as e:
                logging.error(f"safe_send_photo error: {e}")
                time.sleep(20)
        bot.send_message(chat_id, get_lang("user_message_failed"))
        return False
    except Exception as e:
        logging.error(f"safe_send_photo error: {e}")
        return False

def safe_send_document(chat_id, document, caption=None, **kwargs):
    try:
        def escape_markdown(text):
            if not text:
                return ""
            chars = ["_", "*", "[", "]", "(", ")", "~", "`", ">", "#", "+", "-", "=", "|", "{", "}", ".", "!"]
            for char in chars:
                text = text.replace(char, f"\\{char}")
            return text

        caption = escape_markdown(caption) if caption and kwargs.get("parse_mode") == "Markdown" else caption
        for attempt in range(3):
            try:
                bot.send_document(chat_id, document, caption=caption, **kwargs)
                return True
            except (requests.exceptions.RequestException, Exception) as e:
                logging.error(f"safe_send_document error: {e}")
                time.sleep(20)
        bot.send_message(chat_id, get_lang("user_message_failed"))
        return False
    except Exception as e:
        logging.error(f"safe_send_document error: {e}")
        return False

def load_json(path, default=None):
    try:
        if not os.path.exists(path) or not os.path.isfile(path):
            with open(path, "w", encoding="utf-8") as f:
                json.dump(default if default is not None else {}, f, indent=2, ensure_ascii=False)
            return default if default is not None else {}
        with open(path, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception as e:
        logging.error(f"Failed to load JSON from {path}: {e}")
        return default if default is not None else {}
    
def save_json(path, data):
    try:
        with open(path, "w", encoding="utf-8") as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
    except Exception as e:
        logging.error(f"Failed to save JSON to {path}: {e}")


       
def format_number(number):
    try:
        return "{:,}".format(int(number))
    except (ValueError, TypeError):
        return str(number)
    
lang = load_json(LANG_FILE, {})
config = load_json(CONFIG_FILE)
users = load_json(USERS_FILE)
products = load_json(PRODUCTS_FILE)
transactions = load_json(TRANSACTIONS_FILE)

BOT_TOKEN = config.get("bot_token", "")
STORE_NAME = config.get("store_name", "")

bot = telebot.TeleBot(BOT_TOKEN)
user_states = {}
add_product_states = {}
admin_reply_states = {}
add_guide_states = {}

def get_lang(key):
    return lang.get(key, key)

def is_admin(user_id):
    try:
        user_id = str(user_id)
        admin_ids = config.get("admin_ids", [])
        # اطمینان از اینکه admin_ids یک لیست است
        if not isinstance(admin_ids, list):
            logging.error(f"admin_ids is not a list: {admin_ids}")
            return False
        result = user_id in [str(aid) for aid in admin_ids]  # تبدیل تمام آیدی‌ها به رشته برای مقایسه
        logging.info(f"Checking is_admin for user {user_id}: {result}, admin_ids: {admin_ids}")
        return result
    except Exception as e:
        logging.error(f"is_admin error: {e}")
        return False

def ensure_user(user):
    try:
        if str(user.id) not in users:
            users[str(user.id)] = {
                "id": user.id,
                "first_name": user.first_name,
                "username": user.username,
                "warnings": 0,
                "received_products": 0,
                "banned": False,
                "last_support_time": "",
                "wallet_balance": 0
            }
            save_json(USERS_FILE, users)
    except Exception as e:
        logging.error(f"Error registering user {user.id}: {e}")

def is_banned(user_id):
    return users.get(str(user_id), {}).get("banned", False)

def cleanup_states():
    try:
        now = datetime.now()
        timeout = timedelta(hours=1)
        for user_id in list(user_states.keys()):
            if user_id not in users:
                user_states.pop(user_id, None)
        for user_id in list(add_product_states.keys()):
            if user_id not in users:
                add_product_states.pop(user_id, None)
        for user_id in list(admin_reply_states.keys()):
            if user_id not in users:
                admin_reply_states.pop(user_id, None)
    except Exception as e:
        logging.error(f"cleanup_states error: {e}")
        
def check_support_message_permission(user_id):
    try:
        user_data = users.get(str(user_id), {})
        limit_count = config.get("support_msg_limit", 8)
        limit_time = config.get("support_msg_window_sec", 30)
        block_duration = config.get("support_block_duration_sec", 100)

        now = datetime.now()

        # اگر کاربر در حالت بلاک هست
        block_until_str = user_data.get("support_block_until", "")
        if block_until_str:
            try:
                block_until = datetime.fromisoformat(block_until_str)
                if now < block_until:
                    remaining = (block_until - now).seconds
                    return False, get_lang("support_blocked_message").replace("{seconds}", str(remaining))
            except:
                pass  # در صورت فرمت اشتباه بلاک را نادیده بگیر

        # لیست زمانی پیام‌های اخیر در بازه محدودیت
        timestamps = user_data.get("support_msg_timestamps", [])
        valid_timestamps = [
            ts for ts in timestamps if now - datetime.fromisoformat(ts) < timedelta(seconds=limit_time)
        ]

        if len(valid_timestamps) >= limit_count:
            block_until_time = now + timedelta(seconds=block_duration)
            users[str(user_id)]["support_block_until"] = block_until_time.isoformat()
            users[str(user_id)]["support_msg_timestamps"] = valid_timestamps
            save_json(USERS_FILE, users)
            return False, get_lang("support_blocked_message").replace("{seconds}", str(block_duration))

        # اضافه کردن زمان جدید به لیست
        valid_timestamps.append(now.isoformat())
        users[str(user_id)]["support_msg_timestamps"] = valid_timestamps
        save_json(USERS_FILE, users)

        return True, ""
    except Exception as e:
        logging.error(f"check_support_message_permission error: {e}")
        return False, get_lang("support_error_message")

def get_main_keyboard(user_id):
    try:
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("store_button"))
        if config.get("wallet_enabled", True):
            kb.row(get_lang("support_button"), get_lang("wallet_button"))
        else:
            kb.row(get_lang("support_button"))
        kb.row(get_lang("guide_button"))
        kb.row(get_lang("profile_button"))
        if is_admin(user_id):
            kb.row(get_lang("admin_manage_products"), get_lang("admin_statistics"))
            kb.row(get_lang("admin_settings"), get_lang("admin_global_message"))
            kb.row(get_lang("admin_unanswered_supports"))
        logging.info(f"Generating main keyboard for user {user_id}, is_admin: {is_admin(user_id)}")
        return kb
    except Exception as e:
        logging.error(f"get_main_keyboard error: {e}")
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("store_button"), get_lang("profile_button"))
        return kb
    
def get_settings_keyboard(user_id):
    try:
        logging.info(f"Generating settings keyboard for user {user_id}, is_admin: {is_admin(user_id)}")
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        wallet_button = get_lang("disable_wallet_button") if config.get("wallet_enabled", True) else get_lang("enable_wallet_button")
        if is_admin(user_id):
            kb.row(get_lang("change_store_name"), get_lang("change_card_info_button"))
            kb.row(get_lang("admin_set_transaction_group"), get_lang("admin_user_list_button"))
            kb.row(get_lang("admin_set_support_limits"), get_lang("admin_manage_lang_file"))
            kb.row(get_lang("admin_manage_guides"), get_lang("admin_manage_channels"))
            kb.row(get_lang("admin_reload_json"), get_lang("admin_reset_bot"))
            kb.row(wallet_button)
        kb.row(get_lang("back_button"))
        return kb
    except Exception as e:
        logging.error(f"get_settings_keyboard error: {e}")
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("back_button"))
        return kb

# channels
@bot.message_handler(func=lambda m: m.text == get_lang("admin_manage_channels"))
def handle_manage_channels(message: Message):
    try:
        user_id = message.from_user.id
        logging.info(f"User {user_id} clicked manage_channels")
        channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
        kb = types.InlineKeyboardMarkup()
        for channel in channels:
            kb.add(types.InlineKeyboardButton(channel["name"], callback_data=f"view_channel_{channel['id']}"))
        kb.add(types.InlineKeyboardButton(get_lang("admin_add_channel"), callback_data="add_channel"))
        safe_send_message(message.chat.id, get_lang("select_channel"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_manage_channels error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("view_channel_"))
def handle_view_channel(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        channel_id = call.data.split("_")[2]
        channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
        channel = next((c for c in channels if c["id"] == channel_id), None)
        if not channel:
            bot.answer_callback_query(call.id, get_lang("channel_not_found"))
            return
        chat = bot.get_chat(channel["chat_id"])
        members_count = bot.get_chat_member_count(channel["chat_id"])
        text = (
            f"📢 <b>{channel['name']}</b>\n"
            f"🆔 ID: {channel['chat_id']}\n"
            f"🔗 Link: {channel.get('link', '-')}\n"
            f"👤 Username: {channel.get('username', '-')}\n"
            f"👥 Members: {members_count}\n"
            f"📊 Successful Joins: {channel.get('successful_joins', 0)}\n"
            f"📝 Description: {chat.description or '-'}\n"
            f"📌 Type: {chat.type}"
        )
        kb = types.InlineKeyboardMarkup()
        kb.add(types.InlineKeyboardButton(get_lang("delete_channel"), callback_data=f"delete_channel_{channel_id}"))
        kb.add(types.InlineKeyboardButton(get_lang("back_to_channels"), callback_data="manage_channels"))
        bot.edit_message_text(text, call.message.chat.id, call.message.message_id, parse_mode="HTML", reply_markup=kb)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_view_channel error: {e}")
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))
        
@bot.callback_query_handler(func=lambda c: c.data == "manage_channels")
def handle_back_to_channels(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        logging.info(f"User {user_id} clicked back_to_channels")
        channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
        kb = types.InlineKeyboardMarkup()
        for channel in channels:
            kb.add(types.InlineKeyboardButton(channel["name"], callback_data=f"view_channel_{channel['id']}"))
        kb.add(types.InlineKeyboardButton(get_lang("admin_add_channel"), callback_data="add_channel"))
        bot.edit_message_text(
            get_lang("select_channel"),
            call.message.chat.id,
            call.message.message_id,
            reply_markup=kb
        )
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_back_to_channels error: {e}")
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data.startswith("delete_channel_"))
def handle_delete_channel(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        channel_id = call.data.split("_")[2]
        channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
        channels = [c for c in channels if c["id"] != channel_id]
        save_json(os.path.join(DATA_DIR, "channels.json"), channels)
        safe_send_message(call.message.chat.id, get_lang("channel_deleted"), reply_markup=get_settings_keyboard(user_id))
        bot.delete_message(call.message.chat.id, call.message.message_id)
        bot.answer_callback_query(call.id)
        call.data = "manage_channels"
        handle_manage_channels(call.message)
    except Exception as e:
        logging.error(f"handle_delete_channel error: {e}")
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data == "add_channel")
def handle_add_channel(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        logging.info(f"User {user_id} clicked add_channel")
        user_states[user_id] = "awaiting_channel_name"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(call.message.chat.id, get_lang("enter_channel_name"), reply_markup=kb)
        bot.delete_message(call.message.chat.id, call.message.message_id)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_add_channel error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(call.message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_channel_name")
def handle_channel_name(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            add_guide_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))
        if not message.text:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("text_only"), reply_markup=kb)
        add_guide_states[user_id] = {"name": message.text}
        user_states[user_id] = "awaiting_channel_id"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("enter_channel_id"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_channel_name error: {e}")
        user_states.pop(user_id, None)
        add_guide_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_channel_id")
def handle_channel_id(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            add_guide_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))
        if not message.text:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("text_only"), reply_markup=kb)
        
        channel_input = message.text.strip()
        channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
        channel_id = str(int(datetime.now().timestamp()))
        channel_data = {"id": channel_id, "name": add_guide_states[user_id]["name"], "successful_joins": 0}

        # بررسی ورودی به عنوان لینک یا آیدی
        if channel_input.startswith("https://t.me/") or channel_input.startswith("@"):
            username = channel_input.split("/")[-1] if channel_input.startswith("https://") else channel_input[1:]
            link = f"https://t.me/{username}"
            try:
                chat = bot.get_chat(f"@{username}")
                channel_data["chat_id"] = chat.id
                channel_data["username"] = f"@{username}"
                channel_data["link"] = link
            except Exception as e:
                logging.error(f"Invalid channel {channel_input}: {e}")
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("invalid_channel_id"), reply_markup=kb)
        elif channel_input.lstrip("-").isdigit():
            try:
                chat = bot.get_chat(int(channel_input))
                channel_data["chat_id"] = chat.id
                channel_data["username"] = f"@{chat.username}" if chat.username else "-"
                channel_data["link"] = f"https://t.me/{chat.username}" if chat.username else "-"
            except Exception as e:
                logging.error(f"Invalid channel ID {channel_input}: {e}")
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("invalid_channel_id"), reply_markup=kb)
        else:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_channel_id"), reply_markup=kb)

        # بررسی وجود کانال/گروه با chat_id مشابه
        if any(c["chat_id"] == channel_data["chat_id"] for c in channels):
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("channel_already_exists"), reply_markup=kb)

        channels.append(channel_data)
        save_json(os.path.join(DATA_DIR, "channels.json"), channels)
        user_states.pop(user_id, None)
        add_guide_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("channel_added"), reply_markup=get_settings_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_channel_id error: {e}")
        user_states.pop(user_id, None)
        add_guide_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

# checking
def check_channel_membership(user_id):
    try:
        channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
        not_joined = []
        for channel in channels:
            try:
                chat_member = bot.get_chat_member(channel["chat_id"], user_id)
                if chat_member.status not in ["member", "administrator", "creator"]:
                    not_joined.append(channel)
            except Exception as e:
                logging.error(f"check_channel_membership error for user {user_id}, channel {channel['chat_id']}: {e}")
                not_joined.append(channel)
        return not_joined
    except Exception as e:
        logging.error(f"check_channel_membership error: {e}")
        return []
    
def show_channel_buttons(chat_id, user_id, not_joined_channels):
    try:
        if not not_joined_channels:
            return False, get_main_keyboard(user_id)
        kb = types.InlineKeyboardMarkup()
        for channel in not_joined_channels:
            link = channel.get("link", f"https://t.me/{channel['username']}" if channel.get("username") else "#")
            kb.add(types.InlineKeyboardButton(channel["name"], url=link))
        kb.add(types.InlineKeyboardButton(get_lang("check_membership_button"), callback_data="check_membership"))
        safe_send_message(chat_id, get_lang("join_channels_required"), reply_markup=kb, parse_mode="HTML")
        return True, None
    except Exception as e:
        logging.error(f"show_channel_buttons error: {e}")
        safe_send_message(chat_id, get_lang("error_occurred"))
        return False, get_main_keyboard(user_id)

@bot.callback_query_handler(func=lambda c: c.data == "check_membership")
def handle_check_membership(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        not_joined_channels = check_channel_membership(user_id)
        if not not_joined_channels:
            channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
            for channel in channels:
                try:
                    chat_member = bot.get_chat_member(channel["chat_id"], user_id)
                    if chat_member.status in ["member", "administrator", "creator"]:
                        channel["successful_joins"] = channel.get("successful_joins", 0) + 1
                except Exception as e:
                    logging.error(f"handle_check_membership error for channel {channel['chat_id']}: {e}")
            save_json(os.path.join(DATA_DIR, "channels.json"), channels)
            bot.answer_callback_query(call.id, get_lang("membership_confirmed"))
            bot.delete_message(call.message.chat.id, call.message.message_id)
            safe_send_message(call.message.chat.id, get_lang("back_to_main_menu"), reply_markup=get_main_keyboard(user_id))
        else:
            bot.answer_callback_query(call.id, get_lang("not_joined_all_channels"))
            bot.delete_message(call.message.chat.id, call.message.message_id)
            show_channel_buttons(call.message.chat.id, user_id, not_joined_channels)
    except Exception as e:
        logging.error(f"handle_check_membership error: {e}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))
# channels

# wallet on/off
@bot.message_handler(func=lambda m: m.text in [get_lang("enable_wallet_button"), get_lang("disable_wallet_button")])
def handle_toggle_wallet(message: Message):
    try:
        user_id = message.from_user.id
        if not is_admin(user_id):
            return safe_send_message(message.chat.id, get_lang("not_admin"))
        config["wallet_enabled"] = not config.get("wallet_enabled", True)
        save_json(CONFIG_FILE, config)
        safe_send_message(message.chat.id, get_lang("settings_updated"), reply_markup=get_settings_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_toggle_wallet error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))
# wallet on/off

def load_guides():
    return load_json(GUIDES_FILE, [])

@bot.message_handler(func=lambda m: m.text == get_lang("admin_manage_guides"))
def handle_manage_guides(message: Message):
    try:
        user_id = message.from_user.id
        logging.info(f"User {user_id} clicked manage_guides")
        guides = load_guides()
        kb = types.InlineKeyboardMarkup()
        for guide in guides:
            kb.add(types.InlineKeyboardButton(f"{guide['name']} (حذف)", callback_data=f"delete_guide_{guide['id']}"))
        kb.add(types.InlineKeyboardButton(get_lang("admin_add_guide"), callback_data="add_guide"))
        safe_send_message(message.chat.id, get_lang("select_guide"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_manage_guides error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data.startswith("delete_guide_"))
def handle_delete_guide(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        guide_id = call.data.split("_")[2]
        guides = load_guides()
        guide = next((g for g in guides if g["id"] == guide_id), None)
        if not guide:
            bot.answer_callback_query(call.id, get_lang("guide_not_found"))
            return
        transaction_group = config.get("transaction_group", "")
        if transaction_group:
            for file_id in guide.get("file_ids", []):
                try:
                    bot.delete_message(transaction_group, file_id)
                except Exception as e:
                    logging.error(f"Failed to delete message {file_id}: {e}")
        guides = [g for g in guides if g["id"] != guide_id]
        save_json(GUIDES_FILE, guides)
        safe_send_message(call.message.chat.id, get_lang("guide_deleted"), reply_markup=get_settings_keyboard(user_id))
        bot.delete_message(call.message.chat.id, call.message.message_id)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_delete_guide error: {e}")
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data == "add_guide")
def handle_add_guide(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        logging.info(f"User {user_id} clicked add_guide")
        user_states[user_id] = "awaiting_guide_name"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(call.message.chat.id, get_lang("enter_guide_name"), reply_markup=kb)
        bot.delete_message(call.message.chat.id, call.message.message_id)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_add_guide error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(call.message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_guide_name")
def handle_guide_name(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            add_guide_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))
        if not message.text:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("text_only"), reply_markup=kb)
        add_guide_states[user_id] = {"name": message.text, "files": []}
        user_states[user_id] = "awaiting_guide_description"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("enter_guide_description"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_guide_name error: {e}")
        user_states.pop(user_id, None)
        add_guide_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_guide_description")
def handle_guide_description(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            add_guide_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))
        if not message.text:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("text_only"), reply_markup=kb)
        add_guide_states[user_id]["description"] = message.text
        user_states[user_id] = "awaiting_guide_files"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"), get_lang("finish_upload"))
        safe_send_message(message.chat.id, get_lang("send_guide_files"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_guide_description error: {e}")
        user_states.pop(user_id, None)
        add_guide_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(content_types=["text", "photo", "video", "document", "audio"], func=lambda m: user_states.get(m.from_user.id) == "awaiting_guide_files")
def handle_guide_files(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            add_guide_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))
        if message.text == get_lang("finish_upload"):
            guides = load_guides()
            guide_id = str(len(guides) + 1)
            guide = add_guide_states[user_id]
            guide["id"] = guide_id
            transaction_group = config.get("transaction_group_id", None)
            logging.info(f"Transaction group in handle_guide_files: {transaction_group}")
            if not transaction_group:
                user_states.pop(user_id, None)
                add_guide_states.pop(user_id, None)
                return safe_send_message(message.chat.id, get_lang("no_transaction_group"), reply_markup=get_settings_keyboard(user_id))
            guide["file_ids"] = []
            for file in guide["files"]:
                sent_message = None
                caption = f"📚 راهنما: {guide['name']}"  # افزودن کپشن برای مشخص شدن راهنما
                if file["type"] == "text":
                    sent_message = bot.send_message(transaction_group, f"{caption}\n{file['content']}")
                elif file["type"] == "photo":
                    sent_message = bot.send_photo(transaction_group, file["content"], caption=caption)
                elif file["type"] == "video":
                    sent_message = bot.send_video(transaction_group, file["content"], caption=caption)
                elif file["type"] == "document":
                    sent_message = bot.send_document(transaction_group, file["content"], caption=caption)
                elif file["type"] == "audio":
                    sent_message = bot.send_audio(transaction_group, file["content"], caption=caption)
                if sent_message:
                    guide["file_ids"].append(sent_message.message_id)
            guides.append(guide)
            save_json(GUIDES_FILE, guides)
            user_states.pop(user_id, None)
            add_guide_states.pop(user_id, None)
            safe_send_message(message.chat.id, get_lang("guide_added"), reply_markup=get_settings_keyboard(user_id))
            return
        file_info = {}
        if message.text:
            file_info = {"type": "text", "content": message.text}
        elif message.photo:
            file_info = {"type": "photo", "content": message.photo[-1].file_id}
        elif message.video:
            file_info = {"type": "video", "content": message.video.file_id}
        elif message.document:
            file_info = {"type": "document", "content": message.document.file_id}
        elif message.audio:
            file_info = {"type": "audio", "content": message.audio.file_id}
        add_guide_states[user_id]["files"].append(file_info)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"), get_lang("finish_upload"))
        safe_send_message(message.chat.id, get_lang("file_received"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_guide_files error: {e}")
        user_states.pop(user_id, None)
        add_guide_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("guide_button"))
def handle_get_guides(message: Message):
    try:
        user_id = message.from_user.id
        not_joined_channels = check_channel_membership(user_id)
        sent_channels, keyboard = show_channel_buttons(message.chat.id, user_id, not_joined_channels)
        if sent_channels:
            return
        logging.info(f"User {user_id} clicked guide_button")
        guides = load_guides()
        if not guides:
            return safe_send_message(message.chat.id, get_lang("no_guides_available"), reply_markup=get_main_keyboard(user_id))
        kb = types.InlineKeyboardMarkup()
        for guide in guides:
            kb.add(types.InlineKeyboardButton(guide["name"], callback_data=f"guide_{guide['id']}"))
        safe_send_message(message.chat.id, get_lang("select_guide"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_get_guides error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data.startswith("guide_"))
def handle_guide_selection(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        guide_id = call.data.split("_")[1]
        guides = load_guides()
        guide = next((g for g in guides if g["id"] == guide_id), None)
        if not guide:
            bot.answer_callback_query(call.id, get_lang("guide_not_found"))
            return
        safe_send_message(call.message.chat.id, f"<b>{guide['name']}</b>\n{guide['description']}", parse_mode="HTML")
        for file in guide.get("files", []):
            try:
                if file["type"] == "text":
                    safe_send_message(call.message.chat.id, file["content"], parse_mode="HTML")
                elif file["type"] == "photo":
                    bot.send_photo(call.message.chat.id, file["content"], caption=f"📸 {guide['name']}")
                elif file["type"] == "video":
                    bot.send_video(call.message.chat.id, file["content"], caption=f"🎥 {guide['name']}")
                elif file["type"] == "document":
                    bot.send_document(call.message.chat.id, file["content"], caption=f"📄 {guide['name']}")
                elif file["type"] == "audio":
                    bot.send_audio(call.message.chat.id, file["content"], caption=f"🎵 {guide['name']}")
            except Exception as e:
                logging.error(f"Failed to send guide file {file['content']}: {e}")
                safe_send_message(call.message.chat.id, get_lang("file_send_failed"), parse_mode="HTML")
        bot.delete_message(call.message.chat.id, call.message.message_id)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_guide_selection error: {e}")
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("admin_manage_lang_file"))
def handle_manage_lang_file(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return
        
        user_states[message.from_user.id] = "awaiting_lang_file_action"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("download_lang_file"), get_lang("upload_lang_file"))
        kb.row(get_lang("load_default_lang"), get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("manage_lang_file_prompt"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_manage_lang_file error: {e}")
        user_states.pop(message.from_user.id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(message.from_user.id))
        
@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_lang_file_action")
def handle_lang_file_action(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))

        if message.text == get_lang("download_lang_file"):
            if not os.path.exists(LANG_FILE):
                return safe_send_message(message.chat.id, get_lang("lang_file_not_found"), reply_markup=get_settings_keyboard(user_id))
            
            # پیام انتظار
            safe_send_message(message.chat.id, get_lang("please_wait_download"))
            
            # ارسال فایل
            with open(LANG_FILE, "rb") as f:
                bot.send_document(message.chat.id, f, caption=get_lang("current_lang_file"))
            safe_send_message(message.chat.id, get_lang("lang_file_downloaded"), reply_markup=get_settings_keyboard(user_id))
            user_states.pop(user_id, None)
            return

        if message.text == get_lang("upload_lang_file"):
            user_states[user_id] = "awaiting_lang_file_upload"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            safe_send_message(message.chat.id, get_lang("send_lang_file"), reply_markup=kb)
            return

        if message.text == get_lang("load_default_lang"):
            if not os.path.exists(DEFAULT_LANG_FILE):
                return safe_send_message(message.chat.id, get_lang("default_lang_file_not_found"), reply_markup=get_settings_keyboard(user_id))
            
            # تغییر نام فایل قدیمی به BAK_lang.json
            bak_file_path = os.path.join(DATA_DIR, "BAK_lang.json")
            if os.path.exists(LANG_FILE):
                os.rename(LANG_FILE, bak_file_path)
            
            # کپی محتوای default_lang.json به lang.json
            with open(DEFAULT_LANG_FILE, "r", encoding="utf-8") as default_f:
                default_lang_data = json.load(default_f)
            save_json(LANG_FILE, default_lang_data)
            
            # به‌روزرسانی متغیر lang
            global lang
            lang = load_json(LANG_FILE, {})
            
            user_states.pop(user_id, None)
            safe_send_message(message.chat.id, get_lang("default_lang_loaded"), reply_markup=get_settings_keyboard(user_id))
            return

        safe_send_message(message.chat.id, get_lang("invalid_action"), reply_markup=get_settings_keyboard(user_id))
        user_states.pop(user_id, None)
    except Exception as e:
        logging.error(f"handle_lang_file_action error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))
        
@bot.message_handler(content_types=["document"], func=lambda m: user_states.get(m.from_user.id) == "awaiting_lang_file_upload")
def handle_lang_file_upload(message: Message):
    try:
        user_id = message.from_user.id
        if not message.document:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("send_json_file_only"), reply_markup=kb)

        if not message.document.file_name.endswith(".json"):
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_file_format"), reply_markup=kb)

        file_info = bot.get_file(message.document.file_id)
        file_path = file_info.file_path
        downloaded_file = bot.download_file(file_path)

        # اعتبارسنجی محتوای فایل JSON
        try:
            new_lang_data = json.loads(downloaded_file.decode("utf-8"))
            if not isinstance(new_lang_data, dict):
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("invalid_json_content"), reply_markup=kb)
        except json.JSONDecodeError:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_json_format"), reply_markup=kb)

        # ذخیره فایل موقت
        temp_file_path = os.path.join(DATA_DIR, "temp_lang.json")
        with open(temp_file_path, "wb") as f:
            f.write(downloaded_file)

        # بررسی نام فایل
        if message.document.file_name != "lang.json":
            user_states[user_id] = f"confirm_lang_file_name:{temp_file_path}"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
            safe_send_message(
                message.chat.id,
                get_lang("invalid_file_name").replace("{file_name}", message.document.file_name),
                reply_markup=kb
            )
            return

        user_states[user_id] = f"confirm_lang_replace:{temp_file_path}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("confirm_lang_replace"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_lang_file_upload error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(content_types=["text"], func=lambda m: user_states.get(m.from_user.id) == "awaiting_lang_file_upload")
def handle_lang_file_upload_text(message: Message):
    try:
        user_id = message.from_user.id

        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(
                message.chat.id,
                get_lang("cancelled"),
                reply_markup=get_settings_keyboard(user_id)
            )

        # اگر متن غیر از لغو فرستاد
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("send_json_file_only"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_lang_file_upload_text error: {e}")
        user_states.pop(message.from_user.id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(message.from_user.id))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id, "").startswith("confirm_lang_file_name:") or user_states.get(m.from_user.id, "").startswith("confirm_lang_replace:"))
def handle_lang_file_confirm(message: Message):
    try:
        user_id = message.from_user.id
        state = user_states[user_id]
        temp_file_path = state.split(":")[1]

        if message.text == get_lang("cancel_button"):
            if os.path.exists(temp_file_path):
                os.remove(temp_file_path)
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))

        if message.text == get_lang("confirm_button"):
            # تغییر نام فایل قدیمی به BAK_lang.json
            bak_file_path = os.path.join(DATA_DIR, "BAK_lang.json")
            if os.path.exists(LANG_FILE):
                os.rename(LANG_FILE, bak_file_path)

            # جایگزینی فایل جدید
            os.rename(temp_file_path, LANG_FILE)

            # به‌روزرسانی متغیر lang
            global lang
            lang = load_json(LANG_FILE, {})

            user_states.pop(user_id, None)
            safe_send_message(message.chat.id, get_lang("lang_file_updated"), reply_markup=get_settings_keyboard(user_id))
        else:
            safe_send_message(message.chat.id, get_lang("invalid_action"), reply_markup=get_settings_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_lang_file_confirm error: {e}")
        if os.path.exists(temp_file_path):
            os.remove(temp_file_path)
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("admin_user_list_button"))
def handle_admin_user_list(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return
        show_user_list_page(message.chat.id, 0)
    except Exception as e:
        logging.error(f"handle_admin_user_list error: {e}")

def show_user_list_page(chat_id, page):
    try:
        user_items = list(users.items())
        per_page = 10
        total_pages = (len(user_items) - 1) // per_page + 1
        start = page * per_page
        end = start + per_page

        markup = types.InlineKeyboardMarkup(row_width=2)
        for user_id, u in user_items[start:end]:
            name = f"{u.get('first_name', '')} @{u.get('username', '-')}"
            btn = types.InlineKeyboardButton(name, callback_data=f"user_info:{user_id}")
            markup.add(btn)

        nav_buttons = []
        if page > 0:
            nav_buttons.append(types.InlineKeyboardButton(get_lang("prev_page"), callback_data=f"user_page:{page-1}"))
        if end < len(user_items):
            nav_buttons.append(types.InlineKeyboardButton(get_lang("next_page"), callback_data=f"user_page:{page+1}"))
        if nav_buttons:
            markup.add(*nav_buttons)

        bot.send_message(chat_id, get_lang("user_list_page").replace("{page}", str(page+1)), reply_markup=markup)

    except Exception as e:
        logging.error(f"show_user_list_page error: {e}")
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("user_page:") or c.data == "user_list:0")
def handle_user_page(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return
        page = int(call.data.split(":")[1]) if call.data.startswith("user_page:") else 0
        bot.delete_message(call.message.chat.id, call.message.message_id)
        show_user_list_page(call.message.chat.id, page)
    except Exception as e:
        logging.error(f"handle_user_page error: {e}")
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("user_info:"))
def handle_user_info(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return

        user_id = call.data.split(":")[1]
        user = users.get(user_id)
        if not user:
            return bot.answer_callback_query(call.id, get_lang("user_not_found"))

        def escape_markdown(text):
            if not text:
                return "-"
            chars = ["_", "*", "[", "]", "(", ")", "~", "`", ">", "#", "+", "-", "=", "|", "{", "}", ".", "!"]
            for char in chars:
                text = text.replace(char, f"\\{char}")
            return text

        first_name = escape_markdown(user.get("first_name", ""))
        username = escape_markdown(user.get("username", "-"))
        currency = config["currency"]

        text = (
            f"{get_lang('your_id')}: `{user['id']}`\n"
            f"{get_lang('your_name')}: {first_name}\n"
            f"{get_lang('your_username')}: @{username}\n"
            f"{get_lang('your_products_received')}: {user.get('received_products', 0)}\n"
            f"{get_lang('your_warnings')}: {user.get('warnings', 0)}\n"
            f"💰 {get_lang('your_wallet_balance')}: {format_number(user.get('wallet_balance', 0))} {currency}\n"
            f"🚫 {get_lang('banned_status')}: {'✅' if user.get('banned') else '❌'}"
        )

        markup = types.InlineKeyboardMarkup()
        if int(user_id) in config.get("admin_ids", []):
            markup.add(types.InlineKeyboardButton(get_lang("message_user_button"), callback_data=f"user_msg:{user_id}"))
            markup.add(types.InlineKeyboardButton(get_lang("back_to_user_list"), callback_data="user_list:0"))
        else:
            if user.get("banned"):
                markup.add(types.InlineKeyboardButton(get_lang("unban_button"), callback_data=f"user_unban:{user_id}"))
            else:
                markup.add(types.InlineKeyboardButton(get_lang("ban_button"), callback_data=f"user_ban:{user_id}"))

            markup.add(
                types.InlineKeyboardButton(get_lang("add_warning_button"), callback_data=f"user_warn:{user_id}"),
                types.InlineKeyboardButton(get_lang("remove_warning_button"), callback_data=f"user_unwarn:{user_id}")
            )
            markup.add(types.InlineKeyboardButton(get_lang("set_wallet_balance_button"), callback_data=f"set_wallet_balance:{user_id}"))
            markup.add(types.InlineKeyboardButton(get_lang("message_user_button"), callback_data=f"user_msg:{user_id}"))
            markup.add(types.InlineKeyboardButton(get_lang("back_to_user_list"), callback_data="user_list:0"))

        bot.edit_message_text(text, call.message.chat.id, call.message.message_id, parse_mode="Markdown", reply_markup=markup)
    except Exception as e:
        logging.error(f"handle_user_info error: {e}")
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("user_ban:"))
def handle_user_ban(call: CallbackQuery):
    user_id = call.data.split(":")[1]
    users[user_id]["banned"] = True
    save_json(USERS_FILE, users)
    call.data = f"user_info:{user_id}"
    handle_user_info(call)

@bot.callback_query_handler(func=lambda c: c.data.startswith("user_unban:"))
def handle_user_unban(call: CallbackQuery):
    try:
        user_id = call.data.split(":")[1]
        user = users.get(user_id)
        if not user:
            return bot.answer_callback_query(call.id, get_lang("user_not_found"))

        users[user_id]["banned"] = False
        if user.get("warnings", 0) == 3:  # اگر کاربر 3 اخطار دارد، اخطارها را ریست کن
            users[user_id]["warnings"] = 0
            safe_send_message(user_id, get_lang("user_unbanned_warnings_reset"))
        save_json(USERS_FILE, users)
        call.data = f"user_info:{user_id}"
        handle_user_info(call)
    except Exception as e:
        logging.error(f"handle_user_unban error: {e}")
        bot.answer_callback_query(call.id, get_lang("settings_update_failed"))
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("user_warn:"))
def handle_user_warn(call: CallbackQuery):
    try:
        user_id = call.data.split(":")[1]
        user = users.get(user_id)
        if not user:
            return bot.answer_callback_query(call.id, get_lang("user_not_found"))

        if int(user_id) in config.get("admin_ids", []):
            return bot.answer_callback_query(call.id, get_lang("cannot_warn_admin"))

        warnings = user.get("warnings", 0)
        if warnings >= 3:
            return bot.answer_callback_query(call.id, get_lang("user_already_banned"))

        users[user_id]["warnings"] = warnings + 1
        if users[user_id]["warnings"] >= 3:
            users[user_id]["banned"] = True
            save_json(USERS_FILE, users)
            safe_send_message(user_id, get_lang("user_banned_after_warnings"))
            bot.answer_callback_query(call.id, get_lang("user_banned_after_warnings_admin").replace("{user_id}", user_id))
        else:
            save_json(USERS_FILE, users)
            safe_send_message(user_id, get_lang("warning_received").replace("{warnings}", str(users[user_id]["warnings"])))
            bot.answer_callback_query(call.id, get_lang("warning_added").replace("{user_id}", user_id).replace("{warnings}", str(users[user_id]["warnings"])))

        call.data = f"user_info:{user_id}"
        handle_user_info(call)
    except Exception as e:
        logging.error(f"handle_user_warn error: {e}")
        bot.answer_callback_query(call.id, get_lang("settings_update_failed"))
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("user_unwarn:"))
def handle_user_unwarn(call: CallbackQuery):
    user_id = call.data.split(":")[1]
    warnings = users[user_id].get("warnings", 0)
    if warnings > 0:
        users[user_id]["warnings"] = warnings - 1
    save_json(USERS_FILE, users)
    call.data = f"user_info:{user_id}"
    handle_user_info(call)

@bot.callback_query_handler(func=lambda c: c.data.startswith("user_msg:"))
def handle_user_message_request(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return
        user_id = call.data.split(":")[1]
        user_states[call.from_user.id] = f"admin_msg_user:{user_id}"
        safe_send_message(call.message.chat.id, get_lang("write_admin_message"))
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_user_message_request error: {e}")

@bot.message_handler(content_types=["text", "photo"], func=lambda m: m.from_user.id in user_states and user_states[m.from_user.id].startswith("admin_msg_user:"))
def handle_user_message_send(message: Message):
    try:
        key = user_states.pop(message.from_user.id)
        user_id = key.split(":")[1]
        if user_id not in users:
            return safe_send_message(message.chat.id, get_lang("user_not_found"))

        now = datetime.now()
        messages_path = os.path.join(DATA_DIR, "messages.json")
        support_messages = load_json(messages_path, {})

        message_data = {
            "user_id": int(user_id),
            "from_admin": True,
            "text": message.caption if message.photo else message.text,
            "time": now.isoformat(),
            "reply": ""
        }

        if message.photo:
            message_data["photo"] = message.photo[-1].file_id
            text = (
                f"📢 {get_lang('message_from_admin')}\n"
                f"{message_data['text']}"
            )
            if not safe_send_photo(int(user_id), message_data["photo"], caption=text):
                return safe_send_message(message.chat.id, get_lang("message_send_failed"))
        else:
            text = (
                f"📢 {get_lang('message_from_admin')}\n"
                f"{message_data['text']}"
            )
            if not safe_send_message(int(user_id), text):
                return safe_send_message(message.chat.id, get_lang("message_send_failed"))

        support_messages[str(int(now.timestamp()))] = message_data
        save_json(messages_path, support_messages)

        safe_send_message(message.chat.id, get_lang("message_sent"))
    except Exception as e:
        logging.error(f"handle_user_message_send error: {e}")
        safe_send_message(message.chat.id, get_lang("message_send_failed"))
        
@bot.message_handler(func=lambda m: m.text == get_lang("admin_settings"))
def handle_admin_settings(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return

        safe_send_message(message.chat.id, get_lang("admin_settings_menu"), reply_markup=get_settings_keyboard(message.from_user.id))
    except Exception as e:
        logging.error(f"handle_admin_settings error: {e}")

@bot.message_handler(func=lambda m: m.text == get_lang("back_button"))
def handle_back_to_main(message: Message):
    try:
        user_id = message.from_user.id
        not_joined_channels = check_channel_membership(user_id)
        sent_channels, keyboard = show_channel_buttons(message.chat.id, user_id, not_joined_channels)
        if sent_channels:
            return
        safe_send_message(message.chat.id, get_lang("back_to_main_menu"), reply_markup=get_main_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_back_to_main error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))
 
@bot.message_handler(func=lambda m: m.text == get_lang("change_store_name"))
def handle_change_store_name(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return
        user_states[message.from_user.id] = "awaiting_new_store_name"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("send_new_store_name"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_change_store_name error: {e}")
        user_states.pop(message.from_user.id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(message.from_user.id))
        
@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_new_store_name")
def handle_new_store_name(message: Message):
    try:
        if message.text == get_lang("cancel_button"):
            user_states.pop(message.from_user.id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(message.from_user.id))

        store_name = message.text.strip()
        if not store_name:
            return safe_send_message(message.chat.id, get_lang("send_new_store_name"))

        config["store_name"] = store_name
        save_json(CONFIG_FILE, config)

        global STORE_NAME
        STORE_NAME = store_name

        user_states.pop(message.from_user.id, None)

        msg = get_lang("store_name_updated").replace("{store_name}", store_name)
        safe_send_message(message.chat.id, msg, parse_mode="HTML", reply_markup=get_settings_keyboard(message.from_user.id))
    except Exception as e:
        logging.error(f"handle_new_store_name error: {e}")
        user_states.pop(message.from_user.id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(message.from_user.id))
        
@bot.message_handler(commands=["start"])
def handle_start(message: Message):
    try:
        user_id = message.from_user.id
        ensure_user(message.from_user)
        not_joined_channels = check_channel_membership(user_id)
        sent_channels, keyboard = show_channel_buttons(message.chat.id, user_id, not_joined_channels)
        if not sent_channels:
            safe_send_message(message.chat.id, get_lang("welcome_message"), reply_markup=keyboard)
    except Exception as e:
        logging.error(f"handle_start error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"))

@bot.message_handler(func=lambda m: m.text == get_lang("admin_reload_json"))
def handle_reload_json_files(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return

        global lang, config, users, products, transactions
        lang = load_json(LANG_FILE)
        config = load_json(CONFIG_FILE)
        users = load_json(USERS_FILE)
        products = load_json(PRODUCTS_FILE)
        transactions = load_json(TRANSACTIONS_FILE)
        
        logging.info(f"Loaded lang keys: {list(lang.keys())}")
        safe_send_message(message.chat.id, get_lang("json_reload_success"), reply_markup=get_settings_keyboard(message.from_user.id))

    except Exception as e:
        logging.error(f"handle_reload_json_files error: {e}")
        safe_send_message(message.chat.id, get_lang("json_reload_failed"), reply_markup=get_settings_keyboard(message.from_user.id))

@bot.message_handler(func=lambda m: m.text == get_lang("admin_set_support_limits"))
def handle_set_support_limits(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return
        user_states[message.from_user.id] = "awaiting_support_msg_limit"
        current_limit = config.get("support_msg_limit", 8)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(
            message.chat.id,
            get_lang("send_support_msg_limit").replace("{current}", str(current_limit)),
            reply_markup=kb
        )
    except Exception as e:
        logging.error(f"handle_set_support_limits error: {e}")

@bot.message_handler(func=lambda m: m.from_user.id in user_states and user_states[m.from_user.id] in [
    "awaiting_support_msg_limit", "awaiting_support_msg_window", "awaiting_support_block_duration"
])
def handle_support_limits_input(message: Message):
    try:
        user_id = message.from_user.id
        state = user_states[user_id]

        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))

        # اگر ورودی عدد نیست
        if not message.text.isdigit() or int(message.text) <= 0:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_number"), reply_markup=kb)

        value = int(message.text)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))

        if state == "awaiting_support_msg_limit":
            add_product_states[user_id] = {"support_msg_limit": value}
            user_states[user_id] = "awaiting_support_msg_window"
            current_window = config.get("support_msg_window_sec", 30)
            safe_send_message(
                message.chat.id,
                get_lang("send_support_msg_window").replace("{current}", str(current_window)),
                reply_markup=kb
            )

        elif state == "awaiting_support_msg_window":
            add_product_states[user_id]["support_msg_window_sec"] = value
            user_states[user_id] = "awaiting_support_block_duration"
            current_duration = config.get("support_block_duration_sec", 100)
            safe_send_message(
                message.chat.id,
                get_lang("send_support_block_duration").replace("{current}", str(current_duration)),
                reply_markup=kb
            )

        elif state == "awaiting_support_block_duration":
            config["support_msg_limit"] = add_product_states[user_id]["support_msg_limit"]
            config["support_msg_window_sec"] = add_product_states[user_id]["support_msg_window_sec"]
            config["support_block_duration_sec"] = value
            save_json(CONFIG_FILE, config)
            user_states.pop(user_id, None)
            add_product_states.pop(user_id, None)
            safe_send_message(message.chat.id, get_lang("support_limits_set"), reply_markup=get_settings_keyboard(user_id))

    except Exception as e:
        logging.error(f"handle_support_limits_input error: {e}")
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(message.from_user.id))

@bot.message_handler(func=lambda m: m.text == get_lang("support_button"))
def handle_support_start(message: Message):
    try:
        if is_banned(message.from_user.id):
            return safe_send_message(message.chat.id, get_lang("banned_message"))

        ok, msg = check_support_message_permission(message.from_user.id)
        if not ok:
            return safe_send_message(message.chat.id, msg)

        user_states[message.from_user.id] = "awaiting_support_message"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("support_prompt"), reply_markup=kb)

    except Exception as e:
        logging.error(f"Support button error: {e}")

@bot.message_handler(content_types=["text", "photo"], func=lambda m: user_states.get(m.from_user.id) == "awaiting_support_message")
def handle_support_message(message: Message):
    try:
        if message.text == get_lang("cancel_button"):
            user_states.pop(message.from_user.id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(message.from_user.id))

        if not message.text and not message.photo:
            return safe_send_message(message.chat.id, get_lang("support_text_or_photo_only"))

        now = datetime.now()
        msg_id = str(int(now.timestamp()))
        messages_path = os.path.join(DATA_DIR, "messages.json")
        support_messages = load_json(messages_path, {})

        support_data = {
            "user_id": message.from_user.id,
            "first_name": message.from_user.first_name,
            "username": message.from_user.username or "-",
            "text": message.caption if message.photo else message.text,
            "time": now.isoformat(),
            "reply": ""
        }

        if message.photo:
            support_data["photo"] = message.photo[-1].file_id

        support_messages[msg_id] = support_data
        save_json(messages_path, support_messages)

        for admin_id in config.get("admin_ids", []):
            markup = types.InlineKeyboardMarkup()
            markup.add(
                types.InlineKeyboardButton(get_lang("reply_button"), callback_data=f"reply_to:{msg_id}"),
                types.InlineKeyboardButton(get_lang("add_warning_button"), callback_data=f"warn_support:{msg_id}")
            )

            user_info = f"👤 <b>کاربر:</b> {message.from_user.first_name} (@{message.from_user.username or '-'})"

            if message.photo:
                caption = (
                    f"{get_lang('new_support_message')}\n"
                    f"{user_info}\n"
                    f"🆔 <code>{message.from_user.id}</code>\n"
                    f"📝 {support_data['text']}"
                )
                safe_send_photo(admin_id, support_data["photo"], caption=caption, parse_mode="HTML", reply_markup=markup)
            else:
                text = (
                    f"{get_lang('new_support_message')}\n"
                    f"{user_info}\n"
                    f"🆔 <code>{message.from_user.id}</code>\n"
                    f"📝 {support_data['text']}"
                )
                safe_send_message(admin_id, text, parse_mode="HTML", reply_markup=markup)

        user_states.pop(message.from_user.id, None)
        safe_send_message(message.chat.id, get_lang("support_sent"), reply_markup=get_main_keyboard(message.from_user.id))

    except Exception as e:
        logging.error(f"Support message error: {e}")
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("reply_to:"))
def handle_reply_button(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return

        msg_id = call.data.split(":")[1]
        messages_path = os.path.join(DATA_DIR, "messages.json")
        support_messages = load_json(messages_path, {})

        if msg_id not in support_messages:
            return bot.answer_callback_query(call.id, get_lang("message_not_found"))

        admin_reply_states[call.from_user.id] = msg_id

        # نمایش کیبورد لغو
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(call.message.chat.id, get_lang("admin_write_reply"), reply_markup=kb)

        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"Reply button error: {e}")

@bot.callback_query_handler(func=lambda c: c.data.startswith("warn_support:"))
def handle_support_warn(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return

        msg_id = call.data.split(":")[1]
        messages_path = os.path.join(DATA_DIR, "messages.json")
        support_messages = load_json(messages_path, {})

        if msg_id not in support_messages:
            return bot.answer_callback_query(call.id, get_lang("message_not_found"))

        user_id = str(support_messages[msg_id]["user_id"])
        user = users.get(user_id, {})
        if not user:
            return bot.answer_callback_query(call.id, get_lang("user_not_found"))

        # بررسی ادمین بودن
        if int(user_id) in config.get("admin_ids", []):
            return bot.answer_callback_query(call.id, get_lang("cannot_warn_admin"))

        warnings = user.get("warnings", 0)
        if warnings >= 3:
            return bot.answer_callback_query(call.id, get_lang("user_already_banned"))

        # افزایش اخطار
        users[user_id]["warnings"] = warnings + 1
        if users[user_id]["warnings"] >= 3:
            users[user_id]["banned"] = True
            save_json(USERS_FILE, users)
            # اطلاع به کاربر
            safe_send_message(user_id, get_lang("user_banned_after_warnings"))
            # اطلاع به ادمین
            bot.answer_callback_query(call.id, get_lang("user_banned_after_warnings_admin").replace("{user_id}", user_id))
        else:
            save_json(USERS_FILE, users)
            # اطلاع به کاربر
            safe_send_message(user_id, get_lang("warning_received").replace("{warnings}", str(users[user_id]["warnings"])))
            # اطلاع به ادمین
            bot.answer_callback_query(call.id, get_lang("warning_added").replace("{user_id}", user_id).replace("{warnings}", str(users[user_id]["warnings"])))

    except Exception as e:
        logging.error(f"handle_support_warn error: {e}")
        bot.answer_callback_query(call.id, get_lang("settings_update_failed"))
        
@bot.message_handler(func=lambda m: m.from_user.id in admin_reply_states)
def handle_admin_reply(message: Message):
    try:
        user_id = message.from_user.id

        # پشتیبانی از دکمه لغو
        if message.text == get_lang("cancel_button"):
            admin_reply_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

        if not message.text:
            return safe_send_message(message.chat.id, get_lang("support_text_or_photo_only"))

        msg_id = admin_reply_states.pop(user_id)
        messages_path = os.path.join(DATA_DIR, "messages.json")
        support_messages = load_json(messages_path, {})

        support_msg = support_messages.get(msg_id)
        if not support_msg:
            return safe_send_message(message.chat.id, get_lang("message_not_found"), reply_markup=get_main_keyboard(user_id))

        target_user_id = support_msg["user_id"]
        response_text = message.text

        # ارسال پاسخ به کاربر
        reply_msg = (
            f"📬 {get_lang('support_reply')}\n"
            f"📝 پیام شما:\n{support_msg['text']}\n\n"
            f"📢 پاسخ ادمین:\n{response_text}"
        )
        if not safe_send_message(target_user_id, reply_msg):
            return safe_send_message(message.chat.id, get_lang("message_send_failed"), reply_markup=get_main_keyboard(user_id))

        # به‌روزرسانی پیام در فایل
        support_msg["reply"] = response_text
        support_msg["reply_time"] = datetime.now().isoformat()
        support_msg["replied_by"] = {
            "id": user_id,
            "username": message.from_user.username or "-",
            "first_name": message.from_user.first_name
        }
        support_messages[msg_id] = support_msg
        save_json(messages_path, support_messages)

        safe_send_message(message.chat.id, get_lang("reply_sent"), reply_markup=get_main_keyboard(user_id))
    except Exception as e:
        logging.error(f"Admin reply handler error: {e}")
        admin_reply_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("admin_unanswered_supports"))
def handle_admin_support_messages(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return

        messages_path = os.path.join(DATA_DIR, "messages.json")
        support_messages = load_json(messages_path, {})

        unanswered = [(msg_id, msg) for msg_id, msg in support_messages.items() if not msg.get("reply")]
        if not unanswered:
            return safe_send_message(message.chat.id, get_lang("no_unanswered_supports"))

        for msg_id, msg in unanswered:
            markup = types.InlineKeyboardMarkup()
            markup.add(types.InlineKeyboardButton(get_lang("reply_button"), callback_data=f"reply_to:{msg_id}"))

            first_name = msg.get("first_name", "-")
            username = msg.get("username", "-")
            user_id = msg.get("user_id", "-")

            user_info = f"👤 <b>کاربر:</b> {first_name} (@{username})\n🆔 <code>{user_id}</code>"

            if "photo" in msg:
                caption = f"📨 <b>پیام:</b>\n{msg.get('text', '')}\n\n{user_info}"
                safe_send_photo(message.chat.id, msg["photo"], caption=caption, parse_mode="HTML", reply_markup=markup)
            else:
                text = f"📨 <b>پیام:</b>\n{msg.get('text', '')}\n\n{user_info}"
                safe_send_message(message.chat.id, text, parse_mode="HTML", reply_markup=markup)

    except Exception as e:
        logging.error(f"Handle admin support messages error: {e}")

@bot.message_handler(func=lambda m: m.text == get_lang("profile_button"))
def handle_profile(message: Message):
    try:
        user_id = message.from_user.id
        not_joined_channels = check_channel_membership(user_id)
        sent_channels, keyboard = show_channel_buttons(message.chat.id, user_id, not_joined_channels)
        if sent_channels:
            return
        if is_banned(user_id):
            return safe_send_message(message.chat.id, get_lang("banned_message"))
        user_data = users.get(str(user_id), {})

        def escape_markdown(text):
            if not text:
                return "-"
            chars = ["_", "*", "[", "]", "(", ")", "~", "`", ">", "#", "+", "-", "=", "|", "{", "}", ".", "!"]
            for char in chars:
                text = text.replace(char, f"\\{char}")
            return text

        first_name = escape_markdown(message.from_user.first_name)
        username = message.from_user.username or "-"
        if username != "-":
            username = f"@{username}"
        else:
            username = escape_markdown(username)
        currency = config["currency"]

        text = (
            f"{get_lang('your_id')}: `{message.from_user.id}`\n"
            f"{get_lang('your_name')}: {first_name}\n"
            f"{get_lang('your_username')}: {username}\n"
            f"{get_lang('your_products_received')}: {user_data.get('received_products', 0)}\n"
            f"{get_lang('your_warnings')}: {user_data.get('warnings', 0)}\n"
        )
        if config.get("wallet_enabled", True):
            text += f"💰 {get_lang('your_wallet_balance')}: {format_number(user_data.get('wallet_balance', 0))} {currency}"
        else:
            text += f"💰 {get_lang('wallet_disabled_message')}"
        safe_send_message(message.chat.id, text, parse_mode="Markdown", reply_markup=get_main_keyboard(user_id))
    except Exception as e:
        logging.error(f"Profile handler error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("admin_global_message"))
def handle_global_message_start(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return

        user_states[message.from_user.id] = "awaiting_global_message"

        # فقط دکمه لغو
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))

        safe_send_message(message.chat.id, get_lang("global_message_prompt"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_global_message_start error: {e}")
        user_states.pop(message.from_user.id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(message.from_user.id))

@bot.message_handler(content_types=["text", "photo"], func=lambda m: user_states.get(m.from_user.id) == "awaiting_global_message")
def handle_global_message(message: Message):
    try:
        user_id = message.from_user.id

        # لغو
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

        if not message.text and not message.photo:
            return safe_send_message(message.chat.id, get_lang("support_text_or_photo_only"))

        now = datetime.now()
        messages_path = os.path.join(DATA_DIR, "messages.json")
        support_messages = load_json(messages_path, {})

        message_data = {
            "from_admin": True,
            "text": message.caption if message.photo else message.text,
            "time": now.isoformat(),
            "global": True
        }

        if message.photo:
            message_data["photo"] = message.photo[-1].file_id

        support_messages[str(int(now.timestamp()))] = message_data
        save_json(messages_path, support_messages)

        failed_users = []
        for uid, user_info in users.copy().items():
            if user_info.get("banned", False):
                continue
            try:
                text = f"📢 {get_lang('message_from_admin')}\n{message_data['text']}"
                if message.photo:
                    if not safe_send_photo(int(uid), message_data["photo"], caption=text, parse_mode="HTML"):
                        failed_users.append(uid)
                else:
                    if not safe_send_message(int(uid), text, parse_mode="HTML"):
                        failed_users.append(uid)
            except Exception as e:
                logging.error(f"Failed to send global message to user {uid}: {e}")
                failed_users.append(uid)

        user_states.pop(user_id, None)
        if failed_users:
            safe_send_message(
                message.chat.id,
                get_lang("global_message_failed") + f"\nکاربران ناموفق: {', '.join(failed_users)}",
                reply_markup=get_main_keyboard(user_id)
            )
        else:
            safe_send_message(message.chat.id, get_lang("global_message_sent"), reply_markup=get_main_keyboard(user_id))

    except Exception as e:
        logging.error(f"handle_global_message error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("admin_reset_bot"))
def handle_reset_bot(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return
        
        # فقط products.json و transactions.json و messages.json ریست بشن
        json_files = [PRODUCTS_FILE, TRANSACTIONS_FILE, os.path.join(DATA_DIR, "messages.json")]
        
        # خالی کردن فایل‌ها
        for file_path in json_files:
            if os.path.exists(file_path):
                save_json(file_path, {})
        
        # به‌روزرسانی متغیرهای جهانی
        global products, transactions
        products = load_json(PRODUCTS_FILE, {})
        transactions = load_json(TRANSACTIONS_FILE, {})

        # پاک‌سازی state‌ها
        user_states.clear()
        add_product_states.clear()
        admin_reply_states.clear()

        safe_send_message(message.chat.id, get_lang("bot_reset_success"), reply_markup=get_settings_keyboard(message.from_user.id))
    except Exception as e:
        logging.error(f"handle_reset_bot error: {e}")
        safe_send_message(message.chat.id, get_lang("bot_reset_failed"))
        
@bot.callback_query_handler(func=lambda c: c.data == "start_add_product")
def start_add_product(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return

        # پاکسازی stateهای قبلی
        user_id = call.from_user.id
        user_states.pop(user_id, None)
        admin_reply_states.pop(user_id, None)

        add_product_states[user_id] = {"step": "title"}

        # فقط کیبورد لغو برای شروع
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))

        safe_send_message(call.message.chat.id, get_lang("add_product_title"), reply_markup=kb)
    except Exception as e:
        logging.error(f"start_add_product error: {e}")

@bot.message_handler(content_types=["text", "document"], func=lambda m: m.from_user.id in add_product_states)
def handle_add_product_steps(message: Message):
    try:
        user_id = message.from_user.id
        state = add_product_states.get(user_id, {})
        step = state.get("step")

        # اگر کاربر لغو زد
        if message.text == get_lang("cancel_button"):
            add_product_states.pop(user_id, None)
            return safe_send_message(
                message.chat.id,
                get_lang("cancelled"),
                reply_markup=get_main_keyboard(user_id)
            )

        currency = config["currency"]

        if step == "title":
            state["title"] = message.text
            state["step"] = "price"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            safe_send_message(message.chat.id, get_lang("add_product_price").replace("{currency}", currency), reply_markup=kb)

        elif step == "price":
            if not message.text.isdigit():
                return safe_send_message(message.chat.id, get_lang("invalid_price"))
            state["price"] = int(message.text)
            state["step"] = "description"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            safe_send_message(message.chat.id, get_lang("add_product_description"), reply_markup=kb)

        elif step == "description":
            state["description"] = message.text
            state["step"] = "delivery_type"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("delivery_file"), get_lang("delivery_link"))
            kb.row(get_lang("cancel_button"))
            safe_send_message(message.chat.id, get_lang("choose_delivery_type"), reply_markup=kb)

        elif step == "delivery_type":
            if message.text == get_lang("delivery_file"):
                state["step"] = "file_upload"
                state["file_ids"] = []
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("finish_upload_button"))
                kb.row(get_lang("cancel_button"))
                safe_send_message(message.chat.id, get_lang("send_product_files"), reply_markup=kb)

            elif message.text == get_lang("delivery_link"):
                state["step"] = "link_input"
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("cancel_button"))
                safe_send_message(message.chat.id, get_lang("send_product_link"), reply_markup=kb)

            else:
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("delivery_file"), get_lang("delivery_link"))
                kb.row(get_lang("cancel_button"))
                safe_send_message(message.chat.id, get_lang("choose_delivery_type"), reply_markup=kb)

        elif step == "file_upload":
            if message.text == get_lang("finish_upload_button"):
                file_ids = state.get("file_ids", [])
                if not file_ids:
                    return safe_send_message(message.chat.id, get_lang("no_file_uploaded_yet"))
                state["step"] = "final_confirm"
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("confirm_add_product"), reply_markup=kb)

            if message.document:
                file_id = message.document.file_id
                state.setdefault("file_ids", []).append(file_id)
                logging.info(f"📎 فایل دریافت شد از کاربر {user_id}: {file_id}")
                return safe_send_message(message.chat.id, get_lang("file_received_next"))

            return safe_send_message(message.chat.id, get_lang("send_file_only"))

        elif step == "link_input":
            state["link"] = message.text
            state["step"] = "final_confirm"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
            safe_send_message(message.chat.id, get_lang("confirm_add_product"), reply_markup=kb)

        elif step == "final_confirm":
            if message.text == get_lang("confirm_button"):
                pid = str(int(datetime.now().timestamp()))
                delivery = {"type": "link", "link": state["link"]} if "link" in state else {
                    "type": "file", "file_ids": state.get("file_ids", [])}
                products[pid] = {
                    "title": state["title"],
                    "price": state["price"],
                    "description": state["description"],
                    "delivery": delivery,
                    "is_active": True
                }
                save_json(PRODUCTS_FILE, products)

                group_id = config.get("transaction_group_id")
                if delivery["type"] == "file" and group_id:
                    for fid in delivery["file_ids"]:
                        try:
                            bot.send_document(group_id, fid, caption=state["title"])
                        except Exception as e:
                            logging.warning(f"Send file to group error: {e}")

                safe_send_message(message.chat.id, get_lang("product_added"), reply_markup=get_main_keyboard(user_id))
            else:
                safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

            add_product_states.pop(user_id, None)

    except Exception as e:
        logging.error(f"handle_add_product_steps error: {e}")
        add_product_states.pop(message.from_user.id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(message.from_user.id))
           
@bot.message_handler(func=lambda m: m.text == get_lang("admin_set_transaction_group"))
def handle_set_transaction_group(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return

        user_states[message.from_user.id] = "awaiting_transaction_group_id"

        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(
            message.chat.id,
            get_lang("send_group_id_instruction"),
            reply_markup=kb
        )
    except Exception as e:
        logging.error(f"handle_set_transaction_group error: {e}")

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_transaction_group_id")
def handle_group_id_input(message: Message):
    try:
        user_id = message.from_user.id
        admin_chat_id = user_id  # چت خصوصی ادمین

        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(admin_chat_id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))

        if message.chat.type in ["group", "supergroup"]:
            group_id = message.chat.id
            try:
                bot.get_chat(group_id)
                config["transaction_group_id"] = group_id
                save_json(CONFIG_FILE, config)
                user_states.pop(user_id, None)
                safe_send_message(
                    admin_chat_id,  # ارسال به چت خصوصی ادمین
                    get_lang("group_id_set_successfully").replace("{group_id}", str(group_id)),
                    reply_markup=get_settings_keyboard(user_id)
                )
            except Exception as e:
                logging.error(f"Invalid group ID {group_id}: {e}")
                safe_send_message(admin_chat_id, get_lang("invalid_group_id"))
            return

        if message.text and message.text.lstrip("-").isdigit():
            group_id = int(message.text)
            try:
                bot.get_chat(group_id)
                config["transaction_group_id"] = group_id
                save_json(CONFIG_FILE, config)
                user_states.pop(user_id, None)
                safe_send_message(
                    admin_chat_id,  # ارسال به چت خصوصی ادمین
                    get_lang("group_id_set_successfully").replace("{group_id}", str(group_id)),
                    reply_markup=get_settings_keyboard(user_id)
                )
            except Exception as e:
                logging.error(f"Invalid group ID {group_id}: {e}")
                safe_send_message(admin_chat_id, get_lang("invalid_group_id"))
            return

        safe_send_message(admin_chat_id, get_lang("invalid_group_id"))
    except Exception as e:
        logging.error(f"handle_group_id_input error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(admin_chat_id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))
        
@bot.message_handler(func=lambda m: m.text == get_lang("admin_manage_products"))
def handle_manage_products(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return

        markup = types.InlineKeyboardMarkup()
        per_page = 5
        product_list = list(products.items())
        page = 0
        end = min(len(product_list), per_page)
        currency = config["currency"]
        for pid, p in product_list[:end]:
            price_text = f"{p['price']} {currency}"
            markup.add(types.InlineKeyboardButton(f"{p['title']} - {price_text}", callback_data=f"delete_product:{pid}"))
        if len(product_list) > per_page:
            markup.add(types.InlineKeyboardButton(get_lang("next_page"), callback_data="product_page:1"))
        markup.add(types.InlineKeyboardButton(get_lang("add_product"), callback_data="start_add_product"))

        safe_send_message(message.chat.id, get_lang("manage_products_prompt"), reply_markup=markup)
    except Exception as e:
        logging.error(f"Manage products error: {e}")
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("product_page:"))
def handle_product_page_callback(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return

        _, page_str = call.data.split(":")
        page = int(page_str)
        per_page = 5
        product_list = list(products.items())
        start = page * per_page
        end = min(start + per_page, len(product_list))

        markup = types.InlineKeyboardMarkup()
        currency = config["currency"]
        for pid, p in product_list[start:end]:
            price_text = f"{p['price']} {currency}"
            markup.add(types.InlineKeyboardButton(f"{p['title']} - {price_text}", callback_data=f"delete_product:{pid}"))

        if start > 0:
            markup.add(types.InlineKeyboardButton(get_lang("prev_page"), callback_data=f"product_page:{page-1}"))
        if end < len(product_list):
            markup.add(types.InlineKeyboardButton(get_lang("next_page"), callback_data=f"product_page:{page+1}"))

        markup.add(types.InlineKeyboardButton(get_lang("add_product"), callback_data="start_add_product"))

        bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=markup)
    except Exception as e:
        logging.error(f"Product page callback error: {e}")
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("delete_product:"))
def handle_delete_product_callback(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return

        pid = call.data.split(":")[1]
        if pid in products:
            del products[pid]
            save_json(PRODUCTS_FILE, products)
            bot.answer_callback_query(call.id, get_lang("product_deleted"))
            bot.delete_message(call.message.chat.id, call.message.message_id)
            handle_manage_products(call.message)
        else:
            bot.answer_callback_query(call.id, get_lang("product_not_found"))
    except Exception as e:
        logging.error(f"Delete product callback error: {e}")

@bot.message_handler(func=lambda m: m.text == get_lang("wallet_button"))
def handle_wallet(message: Message):
    try:
        user_id = message.from_user.id
        not_joined_channels = check_channel_membership(user_id)
        sent_channels, keyboard = show_channel_buttons(message.chat.id, user_id, not_joined_channels)
        if sent_channels:
            return
        if is_banned(user_id):
            return safe_send_message(message.chat.id, get_lang("banned_message"), reply_markup=get_main_keyboard(user_id))

        if not config.get("wallet_enabled", True):
            return safe_send_message(message.chat.id, get_lang("wallet_disabled_message"), reply_markup=get_main_keyboard(user_id))

        user_data = users.get(str(user_id), {})
        balance = user_data.get("wallet_balance", 0)
        currency = config["currency"]

        text = get_lang("wallet_info").replace("{balance}", format_number(balance)).replace("{currency}", currency)
        markup = types.InlineKeyboardMarkup()
        markup.add(types.InlineKeyboardButton(get_lang("charge_wallet_button"), callback_data="charge_wallet"))

        safe_send_message(message.chat.id, text, parse_mode="HTML", reply_markup=markup)
    except Exception as e:
        logging.error(f"handle_wallet error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))
        
@bot.callback_query_handler(func=lambda c: c.data == "charge_wallet")
def handle_charge_wallet(call: CallbackQuery):
    try:
        if is_banned(call.from_user.id):
            bot.delete_message(call.message.chat.id, call.message.message_id)
            return safe_send_message(call.message.chat.id, get_lang("banned_message"))

        user_states[call.from_user.id] = "awaiting_charge_amount"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(call.message.chat.id, get_lang("enter_charge_amount"), reply_markup=kb)
        bot.delete_message(call.message.chat.id, call.message.message_id)
    except Exception as e:
        logging.error(f"handle_charge_wallet error: {e}")
        user_states.pop(call.from_user.id, None)
        safe_send_message(call.message.chat.id, get_lang("settings_update_failed"))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_charge_amount")
def handle_charge_amount(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

        if not message.text.isdigit() or int(message.text) <= 0:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_amount"), reply_markup=kb)

        amount = int(message.text)
        currency = config["currency"]
        user_states[user_id] = f"confirm_charge_amount:{amount}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
        text = get_lang("confirm_wallet_charge").replace("{amount}", format_number(amount)).replace("{currency}", currency)
        safe_send_message(message.chat.id, text, reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_charge_amount error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id, "").startswith("confirm_charge_amount:"))
def handle_confirm_charge(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

        if message.text != get_lang("confirm_button"):
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_action"), reply_markup=kb)

        amount = int(user_states[user_id].split(":")[1])
        user_states[user_id] = f"awaiting_charge_payment:{amount}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        card_info = config.get("card_info", "اطلاعات کارت تنظیم نشده")
        payment_message = f"{get_lang('send_payment_info')}\n\n{get_lang('card_info').replace('{card_info}', card_info)}"
        safe_send_message(message.chat.id, payment_message, reply_markup=kb, parse_mode="HTML")
    except Exception as e:
        logging.error(f"handle_confirm_charge error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("change_card_info_button"))
def handle_change_card_info(message: Message):
    try:
        user_id = message.from_user.id
        logging.info(f"User {user_id} clicked change_card_info_button")
        user_states[user_id] = "awaiting_card_info"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        card_info = config.get("card_info", get_lang("card_info_not_set"))
        text = get_lang("enter_card_info").replace("{card_info}", card_info)
        safe_send_message(message.chat.id, text, reply_markup=kb, parse_mode="HTML")
    except Exception as e:
        logging.error(f"handle_change_card_info error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))
        
@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_card_info")
def handle_card_info_input(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))
        if not message.text:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("support_text_or_photo_only"), reply_markup=kb)
        config["card_info"] = message.text
        save_json(CONFIG_FILE, config)
        user_states.pop(user_id, None)
        text = get_lang("card_info_updated").replace("{card_info}", message.text)
        safe_send_message(message.chat.id, text, reply_markup=get_settings_keyboard(user_id), parse_mode="HTML")
    except Exception as e:
        logging.error(f"handle_card_info_input error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))
        
@bot.message_handler(content_types=["text", "photo"], func=lambda m: user_states.get(m.from_user.id, "").startswith("awaiting_charge_payment:"))
def handle_charge_payment(message: Message):
    try:
        user_id = message.from_user.id
        amount = int(user_states[user_id].split(":")[1])
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

        group_id = config.get("transaction_group_id")
        if not group_id:
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("no_transaction_group"), reply_markup=get_main_keyboard(user_id))

        now = datetime.now()
        transaction_id = str(int(now.timestamp()))
        currency = config["currency"]
        transaction_data = {
            "user_id": user_id,
            "type": "wallet_charge",
            "amount": amount,
            "status": "pending",
            "time": now.isoformat()
        }

        if message.photo:
            transaction_data["photo"] = message.photo[-1].file_id
            transaction_data["caption"] = message.caption or ""
        else:
            transaction_data["text"] = message.text

        transactions[transaction_id] = transaction_data
        save_json(TRANSACTIONS_FILE, transactions)

        user_info = f"👤 <b>کاربر:</b> {message.from_user.first_name} (@{message.from_user.username or '-'})"
        transaction_info = f"💰 <b>شارژ کیف پول:</b> {format_number(amount)} {currency}\n#شارژ_کیف_پول"
        status_info = f"📌 <b>وضعیت:</b> در انتظار تأیید"

        markup = types.InlineKeyboardMarkup()
        markup.add(
            types.InlineKeyboardButton(get_lang("accept_transaction"), callback_data=f"accept_transaction:{transaction_id}"),
            types.InlineKeyboardButton(get_lang("reject_transaction"), callback_data=f"reject_transaction:{transaction_id}")
        )

        if "photo" in transaction_data:
            caption = (
                f"{get_lang('new_transaction')}\n"
                f"{user_info}\n"
                f"🆔 <code>{user_id}</code>\n"
                f"{transaction_info}\n"
                f"📝 <b>کپشن:</b> {transaction_data['caption']}\n"
                f"{status_info}"
            )
            safe_send_photo(group_id, transaction_data["photo"], caption=caption, parse_mode="HTML", reply_markup=markup)
        else:
            text = (
                f"{get_lang('new_transaction')}\n"
                f"{user_info}\n"
                f"🆔 <code>{user_id}</code>\n"
                f"{transaction_info}\n"
                f"📝 <b>متن:</b> {transaction_data['text']}\n"
                f"{status_info}"
            )
            safe_send_message(group_id, text, parse_mode="HTML", reply_markup=markup)

        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("wallet_charge_submitted"), reply_markup=get_main_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_charge_payment error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data.startswith("set_wallet_balance:"))
def handle_set_wallet_balance(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return

        user_id = call.data.split(":")[1]
        user_states[call.from_user.id] = f"awaiting_wallet_balance:{user_id}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(call.message.chat.id, get_lang("enter_wallet_balance"), reply_markup=kb)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_set_wallet_balance error: {e}")
        user_states.pop(call.from_user.id, None)
        safe_send_message(call.message.chat.id, get_lang("settings_update_failed"))
        
@bot.message_handler(func=lambda m: user_states.get(m.from_user.id, "").startswith("awaiting_wallet_balance:"))
def handle_wallet_balance_input(message: Message):
    try:
        user_id = message.from_user.id
        target_user_id = user_states[user_id].split(":")[1]

        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))

        if not message.text.isdigit() or int(message.text) < 0:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_amount"), reply_markup=kb)

        balance = int(message.text)
        currency = config["currency"]
        users[target_user_id]["wallet_balance"] = balance
        save_json(USERS_FILE, users)

        user_states.pop(user_id, None)
        text = get_lang("wallet_balance_updated").replace("{balance}", format_number(balance)).replace("{currency}", currency)
        safe_send_message(message.chat.id, text, reply_markup=get_settings_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_wallet_balance_input error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("buy_with_wallet:"))
def handle_buy_with_wallet(call: CallbackQuery):
    try:
        if is_banned(call.from_user.id):
            bot.delete_message(call.message.chat.id, call.message.message_id)
            return safe_send_message(call.message.chat.id, get_lang("banned_message"))

        pid = call.data.split(":")[1]
        product = products.get(pid)
        if not product:
            bot.answer_callback_query(call.id, get_lang("product_not_found"))
            return

        user_id = str(call.from_user.id)
        user_data = users.get(user_id, {})
        balance = user_data.get("wallet_balance", 0)
        currency = config["currency"]

        if balance < product["price"]:
            text = get_lang("insufficient_balance").replace("{balance}", format_number(balance)).replace("{price}", format_number(product["price"])).replace("{currency}", currency)
            user_states.pop(user_id, None)
            add_product_states.pop(user_id, None)
            bot.delete_message(call.message.chat.id, call.message.message_id)
            return safe_send_message(call.message.chat.id, text, reply_markup=get_main_keyboard(user_id))

        user_states[call.from_user.id] = f"confirm_wallet_purchase:{pid}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
        text = get_lang("confirm_wallet_purchase").replace("{title}", product["title"]).replace("{price}", format_number(product["price"])).replace("{currency}", currency)
        safe_send_message(call.message.chat.id, text, reply_markup=kb)
        bot.delete_message(call.message.chat.id, call.message.message_id)
    except Exception as e:
        logging.error(f"handle_buy_with_wallet error: {e}")
        user_states.pop(call.from_user.id, None)
        add_product_states.pop(call.from_user.id, None)
        safe_send_message(call.message.chat.id, get_lang("settings_update_failed"))
        
@bot.message_handler(func=lambda m: user_states.get(m.from_user.id, "").startswith("confirm_wallet_purchase:"))
def handle_confirm_wallet_purchase(message: Message):
    try:
        user_id = message.from_user.id
        pid = user_states[user_id].split(":")[1]
        product = products.get(pid)
        if not product:
            user_states.pop(user_id, None)
            add_product_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("product_not_found"), reply_markup=get_main_keyboard(user_id))

        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            add_product_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

        if message.text != get_lang("confirm_button"):
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_action"), reply_markup=kb)

        user_data = users.get(str(user_id), {})
        balance = user_data.get("wallet_balance", 0)
        currency = config["currency"]

        if balance < product["price"]:
            text = get_lang("insufficient_balance").replace("{balance}", format_number(balance)).replace("{price}", format_number(product["price"])).replace("{currency}", currency)
            user_states.pop(user_id, None)
            add_product_states.pop(user_id, None)
            return safe_send_message(message.chat.id, text, reply_markup=get_main_keyboard(user_id))

        users[str(user_id)]["wallet_balance"] = balance - product["price"]
        users[str(user_id)]["received_products"] = user_data.get("received_products", 0) + 1
        save_json(USERS_FILE, users)

        now = datetime.now()
        transaction_id = str(int(now.timestamp()))
        transactions[transaction_id] = {
            "user_id": user_id,
            "type": "wallet_purchase",
            "product_id": pid,
            "product_title": product["title"],
            "price": product["price"],
            "status": "accepted",
            "time": now.isoformat()
        }
        save_json(TRANSACTIONS_FILE, transactions)

        group_id = config.get("transaction_group_id")
        if group_id:
            user_info = f"👤 <b>کاربر:</b> {message.from_user.first_name} (@{message.from_user.username or '-'})"
            product_info = f"📦 <b>محصول:</b> {product['title']}\n💰 <b>قیمت:</b> {format_number(product['price'])} {currency}\n#خرید_محصول"
            status_info = f"📌 <b>وضعیت:</b> تأیید شده (پرداخت با کیف پول)"
            text = f"{get_lang('new_transaction')}\n{user_info}\n🆔 <code>{user_id}</code>\n{product_info}\n{status_info}"
            markup = types.InlineKeyboardMarkup()
            markup.add(types.InlineKeyboardButton(get_lang("transaction_accepted"), callback_data="no_action"))
            safe_send_message(group_id, text, parse_mode="HTML", reply_markup=markup)

        product_details = (
            f"🎉 <b>تراکنش شما برای محصول {product['title']} تأیید شد!</b>\n"
            f"📦 <b>عنوان محصول:</b> {product['title']}\n"
            f"📝 <b>توضیحات:</b> {product['description']}\n"
            f"🚚 <b>تحویل:</b> {'فایل' if product['delivery']['type'] == 'file' else 'لینک'}"
        )
        safe_send_message(user_id, product_details, parse_mode="HTML")

        if product["delivery"]["type"] == "file":
            for file_id in product["delivery"]["file_ids"]:
                safe_send_document(user_id, file_id, caption=f"📄 فایل محصول: {product['title']}", parse_mode="HTML")
        elif product["delivery"]["type"] == "link":
            safe_send_message(user_id, f"🔗 لینک محصول: {product['delivery']['link']}", parse_mode="HTML")

        text = get_lang("wallet_purchase_success").replace("{title}", product["title"]).replace("{balance}", format_number(users[str(user_id)]["wallet_balance"])).replace("{currency}", currency)
        safe_send_message(user_id, text, reply_markup=get_main_keyboard(user_id))
        user_states.pop(user_id, None)
        add_product_states.pop(user_id, None)
    except Exception as e:
        logging.error(f"handle_confirm_wallet_purchase error: {e}")
        user_states.pop(user_id, None)
        add_product_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("admin_statistics"))
def handle_statistics(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return
        total_users = len(users)
        total_products = len(products)
        total_tx = len(transactions)
        accepted_tx = sum(1 for t in transactions.values() if t.get("status") == "accepted")
        total_income = sum(t.get("price", 0) for t in transactions.values() if t.get("status") == "accepted")
        currency = config["currency"]
        stats = (
            f"👥 کاربران: {total_users}\n"
            f"📦 محصولات: {total_products}\n"
            f"🧾 کل خریدها: {total_tx}\n"
            f"✅ خریدهای تأییدشده: {accepted_tx}\n"
            f"💰 مجموع فروش: {total_income} {currency}"
        )
        safe_send_message(message.chat.id, stats)
    except Exception as e:
        logging.error(f"Statistics handler error: {e}")
        
@bot.message_handler(func=lambda m: m.text == get_lang("store_button"))
def handle_store(message: Message):
    try:
        user_id = message.from_user.id
        not_joined_channels = check_channel_membership(user_id)
        sent_channels, keyboard = show_channel_buttons(message.chat.id, user_id, not_joined_channels)
        if sent_channels:
            return
        if is_banned(user_id):
            return safe_send_message(message.chat.id, get_lang("banned_message"), reply_markup=get_main_keyboard(user_id))

        if not products:
            return safe_send_message(message.chat.id, get_lang("no_products"), reply_markup=get_main_keyboard(user_id))

        markup = types.InlineKeyboardMarkup()
        currency = config["currency"]
        for pid, p in products.items():
            if not p.get("is_active", True):
                continue
            price_text = f"{format_number(p['price'])} {currency}"
            markup.add(types.InlineKeyboardButton(text=f"{p['title']} - {price_text}", callback_data=f"view_product:{pid}"))
        safe_send_message(message.chat.id, get_lang("store_choose"), reply_markup=markup, parse_mode="HTML")
    except Exception as e:
        logging.error(f"Store handler error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("view_product:"))
def handle_view_product(call: CallbackQuery):
    try:
        if is_banned(call.from_user.id):
            bot.delete_message(call.message.chat.id, call.message.message_id)
            return safe_send_message(call.message.chat.id, get_lang("banned_message"))

        pid = call.data.split(":")[1]
        product = products.get(pid)
        if not product:
            bot.answer_callback_query(call.id, get_lang("product_not_found"))
            return

        currency = config["currency"]
        text = (
            f"📦 <b>{product['title']}</b>\n"
            f"💰 قیمت: {format_number(product['price'])} {currency}\n"
            f"📝 توضیحات: {product['description']}"
        )

        markup = types.InlineKeyboardMarkup()
        buttons = [types.InlineKeyboardButton(get_lang("buy_card_to_card"), callback_data=f"buy_product:{pid}")]
        if config.get("wallet_enabled", True):
            buttons.append(types.InlineKeyboardButton(get_lang("buy_with_wallet"), callback_data=f"buy_with_wallet:{pid}"))
        markup.add(*buttons)
        markup.add(types.InlineKeyboardButton(get_lang("back_to_store"), callback_data="back_to_store"))

        bot.edit_message_text(text, call.message.chat.id, call.message.message_id, parse_mode="HTML", reply_markup=markup)
    except Exception as e:
        logging.error(f"handle_view_product error: {e}")
        bot.answer_callback_query(call.id, get_lang("settings_update_failed"))
        
@bot.callback_query_handler(func=lambda c: c.data == "back_to_store")
def handle_back_to_store(call: CallbackQuery):
    try:
        if is_banned(call.from_user.id):
            bot.delete_message(call.message.chat.id, call.message.message_id)
            return safe_send_message(call.message.chat.id, get_lang("banned_message"))

        if not products:
            bot.delete_message(call.message.chat.id, call.message.message_id)
            return safe_send_message(call.message.chat.id, get_lang("no_products"))

        markup = types.InlineKeyboardMarkup()
        currency = config["currency"]
        for pid, p in products.items():
            if not p.get("is_active", True):
                continue
            price_text = f"{format_number(p['price'])} {currency}"
            markup.add(types.InlineKeyboardButton(text=f"{p['title']} - {price_text}", callback_data=f"view_product:{pid}"))

        bot.edit_message_text(
            get_lang("store_choose"),
            call.message.chat.id,
            call.message.message_id,
            reply_markup=markup
        )
    except Exception as e:
        logging.error(f"handle_back_to_store error: {e}")
        bot.answer_callback_query(call.id, get_lang("settings_update_failed"))
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("buy_product:"))
def handle_buy_product(call: CallbackQuery):
    try:
        if is_banned(call.from_user.id):
            bot.delete_message(call.message.chat.id, call.message.message_id)
            return safe_send_message(call.message.chat.id, get_lang("banned_message"))

        pid = call.data.split(":")[1]
        if pid not in products:
            bot.answer_callback_query(call.id, get_lang("product_not_found"))
            return

        user_states[call.from_user.id] = f"awaiting_payment_info:{pid}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        
        card_info = config.get("card_info", "اطلاعات کارت تنظیم نشده")
        payment_message = f"{get_lang('send_payment_info')}\n\n{get_lang('card_info').replace('{card_info}', card_info)}"   
        
        safe_send_message(
            call.message.chat.id,
            payment_message,
            reply_markup=kb,
            parse_mode="HTML"
        )
        bot.delete_message(call.message.chat.id, call.message.message_id)
    except Exception as e:
        logging.error(f"handle_buy_product error: {e}")
        user_states.pop(call.from_user.id, None)
        safe_send_message(call.message.chat.id, get_lang("settings_update_failed"))
        
@bot.message_handler(content_types=["text", "photo"], func=lambda m: user_states.get(m.from_user.id, "").startswith("awaiting_payment_info:"))
def handle_payment_info(message: Message):
    try:
        user_id = message.from_user.id
        pid = user_states[user_id].split(":")[1]
        product = products.get(pid)
        if not product:
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("product_not_found"), reply_markup=get_main_keyboard(user_id))

        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

        group_id = config.get("transaction_group_id")
        if not group_id:
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("no_transaction_group"), reply_markup=get_main_keyboard(user_id))

        now = datetime.now()
        transaction_id = str(int(now.timestamp()))
        currency = config["currency"]
        transaction_data = {
            "user_id": user_id,
            "product_id": pid,
            "product_title": product["title"],
            "price": product["price"],
            "status": "pending",
            "time": now.isoformat()
        }

        if message.photo:
            transaction_data["photo"] = message.photo[-1].file_id
            transaction_data["caption"] = message.caption or ""
        else:
            transaction_data["text"] = message.text

        transactions[transaction_id] = transaction_data
        save_json(TRANSACTIONS_FILE, transactions)

        user_info = f"👤 <b>کاربر:</b> {message.from_user.first_name} (@{message.from_user.username or '-'})"
        product_info = f"📦 <b>محصول:</b> {product['title']}\n💰 <b>قیمت:</b> {format_number(product['price'])} {currency}"
        status_info = f"📌 <b>وضعیت:</b> در انتظار تأیید"

        markup = types.InlineKeyboardMarkup()
        markup.add(
            types.InlineKeyboardButton(get_lang("accept_transaction"), callback_data=f"accept_transaction:{transaction_id}"),
            types.InlineKeyboardButton(get_lang("reject_transaction"), callback_data=f"reject_transaction:{transaction_id}")
        )

        if "photo" in transaction_data:
            caption = (
                f"{get_lang('new_transaction')}\n"
                f"{user_info}\n"
                f"🆔 <code>{user_id}</code>\n"
                f"{product_info}\n"
                f"📝 <b>کپشن:</b> {transaction_data['caption']}\n"
                f"{status_info}"
            )
            safe_send_photo(group_id, transaction_data["photo"], caption=caption, parse_mode="HTML", reply_markup=markup)
        else:
            text = (
                f"{get_lang('new_transaction')}\n"
                f"{user_info}\n"
                f"🆔 <code>{user_id}</code>\n"
                f"{product_info}\n"
                f"📝 <b>متن:</b> {transaction_data['text']}\n"
                f"{status_info}"
            )
            safe_send_message(group_id, text, parse_mode="HTML", reply_markup=markup)

        user_states.pop(user_id, None)
        safe_send_message(
            message.chat.id,
            get_lang("transaction_submitted"),
            reply_markup=get_main_keyboard(user_id)
        )
    except Exception as e:
        logging.error(f"handle_payment_info error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("accept_transaction:") or c.data.startswith("reject_transaction:"))
def handle_transaction_action(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            bot.answer_callback_query(call.id, get_lang("admin_only_error"))
            return

        action, transaction_id = call.data.split(":")
        transaction = transactions.get(transaction_id)
        if not transaction:
            bot.answer_callback_query(call.id, get_lang("transaction_not_found"))
            return

        user_id = transaction["user_id"]
        currency = config["currency"]
        user_info = f"👤 <b>کاربر:</b> {users.get(str(user_id), {}).get('first_name', '-')} (@{users.get(str(user_id), {}).get('username', '-')})"

        # بررسی نوع تراکنش با پیش‌فرض برای سازگاری با داده‌های قدیمی
        transaction_type = transaction.get("type", "product_purchase")  # پیش‌فرض: خرید محصول
        if transaction_type == "wallet_charge":
            transaction_info = f"💰 <b>شارژ کیف پول:</b> {format_number(transaction['amount'])} {currency}\n#شارژ_کیف_پول"
        else:
            product = products.get(transaction.get("product_id", ""))
            if not product:
                bot.answer_callback_query(call.id, get_lang("product_not_found"))
                return
            transaction_info = f"📦 <b>محصول:</b> {product['title']}\n💰 <b>قیمت:</b> {format_number(transaction['price'])} {currency}\n#خرید_محصول"

        if action == "accept_transaction":
            transactions[transaction_id]["status"] = "accepted"
            save_json(TRANSACTIONS_FILE, transactions)

            if transaction_type == "wallet_charge":
                users[str(user_id)]["wallet_balance"] = users.get(str(user_id), {}).get("wallet_balance", 0) + transaction["amount"]
                save_json(USERS_FILE, users)
                text = get_lang("wallet_charge_accepted").replace("{amount}", format_number(transaction["amount"])).replace("{balance}", format_number(users[str(user_id)]["wallet_balance"])).replace("{currency}", currency)
                safe_send_message(user_id, text)
            else:
                users[str(user_id)]["received_products"] = users.get(str(user_id), {}).get("received_products", 0) + 1
                save_json(USERS_FILE, users)
                product = products.get(transaction["product_id"])
                product_details = (
                    f"🎉 <b>تراکنش شما برای محصول {product['title']} تأیید شد!</b>\n"
                    f"📦 <b>عنوان محصول:</b> {product['title']}\n"
                    f"📝 <b>توضیحات:</b> {product['description']}\n"
                    f"🚚 <b>تحویل:</b> {'فایل' if product['delivery']['type'] == 'file' else 'لینک'}"
                )
                safe_send_message(user_id, product_details, parse_mode="HTML")
                if product["delivery"]["type"] == "file":
                    for file_id in product["delivery"]["file_ids"]:
                        safe_send_document(user_id, file_id, caption=f"📄 فایل محصول: {product['title']}", parse_mode="HTML")
                elif product["delivery"]["type"] == "link":
                    safe_send_message(user_id, f"🔗 لینک محصول: {product['delivery']['link']}", parse_mode="HTML")

            status_info = f"📌 <b>وضعیت:</b> تأیید شده"
            markup = types.InlineKeyboardMarkup()
            markup.add(types.InlineKeyboardButton(get_lang("transaction_accepted"), callback_data="no_action"))

            if transaction.get("photo"):
                caption = (
                    f"{get_lang('new_transaction')}\n"
                    f"{user_info}\n"
                    f"🆔 <code>{user_id}</code>\n"
                    f"{transaction_info}\n"
                    f"📝 <b>کپشن:</b> {transaction.get('caption', '')}\n"
                    f"{status_info}"
                )
                bot.edit_message_caption(
                    caption=caption,
                    chat_id=call.message.chat.id,
                    message_id=call.message.message_id,
                    parse_mode="HTML",
                    reply_markup=markup
                )
            else:
                text = (
                    f"{get_lang('new_transaction')}\n"
                    f"{user_info}\n"
                    f"🆔 <code>{user_id}</code>\n"
                    f"{transaction_info}\n"
                    f"📝 <b>متن:</b> {transaction.get('text', '')}\n"
                    f"{status_info}"
                )
                bot.edit_message_text(
                    text,
                    call.message.chat.id,
                    call.message.message_id,
                    parse_mode="HTML",
                    reply_markup=markup
                )

            bot.answer_callback_query(call.id, get_lang("transaction_accepted_admin"))

        elif action == "reject_transaction":
            transactions[transaction_id]["status"] = "rejected"
            save_json(TRANSACTIONS_FILE, transactions)

            if transaction_type == "wallet_charge":
                text = get_lang("wallet_charge_rejected").replace("{amount}", format_number(transaction["amount"])).replace("{currency}", currency)
                safe_send_message(user_id, text)
            else:
                product = products.get(transaction["product_id"])
                safe_send_message(user_id, get_lang("transaction_rejected_user").replace("{product_title}", product["title"]))

            status_info = f"📌 <b>وضعیت:</b> رد شده"
            markup = types.InlineKeyboardMarkup()
            markup.add(types.InlineKeyboardButton(get_lang("transaction_rejected"), callback_data="no_action"))

            if transaction.get("photo"):
                caption = (
                    f"{get_lang('new_transaction')}\n"
                    f"{user_info}\n"
                    f"🆔 <code>{user_id}</code>\n"
                    f"{transaction_info}\n"
                    f"📝 <b>کپشن:</b> {transaction.get('caption', '')}\n"
                    f"{status_info}"
                )
                bot.edit_message_caption(
                    caption=caption,
                    chat_id=call.message.chat.id,
                    message_id=call.message.message_id,
                    parse_mode="HTML",
                    reply_markup=markup
                )
            else:
                text = (
                    f"{get_lang('new_transaction')}\n"
                    f"{user_info}\n"
                    f"🆔 <code>{user_id}</code>\n"
                    f"{transaction_info}\n"
                    f"📝 <b>متن:</b> {transaction.get('text', '')}\n"
                    f"{status_info}"
                )
                bot.edit_message_text(
                    text,
                    call.message.chat.id,
                    call.message.message_id,
                    parse_mode="HTML",
                    reply_markup=markup
                )

            bot.answer_callback_query(call.id, get_lang("transaction_rejected_admin"))

    except Exception as e:
        logging.error(f"handle_transaction_action error: {e}")
        bot.answer_callback_query(call.id, get_lang("settings_update_failed"))        
def run_bot():
    try:
        print("Bot is running...")
        while True:
            cleanup_states()
            bot.infinity_polling()
            time.sleep(3600)
    except Exception as e:
        logging.critical(f"Bot crashed: {e}")
        
if __name__ == "__main__":
    run_bot()
