import os
import re
import json
import logging
import telebot
import uuid
from telebot import types
from telebot.types import Message, CallbackQuery
from datetime import datetime, timedelta
import time
import requests.exceptions
from threading import Timer

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")
DISCOUNT_CODES = os.path.join(DATA_DIR, "discount_codes.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)
discount_codes = load_json(DISCOUNT_CODES)

BOT_TOKEN = config.get("bot_token", "")
STORE_NAME = config.get("store_name", "")
DISCOUNT_TRANSACTION_GROUP_ID = config.get("discount_transaction_group_id", None)
DISCOUNT_CODES = os.path.join(DATA_DIR, "discount_codes.json")

bot = telebot.TeleBot(BOT_TOKEN)
user_states = {}
add_product_states = {}
admin_reply_states = {}
add_guide_states = {}
add_discount_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", [])
        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)
        # فقط دکمه خرید فروشگاه (store_button) بدون دکمه فروش
        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"), get_lang("profile_button"))
        if is_admin(user_id):
            kb.row(get_lang("admin_manage_products"), get_lang("admin_manage_discount_codes"))
            kb.row(get_lang("admin_statistics"), get_lang("admin_settings"))
            kb.row(get_lang("admin_unanswered_supports"), get_lang("admin_global_message"))
        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_set_discount_group"))
            kb.row(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

# مدیریت کانفیگ‌ها (دست نخورده)
@bot.message_handler(func=lambda m: m.text == get_lang("admin_manage_discount_codes"))
def handle_manage_discount_codes(message: Message):
    try:
        user_id = message.from_user.id
        kb = types.InlineKeyboardMarkup()
        if discount_codes:
            for discount in discount_codes:
                title = discount.get("title", "بدون عنوان")
                price = discount.get("price")
                currency = config.get("currency")
                kb.add(types.InlineKeyboardButton(
                    text=f"{title} ({format_number(price)} {currency})",
                    callback_data=f"view_discount_{discount['id']}"
                ))
        kb.add(types.InlineKeyboardButton(
            text=get_lang("add_discount_code"),
            callback_data="add_discount_code"
        ))
        safe_send_message(message.chat.id, get_lang("select_discount_code"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_manage_discount_codes 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_discount_") and not c.data.startswith("view_discount_lines_") and not c.data.startswith("view_discount_codes_"))
def handle_view_discount_code(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        discount_id = call.data.replace("view_discount_", "")
        discount = next((d for d in discount_codes if d["id"] == discount_id), None)
        if not discount:
            bot.answer_callback_query(call.id, get_lang("discount_not_found"))
            return safe_send_message(call.message.chat.id, get_lang("discount_not_found"))

        title = discount['title']
        price = discount.get("price", 0)
        currency = config.get("currency", "تومان")

        lines = discount.get("lines", [])
        codes = discount.get("codes", [])
        used_lines = discount.get("used_lines", [])
        used_codes = discount.get("used_codes", [])
        total_lines = len(lines) + len(used_lines)
        total_codes = len(codes) + len(used_codes)
        remaining_lines = len(lines)
        remaining_codes = len(codes)

        purchase_limit = discount.get("purchase_limit", "-")

        if remaining_lines == 0 or remaining_codes == 0:
            status = get_lang("unavailable_status")
        else:
            status = get_lang("available_status")

        description = "\n".join(discount.get("text_descriptions", []) or [get_lang("no_caption")])

        text = (
            f"📚 {get_lang('title')}: {title}\n"
            f"💰 {get_lang('price')}: {format_number(price)} {currency}\n"
            f"🔢 {get_lang('config_remaining')}: {total_lines} / {remaining_lines}\n"
            f"📋 {get_lang('sub_remaining')}: {total_codes} / {remaining_codes}\n"
            f"🔄 {get_lang('add_discount_code_purchase_limit')}: {purchase_limit}\n"
            f"📍 {get_lang('status')}: {status}\n"
            f"📝 {get_lang('description')}:\n{description}"
        )

        kb = types.InlineKeyboardMarkup()
        kb.row(
            types.InlineKeyboardButton("📄 کانفیگ‌های باقی‌مانده", callback_data=f"view_discount_lines_{discount_id}"),
            types.InlineKeyboardButton("📄 لینک‌های باقی‌مانده", callback_data=f"view_discount_codes_{discount_id}")
        )
        kb.row(
            types.InlineKeyboardButton(get_lang("edit_discount_code_button"), callback_data=f"edit_discount_{discount_id}"),
            types.InlineKeyboardButton(get_lang("delete_discount_code_button"), callback_data=f"delete_discount_{discount_id}")
        )
        kb.add(types.InlineKeyboardButton(get_lang("back_button"), callback_data="manage_discount_codes"))

        safe_send_message(call.message.chat.id, text, reply_markup=kb, parse_mode="HTML")

        group_id = config.get("transaction_group_id")
        if group_id and discount.get("file_ids"):
            for file_id in discount["file_ids"]:
                try:
                    bot.copy_message(call.message.chat.id, group_id, file_id)
                except Exception as e:
                    logging.error(f"[DISCOUNT] Failed to copy file {file_id}: {e}")

        bot.delete_message(call.message.chat.id, call.message.message_id)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.exception(f"[DISCOUNT] handle_view_discount_code error: {e}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))
        safe_send_message(call.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_discount_lines_"))
def handle_view_discount_lines(call: CallbackQuery):
    try:
        logging.info(f"[LINES] Received callback: {call.data} from user {call.from_user.id}")
        discount_id = call.data.replace("view_discount_lines_", "")
        logging.info(f"[LINES] Extracted discount_id: {discount_id}")
        
        discount = next((d for d in discount_codes if d["id"] == discount_id), None)
        if not discount:
            logging.warning(f"[LINES] Discount ID {discount_id} not found in discount_codes")
            return bot.answer_callback_query(call.id, get_lang("discount_not_found"))

        lines = discount.get("lines", [])
        logging.info(f"[LINES] Found {len(lines)} lines for discount {discount_id}")

        text = "\n".join(lines) if lines else get_lang("no_caption")
        
        bot.answer_callback_query(call.id)
        safe_send_message(call.message.chat.id, f"📄 {get_lang('title')}: {discount['title']}\n\n{text}")
    except Exception as e:
        logging.exception(f"[LINES] handle_view_discount_lines exception: {e}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))

@bot.callback_query_handler(func=lambda c: c.data.startswith("view_discount_codes_"))
def handle_view_discount_codes(call: CallbackQuery):
    try:
        logging.info(f"[CODES] Received callback: {call.data} from user {call.from_user.id}")
        discount_id = call.data.replace("view_discount_codes_", "")
        logging.info(f"[CODES] Extracted discount_id: {discount_id}")
        
        discount = next((d for d in discount_codes if d["id"] == discount_id), None)
        if not discount:
            logging.warning(f"[CODES] Discount ID {discount_id} not found in discount_codes")
            return bot.answer_callback_query(call.id, get_lang("discount_not_found"))

        codes = discount.get("codes", [])
        logging.info(f"[CODES] Found {len(codes)} codes for discount {discount_id}")

        text = "\n".join(codes) if codes else get_lang("no_caption")
        
        bot.answer_callback_query(call.id)
        safe_send_message(call.message.chat.id, f"📄 {get_lang('title')}: {discount['title']}\n\n{text}")
    except Exception as e:
        logging.exception(f"[CODES] handle_view_discount_codes exception: {e}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))

# ویرایش و حذف کانفیگ‌ها (بدون تغییر)
@bot.callback_query_handler(func=lambda c: c.data.startswith("edit_discount_"))
def start_edit_discount_code(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        discount_id = call.data.replace("edit_discount_", "")
        discount = next((d for d in discount_codes if d["id"] == discount_id), None)
        if not discount:
            return bot.answer_callback_query(call.id, get_lang("discount_not_found"))

        add_discount_states[user_id] = {
            "step": "title",
            "edit_mode": True,
            "original_id": discount_id,
            "title": discount.get("title", ""),
            "price": discount.get("price", 0),
            "lines": discount.get("lines", []),
            "codes": discount.get("codes", []),
            "purchase_limit": discount.get("purchase_limit", 1),
            "text_descriptions": discount.get("text_descriptions", []) or [""],
            "description_files": discount.get("file_ids", []),
            "from_edit_flow": True
        }

        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("next_step_button"), get_lang("cancel_button"))
        msg = f"✏️ در حال ویرایش: عنوان کانفیگ\n{get_lang('current_value')}: {discount.get('title', get_lang('no_caption'))}\n{get_lang('edit_enter_new_value')}"
        safe_send_message(call.message.chat.id, msg, reply_markup=kb)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.exception("start_edit_discount_code error")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))

@bot.message_handler(func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id]["step"] == "confirm_update")
def handle_confirm_discount_update(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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_update_discount_button"):
            state = add_discount_states[user_id]
            discount_id = state["original_id"]
            global discount_codes
            discount_codes = [d for d in discount_codes if d["id"] != discount_id]

            updated_discount = {
                "id": discount_id,
                "title": state.get("title", ""),
                "price": state.get("price", 0),
                "lines": state.get("lines", []),
                "codes": state.get("codes", []),
                "purchase_limit": state.get("purchase_limit", 1),
                "file_ids": [],
                "text_descriptions": state.get("text_descriptions", []),
                "is_active": True
            }

            group_id = config.get("transaction_group_id")
            for file in state.get("description_files", []):
                try:
                    caption = f"\ud83d\udcda {get_lang('title')}: {updated_discount['title']}"
                    if file["type"] == "photo":
                        sent = bot.send_photo(group_id, file["content"], caption=caption)
                        updated_discount["file_ids"].append(sent.message_id)
                    elif file["type"] == "video":
                        sent = bot.send_video(group_id, file["content"], caption=caption)
                        updated_discount["file_ids"].append(sent.message_id)
                    elif file["type"] == "text":
                        updated_discount["text_descriptions"].append(file["content"])
                except Exception as e:
                    logging.error(f"Upload file in edit error: {e}")

            discount_codes.append(updated_discount)
            save_json(DISCOUNT_CODES, discount_codes)
            add_discount_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("discount_updated"), reply_markup=get_main_keyboard(user_id))

        else:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("confirm_update_discount_button"), get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_action"), reply_markup=kb)

    except Exception as e:
        logging.exception("handle_confirm_discount_update error")
        add_discount_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id].get("edit_mode") and add_discount_states[m.from_user.id]["step"] in ["title", "price", "lines", "codes", "purchase_limit"] and m.text == get_lang("next_step_button"))
def handle_edit_next_step(message: Message):
    try:
        user_id = message.from_user.id
        state = add_discount_states[user_id]
        step_order = ["title", "price", "lines", "codes", "purchase_limit", "description"]
        current_index = step_order.index(state["step"])
        next_step = step_order[current_index + 1]
        state["step"] = next_step

        step_labels = {
            "title": "عنوان کانفیگ",
            "price": "قیمت کانفیگ",
            "lines": "کانفیگ‌ها",
            "codes": "لینک‌های ساب",
            "purchase_limit": "محدودیت خرید",
            "description": "توضیحات کانفیگ"
        }

        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        if next_step != "description":
            kb.row(get_lang("next_step_button"), get_lang("cancel_button"))
        else:
            kb.row(get_lang("cancel_button"), get_lang("finish_discount_upload"))

        current_val = state.get(next_step, get_lang('no_caption'))
        if isinstance(current_val, list):
            current_val = "\n".join(current_val) if current_val else get_lang('no_caption')
        elif current_val is None:
            current_val = get_lang('no_caption')

        msg = f"✏️ در حال ویرایش: {step_labels[next_step]}\n{get_lang('current_value')}: {current_val}\n{get_lang('edit_enter_new_value')}"
        safe_send_message(message.chat.id, msg, reply_markup=kb)
    except Exception as e:
        logging.exception("handle_edit_next_step error")
        add_discount_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id].get("edit_mode") and add_discount_states[m.from_user.id]["step"] == "title")
def handle_edit_title(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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("next_step_button"):
            add_discount_states[user_id]["step"] = "price"
        else:
            title = message.text.strip()
            if len(title) > 100:
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("next_step_button"), get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("invalid_discount_title"), reply_markup=kb)
            add_discount_states[user_id]["title"] = title
            add_discount_states[user_id]["step"] = "price"

        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("next_step_button"), get_lang("cancel_button"))
        msg = f"✏️ در حال ویرایش: قیمت کانفیگ\n{get_lang('current_value')}: {format_number(add_discount_states[user_id].get('price', 0))}\n{get_lang('edit_enter_new_value')}"
        safe_send_message(message.chat.id, msg, reply_markup=kb)
    except Exception as e:
        logging.exception("handle_edit_title error")
        add_discount_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id].get("edit_mode") and add_discount_states[m.from_user.id]["step"] == "price")
def handle_edit_price(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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("next_step_button"):
            add_discount_states[user_id]["step"] = "lines"
        else:
            price_text = message.text.strip().replace(",", "").replace(" ", "")
            if not price_text.isdigit() or int(price_text) <= 0:
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("next_step_button"), get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("invalid_discount_price"), reply_markup=kb)
            add_discount_states[user_id]["price"] = int(price_text)
            add_discount_states[user_id]["step"] = "lines"

        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("next_step_button"), get_lang("cancel_button"))
        msg = f"✏️ در حال ویرایش: کانفیگ‌ها\n{get_lang('current_value')}: \n" + "\n".join(add_discount_states[user_id].get("lines", []) or [get_lang('no_caption')]) + f"\n{get_lang('edit_enter_new_value')}"
        safe_send_message(message.chat.id, msg, reply_markup=kb)
    except Exception as e:
        logging.exception("handle_edit_price error")
        add_discount_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id].get("edit_mode") and add_discount_states[m.from_user.id]["step"] == "lines")
def handle_edit_lines(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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("next_step_button"):
            add_discount_states[user_id]["step"] = "codes"
        else:
            lines = [l.strip() for l in message.text.strip().split("\n") if l.strip()]
            if not lines:
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("next_step_button"), get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("invalid_discount_lines"), reply_markup=kb)
            add_discount_states[user_id]["lines"] = lines
            add_discount_states[user_id]["step"] = "codes"

        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("next_step_button"), get_lang("cancel_button"))
        msg = f"✏️ در حال ویرایش: لینک‌های ساب\n{get_lang('current_value')}: \n" + "\n".join(add_discount_states[user_id].get("codes", []) or [get_lang('no_caption')]) + f"\n{get_lang('edit_enter_new_value')}"
        safe_send_message(message.chat.id, msg, reply_markup=kb)
    except Exception as e:
        logging.exception("handle_edit_lines error")
        add_discount_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id].get("edit_mode") and add_discount_states[m.from_user.id]["step"] == "codes")
def handle_edit_codes(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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("next_step_button"):
            add_discount_states[user_id]["step"] = "purchase_limit"
        else:
            codes = [c.strip() for c in message.text.strip().split("\n") if c.strip()]
            if not codes:
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("next_step_button"), get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("invalid_discount_codes"), reply_markup=kb)
            add_discount_states[user_id]["codes"] = codes
            add_discount_states[user_id]["step"] = "purchase_limit"

        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("next_step_button"), get_lang("cancel_button"))
        msg = f"✏️ در حال ویرایش: محدودیت خرید\n{get_lang('current_value')}: {add_discount_states[user_id].get('purchase_limit', get_lang('no_caption'))}\n{get_lang('edit_enter_new_value')}"
        safe_send_message(message.chat.id, msg, reply_markup=kb)
    except Exception as e:
        logging.exception("handle_edit_codes error")
        add_discount_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id].get("edit_mode") and add_discount_states[m.from_user.id]["step"] == "purchase_limit")
def handle_edit_purchase_limit(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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("next_step_button"):
            add_discount_states[user_id]["step"] = "description"
        else:
            if not message.text.strip().isdigit():
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("next_step_button"), get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("invalid_discount_purchase_limit"), reply_markup=kb)
            add_discount_states[user_id]["purchase_limit"] = int(message.text.strip())
            add_discount_states[user_id]["step"] = "description"

        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"), get_lang("finish_discount_upload"))
        current_texts = "\n".join(add_discount_states[user_id].get("text_descriptions", []) or [get_lang('no_caption')])
        msg = f"✏️ در حال ویرایش: توضیحات کانفیگ\n{get_lang('current_value')}: {current_texts}\n{get_lang('edit_enter_new_value')}"
        safe_send_message(message.chat.id, msg, reply_markup=kb)
    except Exception as e:
        logging.exception("handle_edit_purchase_limit error")
        add_discount_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(content_types=["text", "photo", "video"], func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id].get("edit_mode") and add_discount_states[m.from_user.id]["step"] == "description")
def handle_edit_description(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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("finish_discount_upload"):
            add_discount_states[user_id]["step"] = "confirm_update"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("confirm_update_discount_button"), get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("are_you_sure_to_update_discount"), reply_markup=kb)

        if message.content_type == "text":
            add_discount_states[user_id]["text_descriptions"] = [message.text.strip()]
        elif message.content_type == "photo":
            add_discount_states[user_id]["description_files"].append({"type": "photo", "content": message.photo[-1].file_id})
        elif message.content_type == "video":
            add_discount_states[user_id]["description_files"].append({"type": "video", "content": message.video.file_id})

        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"), get_lang("finish_discount_upload"))
        return safe_send_message(message.chat.id, get_lang("add_more_or_finish_description"), reply_markup=kb)
    except Exception as e:
        logging.exception("handle_edit_description error")
        add_discount_states.pop(user_id, None)
        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("delete_discount_"))
def handle_delete_discount_code(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        if not is_admin(user_id):
            bot.answer_callback_query(call.id, get_lang("admin_only_error"))
            return

        discount_id = call.data.replace("delete_discount_", "")
        global discount_codes
        discount = next((d for d in discount_codes if d["id"] == discount_id), None)
        if not discount:
            bot.answer_callback_query(call.id, get_lang("discount_not_found"))
            return

        discount_codes = [d for d in discount_codes if d["id"] != discount_id]
        save_json(DISCOUNT_CODES, discount_codes)

        bot.answer_callback_query(call.id, get_lang("discount_code_deleted"))
        bot.delete_message(call.message.chat.id, call.message.message_id)
        safe_send_message(call.message.chat.id, get_lang("discount_code_deleted"), reply_markup=get_main_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_delete_discount_code error: {e}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data == "manage_discount_codes")
def handle_back_to_manage_discount_codes(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        if not is_admin(user_id):
            bot.answer_callback_query(call.id, get_lang("admin_only_error"))
            return

        kb = types.InlineKeyboardMarkup()
        if discount_codes:
            for discount in discount_codes:
                title = discount.get("title", "بدون عنوان")
                price = discount.get("price")
                currency = config.get("currency")
                kb.add(types.InlineKeyboardButton(
                    text=f"{title} ({format_number(price)} {currency})",
                    callback_data=f"view_discount_{discount['id']}"
                ))
        kb.add(types.InlineKeyboardButton(
            text=get_lang("add_discount_code"),
            callback_data="add_discount_code"
        ))
        bot.edit_message_text(
            get_lang("select_discount_code"),
            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_manage_discount_codes error: {e}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))
        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_set_discount_group"))
def handle_set_discount_transaction_group(message: Message):
    try:
        user_id = message.from_user.id
        if not is_admin(user_id):
            return safe_send_message(message.chat.id, get_lang("admin_only_error"), reply_markup=get_main_keyboard(user_id))
        user_states[user_id] = "awaiting_discount_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_discount_transaction_group 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) == "awaiting_discount_group_id")
def handle_discount_group_id_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_main_keyboard(user_id))
        if message.chat.type in ["group", "supergroup"]:
            group_id = message.chat.id
        elif message.text and message.text.lstrip("-").isdigit():
            group_id = int(message.text)
        else:
            return safe_send_message(message.chat.id, get_lang("invalid_group_id"), reply_markup=get_main_keyboard(user_id))
        try:
            bot.get_chat(group_id)
            config["discount_transaction_group_id"] = group_id
            save_json(CONFIG_FILE, config)
            global DISCOUNT_TRANSACTION_GROUP_ID
            DISCOUNT_TRANSACTION_GROUP_ID = group_id
            user_states.pop(user_id, None)
            safe_send_message(user_id, get_lang("group_id_set_successfully").replace("{group_id}", str(group_id)), reply_markup=get_main_keyboard(user_id))
        except Exception as e:
            logging.error(f"Invalid discount group ID {group_id}: {e}")
            safe_send_message(message.chat.id, get_lang("invalid_group_id"), reply_markup=get_main_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_discount_group_id_input 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 == "add_discount_code")
def start_add_discount_code(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        if not is_admin(user_id):
            return bot.answer_callback_query(call.id, get_lang("admin_only_error"))
        user_states.pop(user_id, None)
        add_discount_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_discount_code_title"), 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"start_add_discount_code error: {e}")
        add_discount_states.pop(user_id, None)
        safe_send_message(call.message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(content_types=["text"], func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id]["step"] == "title")
def handle_discount_code_title(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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:
            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)
        title = message.text.strip()
        if len(title) > 100:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_discount_title"), reply_markup=kb)
        add_discount_states[user_id]["title"] = title
        add_discount_states[user_id]["step"] = "price"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("enter_discount_price"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_discount_code_title error: {e}")
        add_discount_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(content_types=["text"], func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id]["step"] == "price")
def handle_discount_code_price(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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:
            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)
        price_text = message.text.strip().replace(",", "").replace(" ", "")
        if not price_text.isdigit() or int(price_text) <= 0:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_discount_price"), reply_markup=kb)
        add_discount_states[user_id]["price"] = int(price_text)
        add_discount_states[user_id]["step"] = "lines"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("add_discount_code_lines"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_discount_code_price error: {e}")
        add_discount_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(content_types=["text"], func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id]["step"] == "lines")
def handle_discount_code_lines(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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:
            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)
        lines = message.text.strip().split("\n")
        if not lines or not any(line.strip() for line in lines):
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_lines_format"), reply_markup=kb)
        add_discount_states[user_id]["lines"] = [line.strip() for line in lines if line.strip()]
        add_discount_states[user_id]["step"] = "confirm_lines"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("resend_lines"), get_lang("confirm_lines"))
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("discount_code_lines_counted").replace("{count}", str(len(add_discount_states[user_id]["lines"]))), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_discount_code_lines error: {e}")
        add_discount_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(content_types=["text"], func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id]["step"] == "confirm_lines")
def handle_confirm_lines(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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("resend_lines"):
            add_discount_states[user_id]["step"] = "lines"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("add_discount_code_lines"), reply_markup=kb)
        if message.text == get_lang("confirm_lines"):
            add_discount_states[user_id]["step"] = "codes"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            safe_send_message(message.chat.id, get_lang("add_discount_code_codes"), reply_markup=kb)
        else:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("resend_lines"), get_lang("confirm_lines"))
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_action"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_confirm_lines error: {e}")
        add_discount_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))

def has_persian(text):
    return bool(re.search(r'[\u0600-\u06FF]', text))

def reset_user_purchase_limits():
    try:
        global transactions
        removed = [tid for tid, t in transactions.items() if t.get("type") in ["discount_purchase", "discount"] and t.get("status") == "accepted"]
        transactions = {
            tid: t for tid, t in transactions.items()
            if not (t.get("type") in ["discount_purchase", "discount"] and t.get("status") == "accepted")
        }
        save_json(TRANSACTIONS_FILE, transactions)
        transactions = load_json(TRANSACTIONS_FILE, {})
        logging.info(f"User discount purchase limits reset successfully. Removed transactions: {removed}")
    except Exception as e:
        logging.error(f"reset_user_purchase_limits error: {e}")

def schedule_next_reset():
    now = datetime.now()
    next_reset = now.replace(hour=15, minute=17, second=0, microsecond=0)
    if now > next_reset:
        next_reset += timedelta(days=1)
    seconds_until_reset = (next_reset - now).total_seconds()
    logging.info(f"Scheduling next reset in {seconds_until_reset} seconds")
    Timer(seconds_until_reset, lambda: [reset_user_purchase_limits(), schedule_next_reset()]).start()

@bot.message_handler(content_types=["text"], func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id]["step"] == "codes")
def handle_discount_code_codes(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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:
            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)
        text = message.text.strip()
        if has_persian(text):
            codes = [text]
        else:
            codes = [line.strip() for line in text.split("\n") if line.strip()]
            if len(codes) != len(add_discount_states[user_id]["lines"]):
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("invalid_codes_format"), reply_markup=kb)
        add_discount_states[user_id]["codes"] = codes
        add_discount_states[user_id]["step"] = "confirm_codes"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("resend_codes"), get_lang("confirm_codes"))
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("discount_code_codes_counted").replace("{count}", str(len(codes))), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_discount_code_codes error: {e}")
        add_discount_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(content_types=["text"], func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id]["step"] == "confirm_codes")
def handle_confirm_codes(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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("resend_codes"):
            add_discount_states[user_id]["step"] = "codes"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("add_discount_code_codes"), reply_markup=kb)
        if message.text == get_lang("confirm_codes"):
            add_discount_states[user_id]["step"] = "purchase_limit"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            safe_send_message(message.chat.id, get_lang("add_discount_code_purchase_limit"), reply_markup=kb)
        else:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("resend_codes"), get_lang("confirm_codes"))
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_action"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_confirm_codes error: {e}")
        add_discount_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(content_types=["text"], func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id]["step"] == "purchase_limit")
def handle_discount_code_purchase_limit(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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_purchase_limit"), reply_markup=kb)
        add_discount_states[user_id]["purchase_limit"] = int(message.text)
        add_discount_states[user_id]["step"] = "description"
        add_discount_states[user_id]["description_files"] = []
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"), get_lang("finish_discount_upload"))
        safe_send_message(message.chat.id, get_lang("add_discount_code_description"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_discount_code_purchase_limit error: {e}")
        add_discount_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(content_types=["text", "photo", "video"], func=lambda m: m.from_user.id in add_discount_states and add_discount_states[m.from_user.id]["step"] == "description")
def handle_discount_code_description(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            add_discount_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("finish_discount_upload"):
            group_id = config.get("transaction_group_id")
            if not group_id:
                add_discount_states.pop(user_id, None)
                return safe_send_message(message.chat.id, get_lang("no_transaction_group"), reply_markup=get_main_keyboard(user_id))
            discount_id = str(int(datetime.now().timestamp()))
            discount_data = {
                "id": discount_id,
                "title": add_discount_states[user_id]["title"],
                "price": add_discount_states[user_id]["price"],
                "lines": add_discount_states[user_id]["lines"],
                "codes": add_discount_states[user_id]["codes"],
                "purchase_limit": add_discount_states[user_id]["purchase_limit"],
                "file_ids": [],
                "text_descriptions": [],
                "is_active": True
            }
            for file in add_discount_states[user_id].get("description_files", []):
                if file["type"] in ["photo", "video"]:
                    sent_message = None
                    caption = f"📚 کانفیگ: {discount_data['title']}"
                    if file["type"] == "photo":
                        sent_message = bot.send_photo(group_id, file["content"], caption=caption)
                    elif file["type"] == "video":
                        sent_message = bot.send_video(group_id, file["content"], caption=caption)
                    if sent_message:
                        discount_data["file_ids"].append(sent_message.message_id)
                elif file["type"] == "text":
                    discount_data["text_descriptions"].append(file["content"])
            discount_codes.append(discount_data)
            save_json(DISCOUNT_CODES, discount_codes)
            add_discount_states.pop(user_id, None)
            safe_send_message(message.chat.id, get_lang("discount_code_added"), reply_markup=get_main_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, "caption": message.caption or ""}
        elif message.video:
            file_info = {"type": "video", "content": message.video.file_id, "caption": message.caption or ""}
        if not add_discount_states[user_id].get("description_files"):
            add_discount_states[user_id]["description_files"] = []
        add_discount_states[user_id]["description_files"].append(file_info)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"), get_lang("finish_discount_upload"))
        safe_send_message(message.chat.id, get_lang("file_received_discount"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_discount_code_description error: {e}")
        add_discount_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("select_quantity_discount:"))
def handle_select_quantity_discount(call: CallbackQuery):
    try:
        from telebot.apihelper import ApiTelegramException
        import re

        user_id = call.from_user.id
        if is_banned(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"), reply_markup=get_main_keyboard(user_id))

        _, discount_id, default_quantity = call.data.split(":")
        default_quantity = int(default_quantity)

        discount = next((d for d in discount_codes if str(d["id"]) == str(discount_id)), None)
        if not discount:
            bot.answer_callback_query(call.id, get_lang("discount_not_found"))
            return safe_send_message(call.message.chat.id, get_lang("discount_not_found"), reply_markup=get_main_keyboard(user_id))

        purchase_limit = discount.get("purchase_limit", 1)
        user_purchases = count_user_discount_purchases(user_id, discount_id)
        remaining = max(0, purchase_limit - user_purchases)
        if remaining <= 0:
            bot.answer_callback_query(call.id, get_lang("purchase_limit_reached"))
            return safe_send_message(call.message.chat.id, get_lang("purchase_limit_reached"), reply_markup=get_main_keyboard(user_id))

        current_text = (call.message.text or call.message.caption or "")
        m = re.search(r"🔢\s*تعداد:\s*(\d+)", current_text)
        prev_quantity = int(m.group(1)) if m else None

        if prev_quantity is None:
            quantity = 1
        else:
            quantity = default_quantity

        quantity = max(1, min(remaining, quantity))

        price = discount.get("price", 0)
        currency = config.get("currency", "تومان")
        total_price = format_number(price * quantity)

        text = (
            f"🎟 <b>{discount['title']}</b>\n"
            f"💰 قیمت واحد: {format_number(price)} {currency}\n"
            f"🔢 تعداد: {quantity}\n"
            f"💸 مبلغ کل: {total_price} {currency}\n"
            f"🔄 خریدهای قبلی شما: {user_purchases} از {purchase_limit}\n"
        )

        kb = types.InlineKeyboardMarkup()
        row = []
        if quantity > 1:
            row.append(types.InlineKeyboardButton("➖", callback_data=f"select_quantity_discount:{discount_id}:{quantity-1}"))
        if quantity < remaining:
            row.append(types.InlineKeyboardButton("➕", callback_data=f"select_quantity_discount:{discount_id}:{quantity+1}"))
        if row:
            kb.row(*row)
        kb.add(types.InlineKeyboardButton(get_lang("confirm_button"), callback_data=f"confirm_discount_payment:{discount_id}:{quantity}"))
        kb.add(types.InlineKeyboardButton(get_lang("back_to_discount"), callback_data=f"view_discount:{discount_id}"))

        try:
            if getattr(call.message, "content_type", "") == "photo":
                bot.edit_message_caption(chat_id=call.message.chat.id, message_id=call.message.message_id,
                                         caption=text, parse_mode="HTML", reply_markup=kb)
            else:
                bot.edit_message_text(text, call.message.chat.id, call.message.message_id, parse_mode="HTML", reply_markup=kb)
        except ApiTelegramException as e:
            if "message is not modified" not in str(e):
                raise

        bot.answer_callback_query(call.id)

    except Exception as e:
        logging.error(f"handle_select_quantity_discount error: {e}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))



@bot.message_handler(func=lambda m: user_states.get(m.from_user.id, "").startswith("awaiting_quantity_discount:"))
def handle_confirm_quantity_discount(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))

        _, discount_id, max_quantity = user_states[user_id].split(":")
        discount = next((d for d in discount_codes if str(d["id"]) == str(discount_id)), None)
        if not discount:
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("discount_not_found"), reply_markup=get_main_keyboard(user_id))

        if not message.text.isdigit() or int(message.text) <= 0 or int(message.text) > int(max_quantity):
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, f"لطفاً یک عدد معتبر بین 1 و {max_quantity} وارد کنید.", reply_markup=kb)

        quantity = int(message.text)
        total_price = quantity * discount["price"]
        currency = config.get("currency", "تومان")
        user_states[user_id] = f"confirm_quantity_discount:{discount_id}:{quantity}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
        text = get_lang("confirm_discount_quantity").replace("{quantity}", str(quantity)).replace("{total_price}", format_number(total_price)).replace("{currency}", currency)
        safe_send_message(message.chat.id, text, reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_confirm_quantity_discount error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(content_types=["text", "photo"], func=lambda m: user_states.get(m.from_user.id, "").startswith("confirm_quantity_discount:"))
def handle_discount_payment_info(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)

        _, discount_id, quantity = user_states[user_id].split(":")
        quantity = int(quantity)
        discount = next((d for d in discount_codes if str(d["id"]) == str(discount_id)), None)
        if not discount:
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("discount_not_found"), reply_markup=get_main_keyboard(user_id))

        group_id = config.get("discount_transaction_group_id")
        if not group_id:
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("no_transaction_discount_group"), reply_markup=get_main_keyboard(user_id))

        total_price = quantity * discount["price"]
        user_states[user_id] = f"awaiting_discount_payment:{discount_id}:{quantity}"
        card_info = config.get("card_info", get_lang("card_info_not_set"))
        text = get_lang("send_payment_info_discount").replace("{price}", format_number(total_price)).replace("{card_info}", card_info)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, text, reply_markup=kb, parse_mode="HTML")
    except Exception as e:
        logging.error(f"handle_discount_payment_info error: {e}")
        user_states.pop(user_id, None)
        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("confirm_discount_payment:"))
def handle_confirm_discount_payment(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        _, discount_id, quantity = call.data.split(":")
        quantity = int(quantity)

        discount = next((d for d in discount_codes if str(d["id"]) == str(discount_id)), None)
        if not discount:
            return bot.answer_callback_query(call.id, get_lang("discount_not_found"))

        user_states[user_id] = f"awaiting_discount_payment_info:{discount_id}:{quantity}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))

        total_price = format_number(discount["price"] * quantity)
        card_info = config.get("card_info", "اطلاعات کارت موجود نیست")
        msg = get_lang("send_payment_info_discount").replace("{price}", total_price).replace("{card_info}", card_info)

        bot.delete_message(call.message.chat.id, call.message.message_id)
        safe_send_message(call.message.chat.id, msg, reply_markup=kb, parse_mode="HTML")
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_confirm_discount_payment error: {e}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))

@bot.message_handler(content_types=["text", "photo"], func=lambda m: m.from_user.id in user_states and str(user_states[m.from_user.id]).startswith("awaiting_discount_payment_info:"))
def handle_discount_payment_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))

        state = str(user_states.pop(user_id))
        _, discount_id, quantity = state.split(":")
        quantity = int(quantity)

        discount = next((d for d in discount_codes if str(d["id"]) == str(discount_id)), None)
        if not discount:
            return safe_send_message(message.chat.id, get_lang("discount_not_found"), reply_markup=get_main_keyboard(user_id))

        group_id = config.get("transaction_group_id")
        if not group_id:
            return safe_send_message(message.chat.id, get_lang("no_transaction_group"), reply_markup=get_main_keyboard(user_id))

        user_info = users.get(str(user_id), {})
        name = user_info.get("first_name", "-")
        username = f"@{user_info.get('username')}" if user_info.get("username") else "-"
        title = discount["title"]
        price = format_number(discount["price"] * quantity)
        currency = config.get("currency", "تومان")
        user_input = message.caption if message.caption else message.text if message.text else "-"

        caption = (
            f"💳 {get_lang('discount_purchase')}\n"
            f"👤 کاربر: {name} ({username})\n"
            f"🆔 <code>{user_id}</code>\n"
            f"🎟 عنوان: {title}\n"
            f"📦 تعداد: {quantity}\n"
            f"💰 قیمت: {price} {currency}\n"
            f"📝 متن: {user_input}\n"
            f"📌 وضعیت: {get_lang('waiting_for_approval')}"
        )

        markup = types.InlineKeyboardMarkup()
        markup.row(
            types.InlineKeyboardButton(get_lang("accept_transaction"), callback_data=f"accept_discount_tx:{discount_id}:{user_id}:{quantity}"),
            types.InlineKeyboardButton(get_lang("reject_transaction"), callback_data=f"reject_discount_tx:{discount_id}:{user_id}:{quantity}")
        )

        if message.photo:
            bot.send_photo(group_id, message.photo[-1].file_id, caption=caption, reply_markup=markup, parse_mode="HTML")
        else:
            bot.send_message(group_id, caption, reply_markup=markup, parse_mode="HTML")

        timestamp = int(datetime.now().timestamp())
        tx_id = f"discount_{discount_id}_{user_id}_{quantity}_{timestamp}"
        transactions[tx_id] = {
            "type": "discount",
            "status": "pending",
            "user_id": user_id,
            "discount_id": discount_id,
            "quantity": quantity,
            "submitted_at": datetime.now().isoformat(),
            "user_input": user_input
        }
        save_json(TRANSACTIONS_FILE, transactions)

        safe_send_message(message.chat.id, get_lang("transaction_sent_to_admin"), reply_markup=get_main_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_discount_payment_message 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("cancel_button") and m.from_user.id in user_states and str(user_states[m.from_user.id]).startswith("awaiting_discount_payment_info:"))
def handle_cancel_discount_payment(message: Message):
    user_states.pop(message.from_user.id, None)
    safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(message.from_user.id))

@bot.callback_query_handler(func=lambda c: c.data.startswith("reject_discount_tx:"))
def handle_reject_discount_transaction(call: CallbackQuery):
    try:
        admin_id = call.from_user.id
        if not is_admin(admin_id):
            return bot.answer_callback_query(call.id, get_lang("admin_only_error"))

        _, discount_id, user_id, quantity = call.data.split(":")
        user_id = int(user_id)
        quantity = int(quantity)

        discount = next((d for d in discount_codes if str(d["id"]) == str(discount_id)), None)
        if not discount:
            return bot.answer_callback_query(call.id, get_lang("discount_not_found"))

        title = discount["title"]

        tx_key = next((k for k, v in transactions.items()
                       if v["type"] == "discount" and
                          v["status"] == "pending" and
                          v["discount_id"] == discount_id and
                          v["user_id"] == user_id and
                          v["quantity"] == quantity), None)
        if not tx_key:
            return bot.answer_callback_query(call.id, get_lang("transaction_not_found"))

        transactions[tx_key]["status"] = "rejected"
        transactions[tx_key]["updated_at"] = datetime.now().isoformat()
        save_json(TRANSACTIONS_FILE, transactions)

        msg = get_lang("discount_purchase_rejected").replace("{title}", title)
        safe_send_message(user_id, msg, reply_markup=get_main_keyboard(user_id))

        new_text = call.message.caption or call.message.text
        if new_text:
            new_text = re.sub(r"(📌 وضعیت:).*", f"📌 وضعیت: {get_lang('rejected_status')}", new_text)
            markup = types.InlineKeyboardMarkup()
            markup.add(types.InlineKeyboardButton(get_lang("rejected_status"), callback_data="noop"))

            if call.message.content_type == "photo":
                bot.edit_message_caption(chat_id=call.message.chat.id, message_id=call.message.message_id,
                                         caption=new_text, parse_mode="HTML", reply_markup=markup)
            else:
                bot.edit_message_text(new_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_reject_discount_transaction error: {e}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))

def escape_markdown_v2(text):
    if not text:
        return ""
    special_chars = r'[_*[\]()~`>#+-=|{}.!]'
    return re.sub(special_chars, r'\\\g<0>', str(text))

@bot.callback_query_handler(func=lambda c: c.data.startswith("accept_discount_tx:"))
def handle_accept_discount_transaction(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return bot.answer_callback_query(call.id, get_lang("admin_only_error"))

        parts = call.data.split(":")
        if len(parts) != 4:
            return bot.answer_callback_query(call.id, get_lang("error_occurred"))

        _, discount_id, user_id, quantity = parts
        user_id = int(user_id)
        quantity = int(quantity)

        discount = next((d for d in discount_codes if str(d.get("id")) == str(discount_id)), None)
        if not discount:
            return bot.answer_callback_query(call.id, get_lang("discount_not_found"))

        available_lines = len(discount.get("lines", []))
        if available_lines < quantity:
            return bot.answer_callback_query(call.id, get_lang("discount_out_of_stock"))

        tx_key = next((k for k, v in transactions.items()
                       if v.get("type") in ("discount_purchase", "discount")
                       and v.get("status") == "pending"
                       and str(v.get("discount_id")) == str(discount_id)
                       and int(v.get("user_id")) == user_id
                       and int(v.get("quantity", 0)) == quantity), None)

        if not tx_key:
            return bot.answer_callback_query(call.id, get_lang("transaction_not_found"))

        lines = discount.get("lines", [])
        codes = discount.get("codes", [])
        descriptions = discount.get("text_descriptions", []) or [get_lang("no_caption")]

        sent_count = min(quantity, len(lines))
        purchased_lines = [lines.pop(0) for _ in range(sent_count)]

        purchased_codes = []
        for _ in range(sent_count):
            if codes:
                purchased_codes.append(codes.pop(0))
            else:
                purchased_codes.append(get_lang("default_code_text"))

        import html as _html
        purchase_parts = [get_lang("purchase_successful"), ""]
        for ln, cd in zip(purchased_lines, purchased_codes):
            purchase_parts.append(f"📞 کانفیگ: <code>{_html.escape(ln.strip())}</code>\n🔐 لینک ساب: <code>{_html.escape(cd.strip())}</code>")
            purchase_parts.append("")
        purchase_text = "\n".join(purchase_parts).strip()

        safe_send_message(user_id, purchase_text, parse_mode="HTML")

        for desc in descriptions:
            safe_send_message(user_id, _html.escape(str(desc)), parse_mode="HTML")

        transactions[tx_key]["status"] = "accepted"
        transactions[tx_key]["updated_at"] = datetime.now().isoformat()
        transactions[tx_key]["lines"] = purchased_lines
        transactions[tx_key]["codes"] = purchased_codes
        save_json(TRANSACTIONS_FILE, transactions)

        discount.setdefault("used_lines", []).extend(purchased_lines)
        discount.setdefault("used_codes", []).extend(purchased_codes)
        discount["lines"] = lines
        discount["codes"] = codes
        save_json(DISCOUNT_CODES, discount_codes)

        new_text = (call.message.caption or call.message.text or "").strip()
        accepted_status = get_lang("accepted_status")

        pattern_html = r"(📌\s*(?:<b>)?وضعیت:(?:</b>)?\s*).*"
        if re.search(pattern_html, new_text):
            new_text = re.sub(pattern_html, f"📌 <b>وضعیت:</b> {_html.escape(accepted_status)}", new_text)
        else:
            new_text = (new_text + f"\n📌 <b>وضعیت:</b> {_html.escape(accepted_status)}").strip()

        if purchased_lines:
            new_text += "\n" + "\n".join([f"📞 کانفیگ: <code>{_html.escape(l)}</code>" for l in purchased_lines])
        if purchased_codes:
            new_text += "\n" + "\n".join([f"🔐 لینک ساب: <code>{_html.escape(c)}</code>" for c in purchased_codes])

        markup = types.InlineKeyboardMarkup()
        markup.add(types.InlineKeyboardButton(get_lang("accepted_status"), callback_data="noop"))

        try:
            if getattr(call.message, "content_type", "") == "photo":
                bot.edit_message_caption(
                    chat_id=call.message.chat.id,
                    message_id=call.message.message_id,
                    caption=new_text,
                    parse_mode="HTML",
                    reply_markup=markup
                )
            else:
                bot.edit_message_text(
                    new_text,
                    call.message.chat.id,
                    call.message.message_id,
                    parse_mode="HTML",
                    reply_markup=markup
                )
        except Exception as e:
            logging.error(f"Failed to edit admin message: {e}")
            discount["lines"] = purchased_lines + discount.get("lines", [])
            discount["codes"] = purchased_codes + discount.get("codes", [])
            save_json(DISCOUNT_CODES, discount_codes)
            raise e

        bot.answer_callback_query(call.id, get_lang("transaction_accepted_admin"))

    except Exception as e:
        logging.error(f"handle_accept_discount_transaction error: {e}")
        try:
            bot.answer_callback_query(call.id, get_lang("error_occurred"))
        except Exception as e2:
            logging.error(f"answer_callback_query failed: {e2}")

@bot.message_handler(content_types=["text", "photo"], func=lambda m: user_states.get(m.from_user.id, "").startswith("awaiting_discount_payment:"))
def handle_discount_payment(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))

        _, discount_id, quantity = user_states[user_id].split(":")
        quantity = int(quantity)
        discount = next((d for d in discount_codes if str(d["id"]) == str(discount_id)), None)
        if not discount:
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("discount_not_found"), reply_markup=get_main_keyboard(user_id))

        group_id = config.get("discount_transaction_group_id")
        if not group_id:
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("no_transaction_discount_group"), reply_markup=get_main_keyboard(user_id))

        now = datetime.now()
        transaction_id = str(int(now.timestamp()))
        currency = config["currency"]
        total_price = quantity * discount["price"]
        transaction_data = {
            "user_id": user_id,
            "type": "discount_purchase",
            "discount_id": discount_id,
            "discount_title": discount["title"],
            "price": total_price,
            "quantity": quantity,
            "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 '-'})"
        discount_info = (
            f"🎟 <b>کانفیگ:</b> {discount['title']}\n"
            f"🔢 <b>تعداد:</b> {quantity}\n"
            f"💰 <b>قیمت:</b> {format_number(total_price)} {currency}\n"
            f"#خرید_کانفیگ"
        )
        status_info = f"📌 <b>وضعیت:</b> {get_lang('waiting_for_approval')}"

        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"{discount_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"{discount_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_sent_to_admin"), reply_markup=get_main_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_discount_payment error: {e}")
        user_states.pop(user_id, None)
        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("buy_discount_wallet:"))
def handle_buy_discount_wallet(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        if is_banned(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"), reply_markup=get_main_keyboard(user_id))

        discount_id = call.data.split(":")[1]
        discount = next((d for d in discount_codes if str(d["id"]) == str(discount_id)), None)
        if not discount:
            bot.answer_callback_query(call.id, get_lang("discount_not_found"))
            return safe_send_message(call.message.chat.id, get_lang("discount_not_found"), reply_markup=get_main_keyboard(user_id))

        purchase_limit = discount.get("purchase_limit", 1)
        user_purchases = count_user_discount_purchases(user_id, discount_id)
        remaining_purchases = max(0, purchase_limit - user_purchases)
        if remaining_purchases <= 0:
            bot.answer_callback_query(call.id, get_lang("discount_not_found"))
            return safe_send_message(call.message.chat.id, get_lang("discount_not_found"), reply_markup=get_main_keyboard(user_id))

        default_quantity = min(remaining_purchases, user_purchases if user_purchases > 0 else 1)
        user_states[user_id] = f"awaiting_quantity_discount:{discount_id}:{remaining_purchases}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        text = f"لطفاً تعداد مورد نظر را وارد کنید (حداکثر {remaining_purchases}، پیش‌فرض: {default_quantity}):\nخریدهای قبلی شما: {user_purchases}"
        safe_send_message(call.message.chat.id, text, 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_buy_discount_wallet error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))
        
@bot.message_handler(func=lambda m: user_states.get(m.from_user.id, "").startswith("confirm_wallet_discount_purchase:"))
def handle_confirm_wallet_discount_purchase(message: Message):
    try:
        user_id = message.from_user.id
        _, discount_id, quantity = user_states[user_id].split(":")
        quantity = int(quantity)
        discount = next((d for d in discount_codes if str(d["id"]) == str(discount_id)), None)
        if not discount:
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("discount_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))

        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.get("currency", "تومان")
        total_price = quantity * discount["price"]

        if balance < total_price:
            text = get_lang("insufficient_balance").replace("{balance}", format_number(balance)).replace("{price}", format_number(total_price)).replace("{currency}", currency)
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, text, reply_markup=get_main_keyboard(user_id))

        if len(discount["lines"]) < quantity:
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, "کانفیگ کافی موجود نیست.", reply_markup=get_main_keyboard(user_id))

        users[str(user_id)]["wallet_balance"] = balance - total_price
        save_json(USERS_FILE, users)

        now = datetime.now()
        transaction_id = str(int(now.timestamp()))
        transactions[transaction_id] = {
            "user_id": user_id,
            "type": "discount_purchase",
            "discount_id": discount_id,
            "discount_title": discount["title"],
            "price": total_price,
            "quantity": quantity,
            "status": "accepted",
            "time": now.isoformat()
        }
        save_json(TRANSACTIONS_FILE, transactions)

        if "sold_lines" not in discount:
            discount["sold_lines"] = []
            discount["sold_codes"] = []
        lines = discount.get("lines", [])
        codes = discount.get("codes", [])
        purchased_lines = lines[:quantity]
        purchased_codes = codes[:quantity] if codes else [codes[0]] * quantity if codes else [get_lang("default_code_text")]
        discount["sold_lines"].extend(purchased_lines)
        discount["sold_codes"].extend(purchased_codes)
        discount["lines"] = lines[quantity:]
        discount["codes"] = codes[quantity:] if codes else codes
        save_json(DISCOUNT_CODES, discount_codes)

        purchase_text = f"{get_lang('discount_purchase_success')}\n\n" + "\n".join(
            f"📞 {get_lang('line')}: {line}\n🔐 {get_lang('code')}: {code}"
            for line, code in zip(purchased_lines, purchased_codes)
        )
        safe_send_message(user_id, purchase_text)

        text_descriptions = discount.get("text_descriptions", [])
        if text_descriptions:
            safe_send_message(user_id, "\n".join(text_descriptions))
        for file_id in discount.get("file_ids", []):
            safe_send_document(user_id, file_id)

        group_id = config.get("discount_transaction_group_id")
        if group_id:
            user_info = f"👤 <b>کاربر:</b> {message.from_user.first_name} (@{message.from_user.username or '-'})"
            discount_info = (
                f"🎟 <b>کانفیگ:</b> {discount['title']}\n"
                f"🔢 <b>تعداد:</b> {quantity}\n"
                f"💰 <b>قیمت:</b> {format_number(total_price)} {currency}\n"
                f"#خرید_کانفیگ"
            )
            status_info = f"📌 <b>وضعیت:</b> {get_lang('accepted_status')}"
            text = f"{get_lang('new_transaction')}\n{user_info}\n🆔 <code>{user_id}</code>\n{discount_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)

        text = get_lang("wallet_purchase_success").replace("{title}", discount["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)
    except Exception as e:
        logging.error(f"handle_confirm_wallet_discount_purchase error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

# ================= حذف کامل بخش فروش کانفیگ توسط کاربر =================
# توابع مربوط به فروش کانفیگ (sell_discount_button) به طور کامل حذف شده‌اند.
# ======================================================================

# 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)

        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_file_path = os.path.join(DATA_DIR, "BAK_lang.json")
            if os.path.exists(LANG_FILE):
                os.rename(LANG_FILE, bak_file_path)
            
            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)
            
            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)

        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_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)

            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]
        send_user_info_to_admin(call.message.chat.id, user_id, call.message.message_id, edit=True)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_user_info error: {e}")

@bot.message_handler(func=lambda m: m.text and m.text.startswith("/u_") and m.text[3:].isdigit())
def handle_user_info_command(m: Message):
    try:
        if not is_admin(m.from_user.id):
            return
        user_id = m.text[3:]
        send_user_info_to_admin(m.chat.id, user_id)
    except Exception as e:
        logging.error(f"handle_user_info_command error: {e}")
        safe_send_message(m.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(m.from_user.id))

def send_user_info_to_admin(chat_id, user_id, message_id=None, edit=False):
    try:
        user = users.get(str(user_id))
        if not user:
            return safe_send_message(chat_id, get_lang("user_not_found"), reply_markup=get_main_keyboard(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(user.get("first_name", ""))
        username = escape_markdown(user.get("username", "-"))
        currency = config.get("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"))

        if edit and message_id:
            bot.edit_message_text(text, chat_id, message_id, parse_mode="Markdown", reply_markup=markup)
        else:
            safe_send_message(chat_id, text, reply_markup=markup, parse_mode="Markdown")
    except Exception as e:
        logging.error(f"send_user_info_to_admin error: {e}")
        safe_send_message(chat_id, get_lang("error_occurred"))

@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:
            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))
        
def get_start_menu():
    menu_commands = [
        types.BotCommand("start", "شروع یا ریست کردن ربات")
    ]
    bot.set_my_commands(menu_commands)

@bot.message_handler(commands=['start'])
def handle_start(message: Message):
    try:
        user_id = message.from_user.id
        ensure_user(message.from_user)
        if is_banned(user_id):
            return safe_send_message(message.chat.id, get_lang("banned_message"), reply_markup=get_main_keyboard(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
        
        user_states.pop(user_id, None)
        add_product_states.pop(user_id, None)
        add_discount_states.pop(user_id, None)
        admin_reply_states.pop(user_id, None)
        
        welcome_message = get_lang("welcome_message").replace("{store_name}", STORE_NAME)
        safe_send_message(message.chat.id, welcome_message, reply_markup=get_main_keyboard(user_id), parse_mode="HTML")
    except Exception as e:
        logging.error(f"handle_start 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_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}")
            )
            markup.add(
                types.InlineKeyboardButton(get_lang("mark_as_seen_button"), callback_data=f"mark_seen:{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("mark_seen:"))
def handle_mark_seen_support(call: CallbackQuery):
    try:
        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"))

        support_messages[msg_id]["seen"] = True
        save_json(messages_path, support_messages)

        bot.answer_callback_query(call.id, get_lang("marked_as_seen"))

        new_text = call.message.caption or call.message.text or ""
        if new_text:
            if re.search(r"📌 وضعیت:", new_text):
                new_text = re.sub(r"(📌 وضعیت:).*", f"📌 وضعیت: {get_lang('seen_status')}", new_text)
            else:
                new_text = f"{new_text}\n\n📌 وضعیت: {get_lang('seen_status')}"

            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}")
            )
            markup.add(types.InlineKeyboardButton(get_lang("mark_as_seen_button"), callback_data=f"mark_seen:{msg_id}"))

            try:
                if call.message.content_type == "photo":
                    bot.edit_message_caption(chat_id=call.message.chat.id, message_id=call.message.message_id,
                                             caption=new_text, parse_mode="HTML", reply_markup=markup)
                else:
                    bot.edit_message_text(new_text, call.message.chat.id, call.message.message_id,
                                          parse_mode="HTML", reply_markup=markup)
            except Exception as e:
                logging.error(f"handle_mark_seen_support edit message error: {e}")

    except Exception as e:
        logging.error(f"handle_mark_seen_support error: {e}")
        bot.answer_callback_query(call.id, get_lang("settings_update_failed"))

@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") and not msg.get("seen")
            ]
        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}"),
                types.InlineKeyboardButton(get_lang("mark_as_seen_button"), callback_data=f"mark_seen:{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, {})

        text_to_send = message.caption if message.photo else message.text

        message_data = {
            "from_admin": False,
            "text": text_to_send,
            "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 = []
        success_count = 0

        for uid_str, uinfo in users.items():
            try:
                if uinfo.get("banned", False):
                    continue
                uid = int(uid_str)

                if message.photo:
                    bot.send_photo(uid, message_data["photo"], caption=text_to_send, parse_mode="HTML")
                else:
                    bot.send_message(uid, text_to_send, parse_mode="HTML")

                success_count += 1
            except Exception as e:
                err = str(e).lower()
                if ("chat not found" in err) or ("blocked by the user" in err) or ("bot was blocked" in err) or ("user is deactivated" in err):
                    logging.warning(f"User {uid_str} not reachable for global message: {e}")
                else:
                    logging.error(f"Failed to send global message to {uid_str}: {e}")
                failed_users.append(uid_str)

        user_states.pop(user_id, None)

        if failed_users:
            safe_send_message(
                message.chat.id,
                get_lang("global_message_failed") + "\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
        json_files = [
            PRODUCTS_FILE,
            TRANSACTIONS_FILE,
            os.path.join(DATA_DIR, "messages.json"),
            DISCOUNT_CODES
        ]
        for file_path in json_files:
            if os.path.exists(file_path):
                save_json(file_path, {} if file_path != DISCOUNT_CODES else [])
        global products, transactions, discount_codes
        products = load_json(PRODUCTS_FILE, {})
        transactions = load_json(TRANSACTIONS_FILE, {})
        discount_codes = load_json(DISCOUNT_CODES, [])
        user_states.clear()
        add_product_states.clear()
        admin_reply_states.clear()
        add_guide_states.clear()
        add_discount_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

        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))

        markup = types.InlineKeyboardMarkup()
        currency = config["currency"]
        if products:
            for pid, p in products.items():
                if p.get("is_active", True):
                    price_text = f"{format_number(p['price'])} {currency}"
                    markup.add(types.InlineKeyboardButton(
                        text=f"📦 {p['title']} - {price_text}",
                        callback_data=f"view_product:{pid}"
                    ))
        if discount_codes:
            for discount in discount_codes:
                if discount.get("is_active", True):
                    markup.add(types.InlineKeyboardButton(
                        text=f"🎟 {discount['title']}",
                        callback_data=f"view_discount:{discount['id']}"
                    ))
        if not markup.keyboard:
            return safe_send_message(message.chat.id, get_lang("store_empty"), reply_markup=get_main_keyboard(user_id))

        safe_send_message(message.chat.id, get_lang("select_store_item"), 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_discount:"))
def handle_view_discount_code_user(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        logging.info(f"User {user_id} attempting to view discount code with callback: {call.data}")
        if is_banned(user_id):
            logging.info(f"User {user_id} is banned")
            bot.delete_message(call.message.chat.id, call.message.message_id)
            return safe_send_message(call.message.chat.id, get_lang("banned_message"), reply_markup=get_main_keyboard(user_id))

        discount_id = call.data.replace("view_discount:", "")
        logging.info(f"Extracted discount_id: {discount_id}")
        discount = next((d for d in discount_codes if str(d["id"]) == str(discount_id)), None)
        if not discount:
            logging.error(f"Discount {discount_id} not found")
            bot.answer_callback_query(call.id, get_lang("discount_not_found"))
            return safe_send_message(call.message.chat.id, get_lang("discount_not_found"), reply_markup=get_main_keyboard(user_id))

        currency = config.get("currency", "تومان")
        purchase_limit = discount.get("purchase_limit", 1)
        user_purchases = count_user_discount_purchases(user_id, discount_id)
        remaining_purchases = max(0, purchase_limit - user_purchases)
        price = discount.get("price", None)
        if price is None:
            logging.error(f"Discount {discount_id} has no price defined")
            bot.answer_callback_query(call.id, get_lang("discount_no_price"))
            return safe_send_message(call.message.chat.id, get_lang("discount_no_price"), reply_markup=get_main_keyboard(user_id))
        
        descriptions = discount.get("text_descriptions", [])
        description_text = "\n".join(descriptions) if descriptions else get_lang("no_caption")
        quantity = len(discount.get("lines", []))
        if quantity == 0:
            bot.answer_callback_query(call.id, get_lang("discount_out_of_stock_popup"))

        text = (
            f"🎟 <b>{discount['title']}</b>\n"
            f"💰 قیمت: {format_number(price)} {currency}\n"
            f"📝 توضیحات:\n{description_text}\n\n"
            f"موجودی باقی مانده از این کانفیگ: {quantity} عدد"
        )

        markup = types.InlineKeyboardMarkup()
        buttons = []

        if discount.get("is_active", True):
            if quantity == 0:
                text += f"\n🚫 موجودی این کانفیگ به پایان رسیده است، به‌زودی شارژ می‌شود."
            elif remaining_purchases <= 0:
                text += f"\n🚫 شما به حداکثر محدودیت خرید ({purchase_limit}) رسیده‌اید."
            else:
                default_quantity = min(remaining_purchases, user_purchases if user_purchases > 0 else 1)
                buttons.append(types.InlineKeyboardButton(get_lang("buy_card_to_card"), callback_data=f"select_quantity_discount:{discount_id}:{default_quantity}"))
                if config.get("wallet_enabled", False):
                    buttons.append(types.InlineKeyboardButton(get_lang("buy_with_wallet"), callback_data=f"buy_discount_wallet:{discount_id}"))
        else:
            text += f"\n🚫 این کانفیگ غیرفعال شده است."

        markup.add(*buttons)
        markup.add(types.InlineKeyboardButton(get_lang("back_to_store"), callback_data="back_to_store"))

        logging.info(f"Displaying discount {discount_id} details for user {user_id}")
        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)
    except Exception as e:
        logging.error(f"handle_view_discount_code_user error for user {user_id}, discount {discount_id}: {str(e)}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))
        safe_send_message(call.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:
        user_id = call.from_user.id
        if is_banned(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"), reply_markup=get_main_keyboard(user_id))

        markup = types.InlineKeyboardMarkup()
        currency = config["currency"]
        if products:
            for pid, p in products.items():
                if p.get("is_active", True):
                    price_text = f"{format_number(p['price'])} {currency}"
                    markup.add(types.InlineKeyboardButton(
                        text=f"📦 {p['title']} - {price_text}",
                        callback_data=f"view_product:{pid}"
                    ))
        if discount_codes:
            for discount in discount_codes:
                if discount.get("is_active", True):
                    markup.add(types.InlineKeyboardButton(
                        text=f"🎟 {discount['title']}",
                        callback_data=f"view_discount:{discount['id']}"
                    ))
        if not markup.keyboard:
            bot.delete_message(call.message.chat.id, call.message.message_id)
            return safe_send_message(call.message.chat.id, get_lang("store_empty"), reply_markup=get_main_keyboard(user_id))

        bot.edit_message_text(
            get_lang("select_store_item"),
            call.message.chat.id,
            call.message.message_id,
            reply_markup=markup,
            parse_mode="HTML"
        )
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_back_to_store error: {e}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))
        
@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"))

def count_user_discount_purchases(user_id, discount_id):
    try:
        count = sum(
            tx.get("quantity", 1) for tx in transactions.values()
            if str(tx.get("user_id")) == str(user_id)
            and str(tx.get("discount_id")) == str(discount_id)
            and tx.get("status") == "accepted"
            and tx.get("type") in ["discount_purchase", "discount"]
        )
        logging.info(f"User {user_id} purchases for discount {discount_id}: {count}")
        return count
    except Exception as e:
        logging.error(f"Error counting user purchases for user {user_id}, discount {discount_id}: {e}")
        return 0
        
@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:") or c.data.startswith("accept_discount_tx:") or c.data.startswith("reject_discount_tx:"))
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#شارژ_کیف_پول"
        elif transaction_type == "discount_purchase":
            discount = next((d for d in discount_codes if str(d["id"]) == str(transaction.get("discount_id"))), None)
            if not discount:
                bot.answer_callback_query(call.id, get_lang("discount_not_found"))
                return
            transaction_info = f"🎟 <b>کانفیگ:</b> {discount['title']}\n💰 <b>قیمت:</b> {format_number(transaction['price'])} {currency}\n🔢 <b>تعداد:</b> {transaction['quantity']}\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" or action == "accept_discount_tx":
            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, parse_mode="HTML")
            elif transaction_type == "discount_purchase":
                discount_id = transaction["discount_id"]
                quantity = transaction["quantity"]
                discount = next((d for d in discount_codes if str(d["id"]) == str(discount_id)), None)
                if not discount:
                    bot.answer_callback_query(call.id, get_lang("discount_not_found"))
                    return

                if "sold_lines" not in discount:
                    discount["sold_lines"] = []
                    discount["sold_codes"] = []

                lines = discount.get("lines", [])
                codes = discount.get("codes", [])
                if len(lines) < quantity:
                    bot.answer_callback_query(call.id, "کانفیگ کافی موجود نیست.")
                    return

                purchased_lines = lines[:quantity]
                purchased_codes = codes[:quantity] if codes else [get_lang("default_code_text")] * quantity
                discount["sold_lines"].extend(purchased_lines)
                discount["sold_codes"].extend(purchased_codes)

                discount["lines"] = lines[quantity:]
                discount["codes"] = codes[quantity:] if codes else codes
                save_json(DISCOUNT_CODES, discount_codes)

                transactions[transaction_id]["purchased_lines"] = purchased_lines
                transactions[transaction_id]["purchased_codes"] = purchased_codes
                save_json(TRANSACTIONS_FILE, transactions)

                import html
                purchase_text = f"خرید موفق ✅\n\n"
                for line, code in zip(purchased_lines, purchased_codes):
                    purchase_text += f"📞 کانفیگ: <code>{html.escape(line)}</code>\n🔐 لینک ساب: <code>{html.escape(code)}</code>\n\n"
                
                safe_send_message(user_id, purchase_text, parse_mode="HTML")

                text_descriptions = discount.get("text_descriptions", [])
                if text_descriptions:
                    safe_send_message(user_id, "\n".join(text_descriptions), parse_mode="HTML")
                for file_id in discount.get("file_ids", []):
                    safe_send_document(user_id, file_id)

                transaction_info += f"\n📞 <b>کانفیگ‌های فروخته‌شده:</b>\n" + "\n".join([f"📄 {html.escape(l)}" for l in purchased_lines])
                transaction_info += f"\n🔐 <b>لینک‌های ساب:</b>\n" + "\n".join([f"🔗 {html.escape(c)}" for c in purchased_codes])

            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> {get_lang('accepted_status')}"
            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" or action == "reject_discount_tx":
            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)
            elif transaction_type == "discount_purchase":
                safe_send_message(user_id, get_lang("discount_purchase_rejected").replace("{title}", transaction["discount_title"]))
            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> {get_lang('rejected_status')}"
            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...")
        schedule_next_reset()
        while True:
            cleanup_states()
            bot.infinity_polling()
            time.sleep(3600)
    except Exception as e:
        logging.critical(f"Bot crashed: {e}")
        
if __name__ == "__main__":
    get_start_menu()
    run_bot()