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", [])
        # اطمینان از اینکه admin_ids یک لیست است
        if not isinstance(admin_ids, list):
            logging.error(f"admin_ids is not a list: {admin_ids}")
            return False
        result = user_id in [str(aid) for aid in admin_ids]  # تبدیل تمام آیدی‌ها به رشته برای مقایسه
        logging.info(f"Checking is_admin for user {user_id}: {result}, admin_ids: {admin_ids}")
        return result
    except Exception as e:
        logging.error(f"is_admin error: {e}")
        return False

def ensure_user(user):
    try:
        if str(user.id) not in users:
            users[str(user.id)] = {
                "id": user.id,
                "first_name": user.first_name,
                "username": user.username,
                "warnings": 0,
                "received_products": 0,
                "banned": False,
                "last_support_time": "",
                "wallet_balance": 0
            }
            save_json(USERS_FILE, users)
    except Exception as e:
        logging.error(f"Error registering user {user.id}: {e}")

def is_banned(user_id):
    return users.get(str(user_id), {}).get("banned", False)

def cleanup_states():
    try:
        now = datetime.now()
        timeout = timedelta(hours=1)
        for user_id in list(user_states.keys()):
            if user_id not in users:
                user_states.pop(user_id, None)
        for user_id in list(add_product_states.keys()):
            if user_id not in users:
                add_product_states.pop(user_id, None)
        for user_id in list(admin_reply_states.keys()):
            if user_id not in users:
                admin_reply_states.pop(user_id, None)
    except Exception as e:
        logging.error(f"cleanup_states error: {e}")
        
def check_support_message_permission(user_id):
    try:
        user_data = users.get(str(user_id), {})
        limit_count = config.get("support_msg_limit", 8)
        limit_time = config.get("support_msg_window_sec", 30)
        block_duration = config.get("support_block_duration_sec", 100)

        now = datetime.now()

        # اگر کاربر در حالت بلاک هست
        block_until_str = user_data.get("support_block_until", "")
        if block_until_str:
            try:
                block_until = datetime.fromisoformat(block_until_str)
                if now < block_until:
                    remaining = (block_until - now).seconds
                    return False, get_lang("support_blocked_message").replace("{seconds}", str(remaining))
            except:
                pass  # در صورت فرمت اشتباه بلاک را نادیده بگیر

        # لیست زمانی پیام‌های اخیر در بازه محدودیت
        timestamps = user_data.get("support_msg_timestamps", [])
        valid_timestamps = [
            ts for ts in timestamps if now - datetime.fromisoformat(ts) < timedelta(seconds=limit_time)
        ]

        if len(valid_timestamps) >= limit_count:
            block_until_time = now + timedelta(seconds=block_duration)
            users[str(user_id)]["support_block_until"] = block_until_time.isoformat()
            users[str(user_id)]["support_msg_timestamps"] = valid_timestamps
            save_json(USERS_FILE, users)
            return False, get_lang("support_blocked_message").replace("{seconds}", str(block_duration))

        # اضافه کردن زمان جدید به لیست
        valid_timestamps.append(now.isoformat())
        users[str(user_id)]["support_msg_timestamps"] = valid_timestamps
        save_json(USERS_FILE, users)

        return True, ""
    except Exception as e:
        logging.error(f"check_support_message_permission error: {e}")
        return False, get_lang("support_error_message")

def get_main_keyboard(user_id):
    try:
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("store_button"), get_lang("sell_discount_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

# discount codes
@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']}"
                ))
        # else:
            # safe_send_message(message.chat.id, get_lang("no_discount_codes"))
        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"🔢 خط: {total_lines} / {remaining_lines}\n"
            f"📋 کدها: {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

        # کَلمپ مقدار انتخابی به بازه 1 تا remaining
        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")

        # ساخت tx_id یکتا
        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):
    """Escape special characters for MarkdownV2."""
    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"))

        # ارسال به کاربر - مثل گروه با HTML
        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)

        # ویرایش پیام گروه (HTML) + تغییر وضعیت + اضافه کردن line/code
        new_text = (call.message.caption or call.message.text or "").strip()
        accepted_status = get_lang("accepted_status")

        # جایگزینی خط وضعیت (با/بی تگ <b>)
        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))

# discount codes

# user discount codes
@bot.message_handler(func=lambda m: m.text == get_lang("sell_discount_button"))
def handle_start_discount_offer(message: Message):
    user_id = message.from_user.id
    user_states[user_id] = "offer_select_type"

    reply_kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
    reply_kb.row(
        get_lang("offer_type_snapp_food"),
        get_lang("offer_type_tapsi_food")
    )
    reply_kb.row(
        get_lang("offer_type_snapp_taxi"),
        get_lang("offer_type_snapp_express")
    )
    reply_kb.row(
        get_lang("offer_type_snapp_shop"),
        get_lang("offer_type_snapp_sweets")
    )
    reply_kb.row(
        get_lang("offer_type_snapp_smoothie"),
        get_lang("offer_type_snapp_protein")
    )
    reply_kb.row(get_lang("cancel_button"))

    bot.send_message(
        message.chat.id,
        get_lang("offer_select_type_prompt"),
        reply_markup=reply_kb
    )

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "offer_select_type")
def handle_offer_type_selected(message: Message):
    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))

    type_map = {
        get_lang("offer_type_snapp_food"): "snapp_food",
        get_lang("offer_type_tapsi_food"): "tapsi_food",
        get_lang("offer_type_snapp_taxi"): "snapp_taxi",
        get_lang("offer_type_snapp_express"): "snapp_express",
        get_lang("offer_type_snapp_shop"): "snapp_shop",
        get_lang("offer_type_snapp_sweets"): "snapp_sweets",
        get_lang("offer_type_snapp_smoothie"): "snapp_smoothie",
        get_lang("offer_type_snapp_protein"): "snapp_protein"
    }

    offer_type = type_map.get(message.text)
    if not offer_type:
        return bot.send_message(message.chat.id, get_lang("invalid_discount_type"))

    user_states[user_id] = f"offer_amount_min:{offer_type}"

    bot.send_message(
        message.chat.id,
        get_lang("offer_enter_amount_and_min"),
        reply_markup=get_cancel_keyboard()
    )


@bot.callback_query_handler(func=lambda c: c.data.startswith("offer_type:"))
def handle_offer_type_selected(call: CallbackQuery):
    user_id = call.from_user.id
    offer_type = call.data.split("offer_type:")[1]
    user_states[user_id] = f"offer_amount_min:{offer_type}"
    bot.answer_callback_query(call.id)
    bot.send_message(call.message.chat.id, get_lang("offer_enter_amount_and_min"))

@bot.callback_query_handler(func=lambda c: c.data == "cancel_offer")
def handle_cancel_offer(call: CallbackQuery):
    user_states.pop(call.from_user.id, None)
    bot.answer_callback_query(call.id, get_lang("cancelled"))
    bot.send_message(call.message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(call.from_user.id))

@bot.message_handler(func=lambda m: str(user_states.get(m.from_user.id, "")).startswith("offer_amount_min:"))
def handle_offer_amount_min_input(message: Message):
    user_id = message.from_user.id
    state = str(user_states.get(user_id))
    offer_type = state.split("offer_amount_min:")[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))

    # ذخیره مبلغ و حداقل خرید (به‌صورت متن آزاد)
    amount_info = message.text.strip()
    user_states[user_id] = f"offer_awaiting_code:{offer_type}:{amount_info}"

    bot.send_message(
        message.chat.id,
        get_lang("offer_send_code_instruction"),
        reply_markup=get_cancel_keyboard()
    )


def get_cancel_keyboard():
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    markup.row(get_lang("cancel_button"))
    return markup

@bot.message_handler(func=lambda m: str(user_states.get(m.from_user.id, "")).startswith("offer_awaiting_code:"))
def handle_offer_code_input(message: Message):
    user_id = message.from_user.id
    state = str(user_states.get(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))

    _, offer_type, amount_info = state.split(":", 2)
    code_text = message.text.strip()

    # مرحله جدید: تاریخ انقضا
    user_states[user_id] = f"offer_expiry:{offer_type}:{amount_info}:{code_text}"
    bot.send_message(
        message.chat.id,
        get_lang("offer_enter_expiry_prompt"),
        reply_markup=get_cancel_keyboard()
    )

@bot.message_handler(func=lambda m: str(user_states.get(m.from_user.id, "")).startswith("offer_expiry:"))
def handle_offer_expiry_input(message: Message):
    user_id = message.from_user.id
    state = str(user_states.get(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))

    _, offer_type, amount_info, code_text = state.split(":", 3)
    expiry_text = message.text.strip()  # بدون اعتبارسنجی، هرچی کاربر نوشت ذخیره میشه

    user_states[user_id] = f"offer_price:{offer_type}:{amount_info}:{code_text}:{expiry_text}"
    bot.send_message(
        message.chat.id,
        get_lang("offer_enter_price_prompt"),
        reply_markup=get_cancel_keyboard()
    )

# grok
@bot.message_handler(func=lambda m: str(user_states.get(m.from_user.id, "")).startswith("offer_price:"))
def handle_offer_price_input(message: Message):
    user_id = message.from_user.id
    state = str(user_states.get(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))

    try:
        price = int(message.text.strip())
        if price <= 0:
            raise ValueError
    except ValueError:
        return safe_send_message(message.chat.id, get_lang("offer_invalid_price"), reply_markup=get_cancel_keyboard())

    parts = state.split(":", 4)
    offer_type = parts[1]
    amount_info = parts[2]
    code_text = parts[3]
    expiry = parts[4]  # هر متنی که کاربر داده

    user_states[user_id] = f"offer_card_info:{offer_type}:{amount_info}:{code_text}:{price}:{expiry}"
    bot.send_message(
        message.chat.id,
        get_lang("offer_enter_card_info"),
        reply_markup=get_cancel_keyboard()
    )


@bot.message_handler(func=lambda m: str(user_states.get(m.from_user.id, "")).startswith("offer_card_info:"))
def handle_offer_card_info_input(message: Message):
    user_id = message.from_user.id
    state = str(user_states.get(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))

    card_info = message.text.strip()
    parts = state.split(":", 5)
    offer_type = parts[1]
    amount_info = parts[2]
    code_text = parts[3]
    price = parts[4]
    expiry = parts[5]  # متن تاریخ انقضا

    offer_id = f"offer_{uuid.uuid4().hex[:8]}"
    offer_data = {
        "offer_id": offer_id,
        "user_id": user_id,
        "offer_type": offer_type,
        "amount_info": amount_info,
        "code": code_text,
        "price": int(price),
        "card_info": card_info,
        "expiry": expiry,
        "status": "pending",
        "created_at": datetime.now().isoformat()
    }

    offers = load_json("data/discount_offers.json")
    offers[offer_id] = offer_data
    save_json("data/discount_offers.json", offers)

    username = users.get(str(user_id), {}).get("username")
    user_display = f"{user_id} (@{username})" if username else str(user_id)

    group_message = (
        f"📬 درخواست جدید فروش کدتخفیف\n"
        f"🆔 شناسه: {offer_id}\n"
        f"👤 کاربر: {user_display}\n"
        f"🎟️ نوع: {get_lang(f'offer_type_{offer_type}')}\n"
        f"💰 مبلغ و حداقل خرید: {amount_info}\n"
        f"🔐 کد: {code_text}\n"
        f"⏳ تاریخ انقضا: {expiry}\n"
        f"💵 قیمت پیشنهادی: {price} تومان\n"
        f"💳 شماره کارت: {card_info}\n"
        f"📌 وضعیت: {get_lang('offer_pending_status')}"
    )


    markup = types.InlineKeyboardMarkup()
    markup.add(types.InlineKeyboardButton(get_lang("offer_reject_expensive"), callback_data=f"reject_expensive:{offer_id}"))
    markup.add(types.InlineKeyboardButton(get_lang("offer_reject_invalid"), callback_data=f"reject_invalid:{offer_id}"))
    markup.add(types.InlineKeyboardButton(get_lang("offer_confirm"), callback_data=f"confirm:{offer_id}"))

    bot.send_message(
        config["discount_transaction_group_id"],
        group_message,
        reply_markup=markup
    )

    bot.send_message(
        message.chat.id,
        get_lang("offer_submitted"),
        reply_markup=get_main_keyboard(user_id)
    )
    user_states.pop(user_id, None)

def update_offer_status(offer_id: str, status: str):
    offers = load_json("data/discount_offers.json")
    if offer_id in offers:
        offers[offer_id]["status"] = status
        save_json("data/discount_offers.json", offers)

def get_offer_user_id(offer_id: str) -> int:
    offers = load_json("data/discount_offers.json")
    return offers.get(offer_id, {}).get("user_id", 0)

def update_group_message(message: Message, offer_id: str, status_text: str):
    offers = load_json("data/discount_offers.json")
    offer = offers.get(offer_id)
    if not offer:
        return

    username = users.get(str(offer["user_id"]), {}).get("username")
    user_display = f"{offer['user_id']} (@{username})" if username else str(offer["user_id"])
    offer_type = offer['offer_type']
    expiry = offer.get("expiry", get_lang("no_caption"))

    updated_message = (
        f"📬 درخواست فروش کدتخفیف\n"
        f"🆔 شناسه: {offer_id}\n"
        f"👤 کاربر: {user_display}\n"
        f"🎟️ نوع: {get_lang(f'offer_type_{offer_type}')}\n"
        f"💰 مبلغ و حداقل خرید: {offer['amount_info']}\n"
        f"🔐 کد: {offer['code']}\n"
        f"⏳ تاریخ انقضا: {expiry}\n"
        f"💵 قیمت پیشنهادی: {offer['price']} تومان\n"
        f"💳 شماره کارت: {offer['card_info']}\n"
        f"📌 وضعیت: {status_text}"
    )


    markup = types.InlineKeyboardMarkup()
    markup.add(types.InlineKeyboardButton(status_text, callback_data="noop"))
    bot.edit_message_text(
        updated_message,
        message.chat.id,
        message.message_id,
        reply_markup=markup
    )

@bot.callback_query_handler(func=lambda c: c.data.startswith("reject_expensive:"))
def handle_reject_expensive(call: CallbackQuery):
    offer_id = call.data.split("reject_expensive:")[1]
    update_offer_status(offer_id, "rejected_expensive")
    update_group_message(call.message, offer_id, get_lang("offer_reject_expensive"))
    bot.send_message(
        get_offer_user_id(offer_id),
        get_lang("offer_rejected_expensive"),
        reply_markup=get_main_keyboard(get_offer_user_id(offer_id))
    )
    bot.answer_callback_query(call.id, get_lang("offer_rejected"))

@bot.callback_query_handler(func=lambda c: c.data.startswith("reject_invalid:"))
def handle_reject_invalid(call: CallbackQuery):
    offer_id = call.data.split("reject_invalid:")[1]
    update_offer_status(offer_id, "rejected_invalid")
    update_group_message(call.message, offer_id, get_lang("offer_reject_invalid"))
    bot.send_message(
        get_offer_user_id(offer_id),
        get_lang("offer_rejected_invalid"),
        reply_markup=get_main_keyboard(get_offer_user_id(offer_id))
    )
    bot.answer_callback_query(call.id, get_lang("offer_rejected"))

@bot.callback_query_handler(func=lambda c: c.data.startswith("confirm:"))
def handle_confirm_offer(call: CallbackQuery):
    try:
        offer_id = call.data.split(":", 1)[1]
        offers = load_json("data/discount_offers.json")
        offer = offers.get(offer_id)
        if not offer:
            return bot.answer_callback_query(call.id, get_lang("offer_rejected"))

        offer["status"] = "accepted"
        save_json("data/discount_offers.json", offers)

        # ساخت متن جدید برای کاربر
        offer_type = get_lang(f"offer_type_{offer['offer_type']}")
        amount_info = offer["amount_info"]
        price = offer["price"]
        confirm_text = f"✅ کد {offer_type} | {amount_info} با {price} تومان شما دریافت شد.\n" \
                    f"لطفاً کد را استفاده نکنید یا در اختیار دیگران قرار ندهید تا واریزی انجام شود."

        safe_send_message(offer["user_id"], confirm_text)

        # به‌روزرسانی پیام گروه با دکمه «واریز شد»
        markup = types.InlineKeyboardMarkup()
        markup.add(types.InlineKeyboardButton("💳 واریز شد", callback_data=f"paid:{offer_id}"))

        update_group_message_with_markup(call.message, offer_id, get_lang("offer_confirmed"), markup)

        bot.answer_callback_query(call.id, get_lang("offer_confirmed"))
    except Exception as e:
            logging.error(f"handle_offer_confirm error: {e}")
            bot.answer_callback_query(call.id, get_lang("error_occurred"))
            
@bot.callback_query_handler(func=lambda c: c.data.startswith("paid:"))
def handle_offer_paid(call: CallbackQuery):
    try:
        offer_id = call.data.split(":", 1)[1]
        offers = load_json("data/discount_offers.json")
        offer = offers.get(offer_id)
        if not offer:
            return bot.answer_callback_query(call.id, get_lang("offer_rejected"))

        # ارسال پیام واریز به کاربر
        offer_type = get_lang(f"offer_type_{offer['offer_type']}")
        amount_info = offer["amount_info"]
        price = offer["price"]
        card_info = offer["card_info"]
        paid_text = f"هزینه ی کد تخفیف ارسالی شما به {card_info} واریز شد ✅ - {offer_type} | {amount_info} - {price} تومان"

        safe_send_message(offer["user_id"], paid_text)

        # تغییر پیام گروه به «واریز شده»
        markup = types.InlineKeyboardMarkup()
        markup.add(types.InlineKeyboardButton("✅ واریز شده", callback_data="noop"))
        update_group_message_with_markup(call.message, offer_id, "واریز شده", markup)

        bot.answer_callback_query(call.id, "واریز ثبت شد.")
    except Exception as e:
        logging.error(f"handle_offer_paid error: {e}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))

def update_group_message_with_markup(message: Message, offer_id: str, status_text: str, markup):
    offers = load_json("data/discount_offers.json")
    offer = offers.get(offer_id)
    if not offer:
        return

    username = users.get(str(offer["user_id"]), {}).get("username")
    user_display = f"{offer['user_id']} (@{username})" if username else str(offer["user_id"])
    offer_type = get_lang(f"offer_type_{offer['offer_type']}")
    expiry = offer.get("expiry", get_lang("no_caption"))

    updated_message = (
        f"📬 درخواست فروش کدتخفیف\n"
        f"🆔 شناسه: {offer_id}\n"
        f"👤 کاربر: {user_display}\n"
        f"🎟️ نوع: {get_lang(f'offer_type_{offer_type}')}\n"
        f"💰 مبلغ و حداقل خرید: {offer['amount_info']}\n"
        f"🔐 کد: {offer['code']}\n"
        f"⏳ تاریخ انقضا: {expiry}\n"
        f"💵 قیمت پیشنهادی: {offer['price']} تومان\n"
        f"💳 شماره کارت: {offer['card_info']}\n"
        f"📌 وضعیت: {status_text}"
    )

    bot.edit_message_text(
        updated_message,
        message.chat.id,
        message.message_id,
        reply_markup=markup
    )


# user discount codes
# channels
@bot.message_handler(func=lambda m: m.text == get_lang("admin_manage_channels"))
def handle_manage_channels(message: Message):
    try:
        user_id = message.from_user.id
        logging.info(f"User {user_id} clicked manage_channels")
        channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
        kb = types.InlineKeyboardMarkup()
        for channel in channels:
            kb.add(types.InlineKeyboardButton(channel["name"], callback_data=f"view_channel_{channel['id']}"))
        kb.add(types.InlineKeyboardButton(get_lang("admin_add_channel"), callback_data="add_channel"))
        safe_send_message(message.chat.id, get_lang("select_channel"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_manage_channels error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("view_channel_"))
def handle_view_channel(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        channel_id = call.data.split("_")[2]
        channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
        channel = next((c for c in channels if c["id"] == channel_id), None)
        if not channel:
            bot.answer_callback_query(call.id, get_lang("channel_not_found"))
            return
        chat = bot.get_chat(channel["chat_id"])
        members_count = bot.get_chat_member_count(channel["chat_id"])
        text = (
            f"📢 <b>{channel['name']}</b>\n"
            f"🆔 ID: {channel['chat_id']}\n"
            f"🔗 Link: {channel.get('link', '-')}\n"
            f"👤 Username: {channel.get('username', '-')}\n"
            f"👥 Members: {members_count}\n"
            f"📊 Successful Joins: {channel.get('successful_joins', 0)}\n"
            f"📝 Description: {chat.description or '-'}\n"
            f"📌 Type: {chat.type}"
        )
        kb = types.InlineKeyboardMarkup()
        kb.add(types.InlineKeyboardButton(get_lang("delete_channel"), callback_data=f"delete_channel_{channel_id}"))
        kb.add(types.InlineKeyboardButton(get_lang("back_to_channels"), callback_data="manage_channels"))
        bot.edit_message_text(text, call.message.chat.id, call.message.message_id, parse_mode="HTML", reply_markup=kb)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_view_channel error: {e}")
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))
        
@bot.callback_query_handler(func=lambda c: c.data == "manage_channels")
def handle_back_to_channels(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        logging.info(f"User {user_id} clicked back_to_channels")
        channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
        kb = types.InlineKeyboardMarkup()
        for channel in channels:
            kb.add(types.InlineKeyboardButton(channel["name"], callback_data=f"view_channel_{channel['id']}"))
        kb.add(types.InlineKeyboardButton(get_lang("admin_add_channel"), callback_data="add_channel"))
        bot.edit_message_text(
            get_lang("select_channel"),
            call.message.chat.id,
            call.message.message_id,
            reply_markup=kb
        )
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_back_to_channels error: {e}")
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data.startswith("delete_channel_"))
def handle_delete_channel(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        channel_id = call.data.split("_")[2]
        channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
        channels = [c for c in channels if c["id"] != channel_id]
        save_json(os.path.join(DATA_DIR, "channels.json"), channels)
        safe_send_message(call.message.chat.id, get_lang("channel_deleted"), reply_markup=get_settings_keyboard(user_id))
        bot.delete_message(call.message.chat.id, call.message.message_id)
        bot.answer_callback_query(call.id)
        call.data = "manage_channels"
        handle_manage_channels(call.message)
    except Exception as e:
        logging.error(f"handle_delete_channel error: {e}")
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data == "add_channel")
def handle_add_channel(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        logging.info(f"User {user_id} clicked add_channel")
        user_states[user_id] = "awaiting_channel_name"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(call.message.chat.id, get_lang("enter_channel_name"), reply_markup=kb)
        bot.delete_message(call.message.chat.id, call.message.message_id)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_add_channel error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(call.message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_channel_name")
def handle_channel_name(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            add_guide_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))
        if not message.text:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("text_only"), reply_markup=kb)
        add_guide_states[user_id] = {"name": message.text}
        user_states[user_id] = "awaiting_channel_id"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("enter_channel_id"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_channel_name error: {e}")
        user_states.pop(user_id, None)
        add_guide_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_channel_id")
def handle_channel_id(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            add_guide_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))
        if not message.text:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("text_only"), reply_markup=kb)
        
        channel_input = message.text.strip()
        channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
        channel_id = str(int(datetime.now().timestamp()))
        channel_data = {"id": channel_id, "name": add_guide_states[user_id]["name"], "successful_joins": 0}

        # بررسی ورودی به عنوان لینک یا آیدی
        if channel_input.startswith("https://t.me/") or channel_input.startswith("@"):
            username = channel_input.split("/")[-1] if channel_input.startswith("https://") else channel_input[1:]
            link = f"https://t.me/{username}"
            try:
                chat = bot.get_chat(f"@{username}")
                channel_data["chat_id"] = chat.id
                channel_data["username"] = f"@{username}"
                channel_data["link"] = link
            except Exception as e:
                logging.error(f"Invalid channel {channel_input}: {e}")
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("invalid_channel_id"), reply_markup=kb)
        elif channel_input.lstrip("-").isdigit():
            try:
                chat = bot.get_chat(int(channel_input))
                channel_data["chat_id"] = chat.id
                channel_data["username"] = f"@{chat.username}" if chat.username else "-"
                channel_data["link"] = f"https://t.me/{chat.username}" if chat.username else "-"
            except Exception as e:
                logging.error(f"Invalid channel ID {channel_input}: {e}")
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("invalid_channel_id"), reply_markup=kb)
        else:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_channel_id"), reply_markup=kb)

        # بررسی وجود کانال/گروه با chat_id مشابه
        if any(c["chat_id"] == channel_data["chat_id"] for c in channels):
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("channel_already_exists"), reply_markup=kb)

        channels.append(channel_data)
        save_json(os.path.join(DATA_DIR, "channels.json"), channels)
        user_states.pop(user_id, None)
        add_guide_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("channel_added"), reply_markup=get_settings_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_channel_id error: {e}")
        user_states.pop(user_id, None)
        add_guide_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

# checking
def check_channel_membership(user_id):
    try:
        channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
        not_joined = []
        for channel in channels:
            try:
                chat_member = bot.get_chat_member(channel["chat_id"], user_id)
                if chat_member.status not in ["member", "administrator", "creator"]:
                    not_joined.append(channel)
            except Exception as e:
                logging.error(f"check_channel_membership error for user {user_id}, channel {channel['chat_id']}: {e}")
                not_joined.append(channel)
        return not_joined
    except Exception as e:
        logging.error(f"check_channel_membership error: {e}")
        return []
    
def show_channel_buttons(chat_id, user_id, not_joined_channels):
    try:
        if not not_joined_channels:
            return False, get_main_keyboard(user_id)
        kb = types.InlineKeyboardMarkup()
        for channel in not_joined_channels:
            link = channel.get("link", f"https://t.me/{channel['username']}" if channel.get("username") else "#")
            kb.add(types.InlineKeyboardButton(channel["name"], url=link))
        kb.add(types.InlineKeyboardButton(get_lang("check_membership_button"), callback_data="check_membership"))
        safe_send_message(chat_id, get_lang("join_channels_required"), reply_markup=kb, parse_mode="HTML")
        return True, None
    except Exception as e:
        logging.error(f"show_channel_buttons error: {e}")
        safe_send_message(chat_id, get_lang("error_occurred"))
        return False, get_main_keyboard(user_id)

@bot.callback_query_handler(func=lambda c: c.data == "check_membership")
def handle_check_membership(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        not_joined_channels = check_channel_membership(user_id)
        if not not_joined_channels:
            channels = load_json(os.path.join(DATA_DIR, "channels.json"), [])
            for channel in channels:
                try:
                    chat_member = bot.get_chat_member(channel["chat_id"], user_id)
                    if chat_member.status in ["member", "administrator", "creator"]:
                        channel["successful_joins"] = channel.get("successful_joins", 0) + 1
                except Exception as e:
                    logging.error(f"handle_check_membership error for channel {channel['chat_id']}: {e}")
            save_json(os.path.join(DATA_DIR, "channels.json"), channels)
            bot.answer_callback_query(call.id, get_lang("membership_confirmed"))
            bot.delete_message(call.message.chat.id, call.message.message_id)
            safe_send_message(call.message.chat.id, get_lang("back_to_main_menu"), reply_markup=get_main_keyboard(user_id))
        else:
            bot.answer_callback_query(call.id, get_lang("not_joined_all_channels"))
            bot.delete_message(call.message.chat.id, call.message.message_id)
            show_channel_buttons(call.message.chat.id, user_id, not_joined_channels)
    except Exception as e:
        logging.error(f"handle_check_membership error: {e}")
        bot.answer_callback_query(call.id, get_lang("error_occurred"))
# channels

# wallet on/off
@bot.message_handler(func=lambda m: m.text in [get_lang("enable_wallet_button"), get_lang("disable_wallet_button")])
def handle_toggle_wallet(message: Message):
    try:
        user_id = message.from_user.id
        if not is_admin(user_id):
            return safe_send_message(message.chat.id, get_lang("not_admin"))
        config["wallet_enabled"] = not config.get("wallet_enabled", True)
        save_json(CONFIG_FILE, config)
        safe_send_message(message.chat.id, get_lang("settings_updated"), reply_markup=get_settings_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_toggle_wallet error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))
# wallet on/off

def load_guides():
    return load_json(GUIDES_FILE, [])

@bot.message_handler(func=lambda m: m.text == get_lang("admin_manage_guides"))
def handle_manage_guides(message: Message):
    try:
        user_id = message.from_user.id
        logging.info(f"User {user_id} clicked manage_guides")
        guides = load_guides()
        kb = types.InlineKeyboardMarkup()
        for guide in guides:
            kb.add(types.InlineKeyboardButton(f"{guide['name']} (حذف)", callback_data=f"delete_guide_{guide['id']}"))
        kb.add(types.InlineKeyboardButton(get_lang("admin_add_guide"), callback_data="add_guide"))
        safe_send_message(message.chat.id, get_lang("select_guide"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_manage_guides error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data.startswith("delete_guide_"))
def handle_delete_guide(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        guide_id = call.data.split("_")[2]
        guides = load_guides()
        guide = next((g for g in guides if g["id"] == guide_id), None)
        if not guide:
            bot.answer_callback_query(call.id, get_lang("guide_not_found"))
            return
        transaction_group = config.get("transaction_group", "")
        if transaction_group:
            for file_id in guide.get("file_ids", []):
                try:
                    bot.delete_message(transaction_group, file_id)
                except Exception as e:
                    logging.error(f"Failed to delete message {file_id}: {e}")
        guides = [g for g in guides if g["id"] != guide_id]
        save_json(GUIDES_FILE, guides)
        safe_send_message(call.message.chat.id, get_lang("guide_deleted"), reply_markup=get_settings_keyboard(user_id))
        bot.delete_message(call.message.chat.id, call.message.message_id)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_delete_guide error: {e}")
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_settings_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data == "add_guide")
def handle_add_guide(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        logging.info(f"User {user_id} clicked add_guide")
        user_states[user_id] = "awaiting_guide_name"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(call.message.chat.id, get_lang("enter_guide_name"), reply_markup=kb)
        bot.delete_message(call.message.chat.id, call.message.message_id)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_add_guide error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(call.message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_guide_name")
def handle_guide_name(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            add_guide_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))
        if not message.text:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("text_only"), reply_markup=kb)
        add_guide_states[user_id] = {"name": message.text, "files": []}
        user_states[user_id] = "awaiting_guide_description"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("enter_guide_description"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_guide_name error: {e}")
        user_states.pop(user_id, None)
        add_guide_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_guide_description")
def handle_guide_description(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            add_guide_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))
        if not message.text:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("text_only"), reply_markup=kb)
        add_guide_states[user_id]["description"] = message.text
        user_states[user_id] = "awaiting_guide_files"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"), get_lang("finish_upload"))
        safe_send_message(message.chat.id, get_lang("send_guide_files"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_guide_description error: {e}")
        user_states.pop(user_id, None)
        add_guide_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(content_types=["text", "photo", "video", "document", "audio"], func=lambda m: user_states.get(m.from_user.id) == "awaiting_guide_files")
def handle_guide_files(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            add_guide_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))
        if message.text == get_lang("finish_upload"):
            guides = load_guides()
            guide_id = str(len(guides) + 1)
            guide = add_guide_states[user_id]
            guide["id"] = guide_id
            transaction_group = config.get("transaction_group_id", None)
            logging.info(f"Transaction group in handle_guide_files: {transaction_group}")
            if not transaction_group:
                user_states.pop(user_id, None)
                add_guide_states.pop(user_id, None)
                return safe_send_message(message.chat.id, get_lang("no_transaction_group"), reply_markup=get_settings_keyboard(user_id))
            guide["file_ids"] = []
            for file in guide["files"]:
                sent_message = None
                caption = f"📚 راهنما: {guide['name']}"  # افزودن کپشن برای مشخص شدن راهنما
                if file["type"] == "text":
                    sent_message = bot.send_message(transaction_group, f"{caption}\n{file['content']}")
                elif file["type"] == "photo":
                    sent_message = bot.send_photo(transaction_group, file["content"], caption=caption)
                elif file["type"] == "video":
                    sent_message = bot.send_video(transaction_group, file["content"], caption=caption)
                elif file["type"] == "document":
                    sent_message = bot.send_document(transaction_group, file["content"], caption=caption)
                elif file["type"] == "audio":
                    sent_message = bot.send_audio(transaction_group, file["content"], caption=caption)
                if sent_message:
                    guide["file_ids"].append(sent_message.message_id)
            guides.append(guide)
            save_json(GUIDES_FILE, guides)
            user_states.pop(user_id, None)
            add_guide_states.pop(user_id, None)
            safe_send_message(message.chat.id, get_lang("guide_added"), reply_markup=get_settings_keyboard(user_id))
            return
        file_info = {}
        if message.text:
            file_info = {"type": "text", "content": message.text}
        elif message.photo:
            file_info = {"type": "photo", "content": message.photo[-1].file_id}
        elif message.video:
            file_info = {"type": "video", "content": message.video.file_id}
        elif message.document:
            file_info = {"type": "document", "content": message.document.file_id}
        elif message.audio:
            file_info = {"type": "audio", "content": message.audio.file_id}
        add_guide_states[user_id]["files"].append(file_info)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"), get_lang("finish_upload"))
        safe_send_message(message.chat.id, get_lang("file_received"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_guide_files error: {e}")
        user_states.pop(user_id, None)
        add_guide_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("guide_button"))
def handle_get_guides(message: Message):
    try:
        user_id = message.from_user.id
        not_joined_channels = check_channel_membership(user_id)
        sent_channels, keyboard = show_channel_buttons(message.chat.id, user_id, not_joined_channels)
        if sent_channels:
            return
        logging.info(f"User {user_id} clicked guide_button")
        guides = load_guides()
        if not guides:
            return safe_send_message(message.chat.id, get_lang("no_guides_available"), reply_markup=get_main_keyboard(user_id))
        kb = types.InlineKeyboardMarkup()
        for guide in guides:
            kb.add(types.InlineKeyboardButton(guide["name"], callback_data=f"guide_{guide['id']}"))
        safe_send_message(message.chat.id, get_lang("select_guide"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_get_guides error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data.startswith("guide_"))
def handle_guide_selection(call: CallbackQuery):
    try:
        user_id = call.from_user.id
        guide_id = call.data.split("_")[1]
        guides = load_guides()
        guide = next((g for g in guides if g["id"] == guide_id), None)
        if not guide:
            bot.answer_callback_query(call.id, get_lang("guide_not_found"))
            return
        safe_send_message(call.message.chat.id, f"<b>{guide['name']}</b>\n{guide['description']}", parse_mode="HTML")
        for file in guide.get("files", []):
            try:
                if file["type"] == "text":
                    safe_send_message(call.message.chat.id, file["content"], parse_mode="HTML")
                elif file["type"] == "photo":
                    bot.send_photo(call.message.chat.id, file["content"], caption=f"📸 {guide['name']}")
                elif file["type"] == "video":
                    bot.send_video(call.message.chat.id, file["content"], caption=f"🎥 {guide['name']}")
                elif file["type"] == "document":
                    bot.send_document(call.message.chat.id, file["content"], caption=f"📄 {guide['name']}")
                elif file["type"] == "audio":
                    bot.send_audio(call.message.chat.id, file["content"], caption=f"🎵 {guide['name']}")
            except Exception as e:
                logging.error(f"Failed to send guide file {file['content']}: {e}")
                safe_send_message(call.message.chat.id, get_lang("file_send_failed"), parse_mode="HTML")
        bot.delete_message(call.message.chat.id, call.message.message_id)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_guide_selection error: {e}")
        safe_send_message(call.message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("admin_manage_lang_file"))
def handle_manage_lang_file(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return
        
        user_states[message.from_user.id] = "awaiting_lang_file_action"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("download_lang_file"), get_lang("upload_lang_file"))
        kb.row(get_lang("load_default_lang"), get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("manage_lang_file_prompt"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_manage_lang_file error: {e}")
        user_states.pop(message.from_user.id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(message.from_user.id))
        
@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_lang_file_action")
def handle_lang_file_action(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))

        if message.text == get_lang("download_lang_file"):
            if not os.path.exists(LANG_FILE):
                return safe_send_message(message.chat.id, get_lang("lang_file_not_found"), reply_markup=get_settings_keyboard(user_id))
            
            # پیام انتظار
            safe_send_message(message.chat.id, get_lang("please_wait_download"))
            
            # ارسال فایل
            with open(LANG_FILE, "rb") as f:
                bot.send_document(message.chat.id, f, caption=get_lang("current_lang_file"))
            safe_send_message(message.chat.id, get_lang("lang_file_downloaded"), reply_markup=get_settings_keyboard(user_id))
            user_states.pop(user_id, None)
            return

        if message.text == get_lang("upload_lang_file"):
            user_states[user_id] = "awaiting_lang_file_upload"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            safe_send_message(message.chat.id, get_lang("send_lang_file"), reply_markup=kb)
            return

        if message.text == get_lang("load_default_lang"):
            if not os.path.exists(DEFAULT_LANG_FILE):
                return safe_send_message(message.chat.id, get_lang("default_lang_file_not_found"), reply_markup=get_settings_keyboard(user_id))
            
            # تغییر نام فایل قدیمی به BAK_lang.json
            bak_file_path = os.path.join(DATA_DIR, "BAK_lang.json")
            if os.path.exists(LANG_FILE):
                os.rename(LANG_FILE, bak_file_path)
            
            # کپی محتوای default_lang.json به lang.json
            with open(DEFAULT_LANG_FILE, "r", encoding="utf-8") as default_f:
                default_lang_data = json.load(default_f)
            save_json(LANG_FILE, default_lang_data)
            
            # به‌روزرسانی متغیر lang
            global lang
            lang = load_json(LANG_FILE, {})
            
            user_states.pop(user_id, None)
            safe_send_message(message.chat.id, get_lang("default_lang_loaded"), reply_markup=get_settings_keyboard(user_id))
            return

        safe_send_message(message.chat.id, get_lang("invalid_action"), reply_markup=get_settings_keyboard(user_id))
        user_states.pop(user_id, None)
    except Exception as e:
        logging.error(f"handle_lang_file_action error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))
        
@bot.message_handler(content_types=["document"], func=lambda m: user_states.get(m.from_user.id) == "awaiting_lang_file_upload")
def handle_lang_file_upload(message: Message):
    try:
        user_id = message.from_user.id
        if not message.document:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("send_json_file_only"), reply_markup=kb)

        if not message.document.file_name.endswith(".json"):
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_file_format"), reply_markup=kb)

        file_info = bot.get_file(message.document.file_id)
        file_path = file_info.file_path
        downloaded_file = bot.download_file(file_path)

        # اعتبارسنجی محتوای فایل JSON
        try:
            new_lang_data = json.loads(downloaded_file.decode("utf-8"))
            if not isinstance(new_lang_data, dict):
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("invalid_json_content"), reply_markup=kb)
        except json.JSONDecodeError:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_json_format"), reply_markup=kb)

        # ذخیره فایل موقت
        temp_file_path = os.path.join(DATA_DIR, "temp_lang.json")
        with open(temp_file_path, "wb") as f:
            f.write(downloaded_file)

        # بررسی نام فایل
        if message.document.file_name != "lang.json":
            user_states[user_id] = f"confirm_lang_file_name:{temp_file_path}"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
            safe_send_message(
                message.chat.id,
                get_lang("invalid_file_name").replace("{file_name}", message.document.file_name),
                reply_markup=kb
            )
            return

        user_states[user_id] = f"confirm_lang_replace:{temp_file_path}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("confirm_lang_replace"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_lang_file_upload error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(content_types=["text"], func=lambda m: user_states.get(m.from_user.id) == "awaiting_lang_file_upload")
def handle_lang_file_upload_text(message: Message):
    try:
        user_id = message.from_user.id

        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(
                message.chat.id,
                get_lang("cancelled"),
                reply_markup=get_settings_keyboard(user_id)
            )

        # اگر متن غیر از لغو فرستاد
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(message.chat.id, get_lang("send_json_file_only"), reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_lang_file_upload_text error: {e}")
        user_states.pop(message.from_user.id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(message.from_user.id))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id, "").startswith("confirm_lang_file_name:") or user_states.get(m.from_user.id, "").startswith("confirm_lang_replace:"))
def handle_lang_file_confirm(message: Message):
    try:
        user_id = message.from_user.id
        state = user_states[user_id]
        temp_file_path = state.split(":")[1]

        if message.text == get_lang("cancel_button"):
            if os.path.exists(temp_file_path):
                os.remove(temp_file_path)
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))

        if message.text == get_lang("confirm_button"):
            # تغییر نام فایل قدیمی به BAK_lang.json
            bak_file_path = os.path.join(DATA_DIR, "BAK_lang.json")
            if os.path.exists(LANG_FILE):
                os.rename(LANG_FILE, bak_file_path)

            # جایگزینی فایل جدید
            os.rename(temp_file_path, LANG_FILE)

            # به‌روزرسانی متغیر lang
            global lang
            lang = load_json(LANG_FILE, {})

            user_states.pop(user_id, None)
            safe_send_message(message.chat.id, get_lang("lang_file_updated"), reply_markup=get_settings_keyboard(user_id))
        else:
            safe_send_message(message.chat.id, get_lang("invalid_action"), reply_markup=get_settings_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_lang_file_confirm error: {e}")
        if os.path.exists(temp_file_path):
            os.remove(temp_file_path)
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("admin_user_list_button"))
def handle_admin_user_list(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return
        show_user_list_page(message.chat.id, 0)
    except Exception as e:
        logging.error(f"handle_admin_user_list error: {e}")

def show_user_list_page(chat_id, page):
    try:
        user_items = list(users.items())
        per_page = 10
        total_pages = (len(user_items) - 1) // per_page + 1
        start = page * per_page
        end = start + per_page

        markup = types.InlineKeyboardMarkup(row_width=2)
        for user_id, u in user_items[start:end]:
            name = f"{u.get('first_name', '')} @{u.get('username', '-')}"
            btn = types.InlineKeyboardButton(name, callback_data=f"user_info:{user_id}")
            markup.add(btn)

        nav_buttons = []
        if page > 0:
            nav_buttons.append(types.InlineKeyboardButton(get_lang("prev_page"), callback_data=f"user_page:{page-1}"))
        if end < len(user_items):
            nav_buttons.append(types.InlineKeyboardButton(get_lang("next_page"), callback_data=f"user_page:{page+1}"))
        if nav_buttons:
            markup.add(*nav_buttons)

        bot.send_message(chat_id, get_lang("user_list_page").replace("{page}", str(page+1)), reply_markup=markup)

    except Exception as e:
        logging.error(f"show_user_list_page error: {e}")
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("user_page:") or c.data == "user_list:0")
def handle_user_page(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return
        page = int(call.data.split(":")[1]) if call.data.startswith("user_page:") else 0
        bot.delete_message(call.message.chat.id, call.message.message_id)
        show_user_list_page(call.message.chat.id, page)
    except Exception as e:
        logging.error(f"handle_user_page error: {e}")
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("user_info:"))
def handle_user_info(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return
        user_id = call.data.split(":")[1]
        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:  # اگر کاربر 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)

        # پاسخ به کال‌بک (متن در lang.json قرار بگیرد)
        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')}"

            # بازسازى کیبورد تا دکمه‌های reply و warn حفظ شوند
            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

        # ارسال مستقیم با bot.* تا خطای "chat not found" لاگ اضافی نسازد و ارسال به بقیه ادامه یابد
        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

        # پاکسازی stateهای قبلی
        user_id = call.from_user.id
        user_states.pop(user_id, None)
        admin_reply_states.pop(user_id, None)

        add_product_states[user_id] = {"step": "title"}

        # فقط کیبورد لغو برای شروع
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))

        safe_send_message(call.message.chat.id, get_lang("add_product_title"), reply_markup=kb)
    except Exception as e:
        logging.error(f"start_add_product error: {e}")

@bot.message_handler(content_types=["text", "document"], func=lambda m: m.from_user.id in add_product_states)
def handle_add_product_steps(message: Message):
    try:
        user_id = message.from_user.id
        state = add_product_states.get(user_id, {})
        step = state.get("step")

        # اگر کاربر لغو زد
        if message.text == get_lang("cancel_button"):
            add_product_states.pop(user_id, None)
            return safe_send_message(
                message.chat.id,
                get_lang("cancelled"),
                reply_markup=get_main_keyboard(user_id)
            )

        currency = config["currency"]

        if step == "title":
            state["title"] = message.text
            state["step"] = "price"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            safe_send_message(message.chat.id, get_lang("add_product_price").replace("{currency}", currency), reply_markup=kb)

        elif step == "price":
            if not message.text.isdigit():
                return safe_send_message(message.chat.id, get_lang("invalid_price"))
            state["price"] = int(message.text)
            state["step"] = "description"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            safe_send_message(message.chat.id, get_lang("add_product_description"), reply_markup=kb)

        elif step == "description":
            state["description"] = message.text
            state["step"] = "delivery_type"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("delivery_file"), get_lang("delivery_link"))
            kb.row(get_lang("cancel_button"))
            safe_send_message(message.chat.id, get_lang("choose_delivery_type"), reply_markup=kb)

        elif step == "delivery_type":
            if message.text == get_lang("delivery_file"):
                state["step"] = "file_upload"
                state["file_ids"] = []
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("finish_upload_button"))
                kb.row(get_lang("cancel_button"))
                safe_send_message(message.chat.id, get_lang("send_product_files"), reply_markup=kb)

            elif message.text == get_lang("delivery_link"):
                state["step"] = "link_input"
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("cancel_button"))
                safe_send_message(message.chat.id, get_lang("send_product_link"), reply_markup=kb)

            else:
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("delivery_file"), get_lang("delivery_link"))
                kb.row(get_lang("cancel_button"))
                safe_send_message(message.chat.id, get_lang("choose_delivery_type"), reply_markup=kb)

        elif step == "file_upload":
            if message.text == get_lang("finish_upload_button"):
                file_ids = state.get("file_ids", [])
                if not file_ids:
                    return safe_send_message(message.chat.id, get_lang("no_file_uploaded_yet"))
                state["step"] = "final_confirm"
                kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
                kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
                return safe_send_message(message.chat.id, get_lang("confirm_add_product"), reply_markup=kb)

            if message.document:
                file_id = message.document.file_id
                state.setdefault("file_ids", []).append(file_id)
                logging.info(f"📎 فایل دریافت شد از کاربر {user_id}: {file_id}")
                return safe_send_message(message.chat.id, get_lang("file_received_next"))

            return safe_send_message(message.chat.id, get_lang("send_file_only"))

        elif step == "link_input":
            state["link"] = message.text
            state["step"] = "final_confirm"
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
            safe_send_message(message.chat.id, get_lang("confirm_add_product"), reply_markup=kb)

        elif step == "final_confirm":
            if message.text == get_lang("confirm_button"):
                pid = str(int(datetime.now().timestamp()))
                delivery = {"type": "link", "link": state["link"]} if "link" in state else {
                    "type": "file", "file_ids": state.get("file_ids", [])}
                products[pid] = {
                    "title": state["title"],
                    "price": state["price"],
                    "description": state["description"],
                    "delivery": delivery,
                    "is_active": True
                }
                save_json(PRODUCTS_FILE, products)

                group_id = config.get("transaction_group_id")
                if delivery["type"] == "file" and group_id:
                    for fid in delivery["file_ids"]:
                        try:
                            bot.send_document(group_id, fid, caption=state["title"])
                        except Exception as e:
                            logging.warning(f"Send file to group error: {e}")

                safe_send_message(message.chat.id, get_lang("product_added"), reply_markup=get_main_keyboard(user_id))
            else:
                safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

            add_product_states.pop(user_id, None)

    except Exception as e:
        logging.error(f"handle_add_product_steps error: {e}")
        add_product_states.pop(message.from_user.id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(message.from_user.id))
           
@bot.message_handler(func=lambda m: m.text == get_lang("admin_set_transaction_group"))
def handle_set_transaction_group(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return

        user_states[message.from_user.id] = "awaiting_transaction_group_id"

        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(
            message.chat.id,
            get_lang("send_group_id_instruction"),
            reply_markup=kb
        )
    except Exception as e:
        logging.error(f"handle_set_transaction_group error: {e}")

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_transaction_group_id")
def handle_group_id_input(message: Message):
    try:
        user_id = message.from_user.id
        admin_chat_id = user_id  # چت خصوصی ادمین

        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(admin_chat_id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))

        if message.chat.type in ["group", "supergroup"]:
            group_id = message.chat.id
            try:
                bot.get_chat(group_id)
                config["transaction_group_id"] = group_id
                save_json(CONFIG_FILE, config)
                user_states.pop(user_id, None)
                safe_send_message(
                    admin_chat_id,  # ارسال به چت خصوصی ادمین
                    get_lang("group_id_set_successfully").replace("{group_id}", str(group_id)),
                    reply_markup=get_settings_keyboard(user_id)
                )
            except Exception as e:
                logging.error(f"Invalid group ID {group_id}: {e}")
                safe_send_message(admin_chat_id, get_lang("invalid_group_id"))
            return

        if message.text and message.text.lstrip("-").isdigit():
            group_id = int(message.text)
            try:
                bot.get_chat(group_id)
                config["transaction_group_id"] = group_id
                save_json(CONFIG_FILE, config)
                user_states.pop(user_id, None)
                safe_send_message(
                    admin_chat_id,  # ارسال به چت خصوصی ادمین
                    get_lang("group_id_set_successfully").replace("{group_id}", str(group_id)),
                    reply_markup=get_settings_keyboard(user_id)
                )
            except Exception as e:
                logging.error(f"Invalid group ID {group_id}: {e}")
                safe_send_message(admin_chat_id, get_lang("invalid_group_id"))
            return

        safe_send_message(admin_chat_id, get_lang("invalid_group_id"))
    except Exception as e:
        logging.error(f"handle_group_id_input error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(admin_chat_id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))
        
@bot.message_handler(func=lambda m: m.text == get_lang("admin_manage_products"))
def handle_manage_products(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return

        markup = types.InlineKeyboardMarkup()
        per_page = 5
        product_list = list(products.items())
        page = 0
        end = min(len(product_list), per_page)
        currency = config["currency"]
        for pid, p in product_list[:end]:
            price_text = f"{p['price']} {currency}"
            markup.add(types.InlineKeyboardButton(f"{p['title']} - {price_text}", callback_data=f"delete_product:{pid}"))
        if len(product_list) > per_page:
            markup.add(types.InlineKeyboardButton(get_lang("next_page"), callback_data="product_page:1"))
        markup.add(types.InlineKeyboardButton(get_lang("add_product"), callback_data="start_add_product"))

        safe_send_message(message.chat.id, get_lang("manage_products_prompt"), reply_markup=markup)
    except Exception as e:
        logging.error(f"Manage products error: {e}")
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("product_page:"))
def handle_product_page_callback(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return

        _, page_str = call.data.split(":")
        page = int(page_str)
        per_page = 5
        product_list = list(products.items())
        start = page * per_page
        end = min(start + per_page, len(product_list))

        markup = types.InlineKeyboardMarkup()
        currency = config["currency"]
        for pid, p in product_list[start:end]:
            price_text = f"{p['price']} {currency}"
            markup.add(types.InlineKeyboardButton(f"{p['title']} - {price_text}", callback_data=f"delete_product:{pid}"))

        if start > 0:
            markup.add(types.InlineKeyboardButton(get_lang("prev_page"), callback_data=f"product_page:{page-1}"))
        if end < len(product_list):
            markup.add(types.InlineKeyboardButton(get_lang("next_page"), callback_data=f"product_page:{page+1}"))

        markup.add(types.InlineKeyboardButton(get_lang("add_product"), callback_data="start_add_product"))

        bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=markup)
    except Exception as e:
        logging.error(f"Product page callback error: {e}")
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("delete_product:"))
def handle_delete_product_callback(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return

        pid = call.data.split(":")[1]
        if pid in products:
            del products[pid]
            save_json(PRODUCTS_FILE, products)
            bot.answer_callback_query(call.id, get_lang("product_deleted"))
            bot.delete_message(call.message.chat.id, call.message.message_id)
            handle_manage_products(call.message)
        else:
            bot.answer_callback_query(call.id, get_lang("product_not_found"))
    except Exception as e:
        logging.error(f"Delete product callback error: {e}")

@bot.message_handler(func=lambda m: m.text == get_lang("wallet_button"))
def handle_wallet(message: Message):
    try:
        user_id = message.from_user.id
        not_joined_channels = check_channel_membership(user_id)
        sent_channels, keyboard = show_channel_buttons(message.chat.id, user_id, not_joined_channels)
        if sent_channels:
            return
        if is_banned(user_id):
            return safe_send_message(message.chat.id, get_lang("banned_message"), reply_markup=get_main_keyboard(user_id))

        if not config.get("wallet_enabled", True):
            return safe_send_message(message.chat.id, get_lang("wallet_disabled_message"), reply_markup=get_main_keyboard(user_id))

        user_data = users.get(str(user_id), {})
        balance = user_data.get("wallet_balance", 0)
        currency = config["currency"]

        text = get_lang("wallet_info").replace("{balance}", format_number(balance)).replace("{currency}", currency)
        markup = types.InlineKeyboardMarkup()
        markup.add(types.InlineKeyboardButton(get_lang("charge_wallet_button"), callback_data="charge_wallet"))

        safe_send_message(message.chat.id, text, parse_mode="HTML", reply_markup=markup)
    except Exception as e:
        logging.error(f"handle_wallet error: {e}")
        safe_send_message(message.chat.id, get_lang("error_occurred"), reply_markup=get_main_keyboard(user_id))
        
@bot.callback_query_handler(func=lambda c: c.data == "charge_wallet")
def handle_charge_wallet(call: CallbackQuery):
    try:
        if is_banned(call.from_user.id):
            bot.delete_message(call.message.chat.id, call.message.message_id)
            return safe_send_message(call.message.chat.id, get_lang("banned_message"))

        user_states[call.from_user.id] = "awaiting_charge_amount"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(call.message.chat.id, get_lang("enter_charge_amount"), reply_markup=kb)
        bot.delete_message(call.message.chat.id, call.message.message_id)
    except Exception as e:
        logging.error(f"handle_charge_wallet error: {e}")
        user_states.pop(call.from_user.id, None)
        safe_send_message(call.message.chat.id, get_lang("settings_update_failed"))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_charge_amount")
def handle_charge_amount(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

        if not message.text.isdigit() or int(message.text) <= 0:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_amount"), reply_markup=kb)

        amount = int(message.text)
        currency = config["currency"]
        user_states[user_id] = f"confirm_charge_amount:{amount}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
        text = get_lang("confirm_wallet_charge").replace("{amount}", format_number(amount)).replace("{currency}", currency)
        safe_send_message(message.chat.id, text, reply_markup=kb)
    except Exception as e:
        logging.error(f"handle_charge_amount error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: user_states.get(m.from_user.id, "").startswith("confirm_charge_amount:"))
def handle_confirm_charge(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

        if message.text != get_lang("confirm_button"):
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_action"), reply_markup=kb)

        amount = int(user_states[user_id].split(":")[1])
        user_states[user_id] = f"awaiting_charge_payment:{amount}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        card_info = config.get("card_info", "اطلاعات کارت تنظیم نشده")
        payment_message = f"{get_lang('send_payment_info')}\n\n{get_lang('card_info').replace('{card_info}', card_info)}"
        safe_send_message(message.chat.id, payment_message, reply_markup=kb, parse_mode="HTML")
    except Exception as e:
        logging.error(f"handle_confirm_charge error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("change_card_info_button"))
def handle_change_card_info(message: Message):
    try:
        user_id = message.from_user.id
        logging.info(f"User {user_id} clicked change_card_info_button")
        user_states[user_id] = "awaiting_card_info"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        card_info = config.get("card_info", get_lang("card_info_not_set"))
        text = get_lang("enter_card_info").replace("{card_info}", card_info)
        safe_send_message(message.chat.id, text, reply_markup=kb, parse_mode="HTML")
    except Exception as e:
        logging.error(f"handle_change_card_info error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))
        
@bot.message_handler(func=lambda m: user_states.get(m.from_user.id) == "awaiting_card_info")
def handle_card_info_input(message: Message):
    try:
        user_id = message.from_user.id
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))
        if not message.text:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("support_text_or_photo_only"), reply_markup=kb)
        config["card_info"] = message.text
        save_json(CONFIG_FILE, config)
        user_states.pop(user_id, None)
        text = get_lang("card_info_updated").replace("{card_info}", message.text)
        safe_send_message(message.chat.id, text, reply_markup=get_settings_keyboard(user_id), parse_mode="HTML")
    except Exception as e:
        logging.error(f"handle_card_info_input error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))
        
@bot.message_handler(content_types=["text", "photo"], func=lambda m: user_states.get(m.from_user.id, "").startswith("awaiting_charge_payment:"))
def handle_charge_payment(message: Message):
    try:
        user_id = message.from_user.id
        amount = int(user_states[user_id].split(":")[1])
        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

        group_id = config.get("transaction_group_id")
        if not group_id:
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("no_transaction_group"), reply_markup=get_main_keyboard(user_id))

        now = datetime.now()
        transaction_id = str(int(now.timestamp()))
        currency = config["currency"]
        transaction_data = {
            "user_id": user_id,
            "type": "wallet_charge",
            "amount": amount,
            "status": "pending",
            "time": now.isoformat()
        }

        if message.photo:
            transaction_data["photo"] = message.photo[-1].file_id
            transaction_data["caption"] = message.caption or ""
        else:
            transaction_data["text"] = message.text

        transactions[transaction_id] = transaction_data
        save_json(TRANSACTIONS_FILE, transactions)

        user_info = f"👤 <b>کاربر:</b> {message.from_user.first_name} (@{message.from_user.username or '-'})"
        transaction_info = f"💰 <b>شارژ کیف پول:</b> {format_number(amount)} {currency}\n#شارژ_کیف_پول"
        status_info = f"📌 <b>وضعیت:</b> در انتظار تأیید"

        markup = types.InlineKeyboardMarkup()
        markup.add(
            types.InlineKeyboardButton(get_lang("accept_transaction"), callback_data=f"accept_transaction:{transaction_id}"),
            types.InlineKeyboardButton(get_lang("reject_transaction"), callback_data=f"reject_transaction:{transaction_id}")
        )

        if "photo" in transaction_data:
            caption = (
                f"{get_lang('new_transaction')}\n"
                f"{user_info}\n"
                f"🆔 <code>{user_id}</code>\n"
                f"{transaction_info}\n"
                f"📝 <b>کپشن:</b> {transaction_data['caption']}\n"
                f"{status_info}"
            )
            safe_send_photo(group_id, transaction_data["photo"], caption=caption, parse_mode="HTML", reply_markup=markup)
        else:
            text = (
                f"{get_lang('new_transaction')}\n"
                f"{user_info}\n"
                f"🆔 <code>{user_id}</code>\n"
                f"{transaction_info}\n"
                f"📝 <b>متن:</b> {transaction_data['text']}\n"
                f"{status_info}"
            )
            safe_send_message(group_id, text, parse_mode="HTML", reply_markup=markup)

        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("wallet_charge_submitted"), reply_markup=get_main_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_charge_payment error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))

@bot.callback_query_handler(func=lambda c: c.data.startswith("set_wallet_balance:"))
def handle_set_wallet_balance(call: CallbackQuery):
    try:
        if not is_admin(call.from_user.id):
            return

        user_id = call.data.split(":")[1]
        user_states[call.from_user.id] = f"awaiting_wallet_balance:{user_id}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("cancel_button"))
        safe_send_message(call.message.chat.id, get_lang("enter_wallet_balance"), reply_markup=kb)
        bot.answer_callback_query(call.id)
    except Exception as e:
        logging.error(f"handle_set_wallet_balance error: {e}")
        user_states.pop(call.from_user.id, None)
        safe_send_message(call.message.chat.id, get_lang("settings_update_failed"))
        
@bot.message_handler(func=lambda m: user_states.get(m.from_user.id, "").startswith("awaiting_wallet_balance:"))
def handle_wallet_balance_input(message: Message):
    try:
        user_id = message.from_user.id
        target_user_id = user_states[user_id].split(":")[1]

        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_settings_keyboard(user_id))

        if not message.text.isdigit() or int(message.text) < 0:
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_amount"), reply_markup=kb)

        balance = int(message.text)
        currency = config["currency"]
        users[target_user_id]["wallet_balance"] = balance
        save_json(USERS_FILE, users)

        user_states.pop(user_id, None)
        text = get_lang("wallet_balance_updated").replace("{balance}", format_number(balance)).replace("{currency}", currency)
        safe_send_message(message.chat.id, text, reply_markup=get_settings_keyboard(user_id))
    except Exception as e:
        logging.error(f"handle_wallet_balance_input error: {e}")
        user_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_settings_keyboard(user_id))
        
@bot.callback_query_handler(func=lambda c: c.data.startswith("buy_with_wallet:"))
def handle_buy_with_wallet(call: CallbackQuery):
    try:
        if is_banned(call.from_user.id):
            bot.delete_message(call.message.chat.id, call.message.message_id)
            return safe_send_message(call.message.chat.id, get_lang("banned_message"))

        pid = call.data.split(":")[1]
        product = products.get(pid)
        if not product:
            bot.answer_callback_query(call.id, get_lang("product_not_found"))
            return

        user_id = str(call.from_user.id)
        user_data = users.get(user_id, {})
        balance = user_data.get("wallet_balance", 0)
        currency = config["currency"]

        if balance < product["price"]:
            text = get_lang("insufficient_balance").replace("{balance}", format_number(balance)).replace("{price}", format_number(product["price"])).replace("{currency}", currency)
            user_states.pop(user_id, None)
            add_product_states.pop(user_id, None)
            bot.delete_message(call.message.chat.id, call.message.message_id)
            return safe_send_message(call.message.chat.id, text, reply_markup=get_main_keyboard(user_id))

        user_states[call.from_user.id] = f"confirm_wallet_purchase:{pid}"
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
        text = get_lang("confirm_wallet_purchase").replace("{title}", product["title"]).replace("{price}", format_number(product["price"])).replace("{currency}", currency)
        safe_send_message(call.message.chat.id, text, reply_markup=kb)
        bot.delete_message(call.message.chat.id, call.message.message_id)
    except Exception as e:
        logging.error(f"handle_buy_with_wallet error: {e}")
        user_states.pop(call.from_user.id, None)
        add_product_states.pop(call.from_user.id, None)
        safe_send_message(call.message.chat.id, get_lang("settings_update_failed"))
        
@bot.message_handler(func=lambda m: user_states.get(m.from_user.id, "").startswith("confirm_wallet_purchase:"))
def handle_confirm_wallet_purchase(message: Message):
    try:
        user_id = message.from_user.id
        pid = user_states[user_id].split(":")[1]
        product = products.get(pid)
        if not product:
            user_states.pop(user_id, None)
            add_product_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("product_not_found"), reply_markup=get_main_keyboard(user_id))

        if message.text == get_lang("cancel_button"):
            user_states.pop(user_id, None)
            add_product_states.pop(user_id, None)
            return safe_send_message(message.chat.id, get_lang("cancelled"), reply_markup=get_main_keyboard(user_id))

        if message.text != get_lang("confirm_button"):
            kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
            kb.row(get_lang("confirm_button"), get_lang("cancel_button"))
            return safe_send_message(message.chat.id, get_lang("invalid_action"), reply_markup=kb)

        user_data = users.get(str(user_id), {})
        balance = user_data.get("wallet_balance", 0)
        currency = config["currency"]

        if balance < product["price"]:
            text = get_lang("insufficient_balance").replace("{balance}", format_number(balance)).replace("{price}", format_number(product["price"])).replace("{currency}", currency)
            user_states.pop(user_id, None)
            add_product_states.pop(user_id, None)
            return safe_send_message(message.chat.id, text, reply_markup=get_main_keyboard(user_id))

        users[str(user_id)]["wallet_balance"] = balance - product["price"]
        users[str(user_id)]["received_products"] = user_data.get("received_products", 0) + 1
        save_json(USERS_FILE, users)

        now = datetime.now()
        transaction_id = str(int(now.timestamp()))
        transactions[transaction_id] = {
            "user_id": user_id,
            "type": "wallet_purchase",
            "product_id": pid,
            "product_title": product["title"],
            "price": product["price"],
            "status": "accepted",
            "time": now.isoformat()
        }
        save_json(TRANSACTIONS_FILE, transactions)

        group_id = config.get("transaction_group_id")
        if group_id:
            user_info = f"👤 <b>کاربر:</b> {message.from_user.first_name} (@{message.from_user.username or '-'})"
            product_info = f"📦 <b>محصول:</b> {product['title']}\n💰 <b>قیمت:</b> {format_number(product['price'])} {currency}\n#خرید_محصول"
            status_info = f"📌 <b>وضعیت:</b> تأیید شده (پرداخت با کیف پول)"
            text = f"{get_lang('new_transaction')}\n{user_info}\n🆔 <code>{user_id}</code>\n{product_info}\n{status_info}"
            markup = types.InlineKeyboardMarkup()
            markup.add(types.InlineKeyboardButton(get_lang("transaction_accepted"), callback_data="no_action"))
            safe_send_message(group_id, text, parse_mode="HTML", reply_markup=markup)

        product_details = (
            f"🎉 <b>تراکنش شما برای محصول {product['title']} تأیید شد!</b>\n"
            f"📦 <b>عنوان محصول:</b> {product['title']}\n"
            f"📝 <b>توضیحات:</b> {product['description']}\n"
            f"🚚 <b>تحویل:</b> {'فایل' if product['delivery']['type'] == 'file' else 'لینک'}"
        )
        safe_send_message(user_id, product_details, parse_mode="HTML")

        if product["delivery"]["type"] == "file":
            for file_id in product["delivery"]["file_ids"]:
                safe_send_document(user_id, file_id, caption=f"📄 فایل محصول: {product['title']}", parse_mode="HTML")
        elif product["delivery"]["type"] == "link":
            safe_send_message(user_id, f"🔗 لینک محصول: {product['delivery']['link']}", parse_mode="HTML")

        text = get_lang("wallet_purchase_success").replace("{title}", product["title"]).replace("{balance}", format_number(users[str(user_id)]["wallet_balance"])).replace("{currency}", currency)
        safe_send_message(user_id, text, reply_markup=get_main_keyboard(user_id))
        user_states.pop(user_id, None)
        add_product_states.pop(user_id, None)
    except Exception as e:
        logging.error(f"handle_confirm_wallet_purchase error: {e}")
        user_states.pop(user_id, None)
        add_product_states.pop(user_id, None)
        safe_send_message(message.chat.id, get_lang("settings_update_failed"), reply_markup=get_main_keyboard(user_id))

@bot.message_handler(func=lambda m: m.text == get_lang("admin_statistics"))
def handle_statistics(message: Message):
    try:
        if not is_admin(message.from_user.id):
            return
        total_users = len(users)
        total_products = len(products)
        total_tx = len(transactions)
        accepted_tx = sum(1 for t in transactions.values() if t.get("status") == "accepted")
        total_income = sum(t.get("price", 0) for t in transactions.values() if t.get("status") == "accepted")
        currency = config["currency"]
        stats = (
            f"👥 کاربران: {total_users}\n"
            f"📦 محصولات: {total_products}\n"
            f"🧾 کل خریدها: {total_tx}\n"
            f"✅ خریدهای تأییدشده: {accepted_tx}\n"
            f"💰 مجموع فروش: {total_income} {currency}"
        )
        safe_send_message(message.chat.id, stats)
    except Exception as e:
        logging.error(f"Statistics handler error: {e}")
        
@bot.message_handler(func=lambda m: m.text == get_lang("store_button"))
def handle_store(message: Message):
    try:
        user_id = message.from_user.id
        not_joined_channels = check_channel_membership(user_id)
        sent_channels, keyboard = show_channel_buttons(message.chat.id, user_id, not_joined_channels)
        if sent_channels:
            return
        if is_banned(user_id):
            return safe_send_message(message.chat.id, get_lang("banned_message"), reply_markup=get_main_keyboard(user_id))

        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']}"  # اصلاح callback
                    ))
        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"))
            # return safe_send_message(call.message.chat.id, get_lang("discount_out_of_stock_popup"), reply_markup=get_main_keyboard(user_id))

        text = (
            f"🎟 <b>{discount['title']}</b>\n"
            f"💰 قیمت: {format_number(price)} {currency}\n"
            # f"🔄 خریدهای شما: {user_purchases} از {purchase_limit}\n"
            # f"🔄 تعداد باقی‌مانده برای خرید: {remaining_purchases}\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']}"  # اصلاح callback
                    ))
        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

                # انتقال خط و کدها به sold_lines و sold_codes
                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
                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()
