import telebot
from telebot import types

try:
    from telebot.apihelper import ApiTelegramException
except ImportError:
    ApiTelegramException = Exception  # type: ignore

from datetime import datetime
import logging
import json
import os
import time

# تنظیمات لاگ گیری
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

# FileHandler برای ذخیره در فایل
file_handler = logging.FileHandler('bot.log', encoding='utf-8')
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))

# StreamHandler برای نمایش در ترمینال
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
stream_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))

logger.addHandler(file_handler)
logger.addHandler(stream_handler)

# ===== تنظیمات اصلی =====
# روی سرور حتماً BOT_TOKEN (و در صورت نیاز ADMIN_CHAT_ID) را با environment بدهید؛ مقدار پیش‌فرض فقط برای توسعهٔ لوکال است.
TOKEN = os.environ.get(
    "BOT_TOKEN",
    "8223803258:AAEO_0m4YyaOg6o8X5WlqabmVFz-yWyLC2I",
)
try:
    ADMIN_CHAT_ID = int(os.environ.get("ADMIN_CHAT_ID", "389601939"))
except ValueError:
    ADMIN_CHAT_ID = 389601939

CARD_NUMBER = "6219861916521064"
CARD_NAME = "بابادی"
SHEBA_NUMBER = "IR830560611828005292422201"
MONTHLY_PRICE = 5_000_000
# =======================

bot = telebot.TeleBot(TOKEN)

# ذخیره کاربران و وضعیت‌ها
waiting_for_name = set()
waiting_for_receipt = set()  # کاربران در انتظار دریافت رسید
waiting_for_rules_confirm = set()  # کاربران در انتظار تأیید قوانین
user_names = {} # user_id : "Firstname Lastname"
user_phone_numbers = {} # user_id : "09xxxxxxxxx"
user_orders = {} # user_id : {"months": 3, "total_price": 4500000}
user_orders_history = {} # user_id : [{"months": 3, "total_price": 4500000, "date": "..."}]
received_receipts = set() # message_id ها برای بررسی رسید تکراری
admin_messages_map = {} # admin_msg_id : user_id (برای پاسخ ادمین)
admin_send_state = {} # admin_id : {"step": "waiting_id" or "waiting_message", "user_id": user_id}
admin_in_customer_mode = set() # ادمین‌هایی که در حالت کاربر هستند
registered_users = set() # تمام کاربرانی که ربات را شروع کردند
broadcast_state = {} # admin_id : "waiting_message" (برای broadcast)

# فاصلهٔ کوتاه بین ارسال همگانی برای کاهش FloodWait تلگرام
BROADCAST_DELAY_SEC = 0.04

ADMIN_COMPOSE_CONTENT_TYPES = [
    "text", "photo", "document", "video", "animation", "video_note",
    "voice", "audio", "sticker",
]


def clear_admin_send_state():
    admin_send_state.pop(ADMIN_CHAT_ID, None)


def clear_broadcast_state():
    broadcast_state.pop(ADMIN_CHAT_ID, None)


def clear_all_admin_compose_states():
    """هنگام تعویض حالت ارسال تکی / همگانی یا لغو، stateها تداخل نکنند."""
    clear_admin_send_state()
    clear_broadcast_state()


def send_admin_media_to_user(user_id, message):
    """ارسال محتوای پیام ادمین به یک کاربر؛ در خطا فوروارد به‌عنوان پشتیبان."""
    chat = message.chat.id
    mid = message.message_id
    if message.photo:
        try:
            bot.send_photo(user_id, message.photo[-1].file_id, caption=message.caption)
        except Exception:
            bot.forward_message(user_id, chat, mid)
    elif message.document:
        try:
            bot.send_document(user_id, message.document.file_id, caption=message.caption)
        except Exception:
            bot.forward_message(user_id, chat, mid)
    elif message.video:
        try:
            bot.send_video(user_id, message.video.file_id, caption=message.caption)
        except Exception:
            bot.forward_message(user_id, chat, mid)
    elif message.animation:
        try:
            bot.send_animation(user_id, message.animation.file_id, caption=message.caption)
        except Exception:
            bot.forward_message(user_id, chat, mid)
    elif message.video_note:
        try:
            bot.send_video_note(user_id, message.video_note.file_id)
        except Exception:
            bot.forward_message(user_id, chat, mid)
    elif message.voice:
        try:
            bot.send_voice(user_id, message.voice.file_id, caption=message.caption)
        except Exception:
            bot.forward_message(user_id, chat, mid)
    elif message.audio:
        try:
            bot.send_audio(user_id, message.audio.file_id, caption=message.caption)
        except Exception:
            bot.forward_message(user_id, chat, mid)
    elif message.sticker:
        try:
            bot.send_sticker(user_id, message.sticker.file_id)
        except Exception:
            bot.forward_message(user_id, chat, mid)
    elif message.text is not None:
        bot.send_message(user_id, message.text)
    else:
        bot.forward_message(user_id, chat, mid)


def _sleep_retry_after(exc):
    try:
        params = getattr(exc, "result_json", None) or {}
        retry = (params.get("parameters") or {}).get("retry_after", 2)
        time.sleep(min(int(retry) + 1, 60))
    except Exception:
        time.sleep(2)


def broadcast_message_to_all(message):
    """ارسال پیام به همهٔ registered_users با تأخیر کوتاه و مدیریت FloodWait."""
    targets = sorted(registered_users)
    sent_count = 0
    failed_count = 0
    for user_id in targets:
        delivered = False
        counted_failure = False
        for _attempt in range(12):
            try:
                send_admin_media_to_user(user_id, message)
                sent_count += 1
                delivered = True
                break
            except ApiTelegramException as e:
                if getattr(e, "error_code", None) == 429:
                    _sleep_retry_after(e)
                    continue
                failed_count += 1
                counted_failure = True
                logger.warning(f"Broadcast failed user {user_id}: {e}")
                break
            except Exception as e:
                failed_count += 1
                counted_failure = True
                logger.warning(f"Broadcast failed user {user_id}: {e}")
                break
        if not delivered and not counted_failure:
            failed_count += 1
            logger.warning(f"Broadcast: give up after FloodWait retries for user {user_id}")
        time.sleep(BROADCAST_DELAY_SEC)
    return sent_count, failed_count


def is_waiting_receipt_message(message):
    """فقط وقتی کاربر در حالت ارسال رسید است این هندلر فعال شود (قبل از منوی متنی)."""
    uid = message.from_user.id
    if uid == ADMIN_CHAT_ID:
        return False
    return uid in waiting_for_receipt


# پیام هشدار بعد از انتخاب پلن
warning_message = (
"⚠️ کانفیگ‌های ارسال شده در فایل فقط و فقط روی 1 تلفن همراه قابل اجرا هستند "
"و در صورت انتقال اکانت شما بصورت خودکار مسدود و غیر قابل بازگشت خواهد بود.\n\n"
"🚨 پس حتماً اکانت رو به اشخاص مورد اطمینانتان بدهید.\n\n"
"✅ کانفیگ‌ها اختصاصی برای شما ساخته شده و فقط آیپی 1 دیوایس روی آن‌ها ثبت می‌شود "
"(پس روی دیوایس دیگری حتی امتحان هم نکنید، مسدود می‌شود).\n\n"
"✅ بعد از اتصال، یکی یکی کانفیگ‌ها را چک کنید کدومشون وصل می‌شود.\n"
"✅ اگر کانفیگی متصل نشد پاک نکنید، آن سرور اصلاح و مجدد بازسازی می‌شود.\n"
"✅ تیم ما مرتبا در حال به روزرسانی سرورها برای اتصال پایدار شماست.\n"
"✅ لطفا در زمانی که نیاز ندارید کانفیگ را قطع کنید تا همه پایدار بمانند.\n"
"🌱 از اینترنت آزاد لذت ببرید.\n"
"🫂 اگر رضایت داشتید مارو به دوستاتون معرفی کنید 🙏"
)

# پیام راهنمای خرید از وبسایت (بعد از هر دکمه/استارت؛ HTML برای بولد)
WEBSITE_PURCHASE_NOTICE_HTML = (
    "🌐 <b>لطفا برای خرید فقط و فقط از طریق وبسایت اقدام نمایید:</b>\n\n"
    "<b>https://netclubvip.org</b>\n\n"
    "⚠️ <b>مهم:</b> <b>هنگام ورود به سایت لطفاً VPN / پراکسی را حتما خاموش کنید تا خرید بدون مشکل انجام شود.</b>"
)


def send_website_purchase_notice(chat_id):
    try:
        bot.send_message(chat_id, WEBSITE_PURCHASE_NOTICE_HTML, parse_mode="HTML")
    except Exception as e:
        logger.error(f"send_website_purchase_notice failed: {e}")


def is_customer_side(user_id):
    """کاربر عادی یا ادمینی که عمداً حالت مشتری را زده."""
    return user_id != ADMIN_CHAT_ID or user_id in admin_in_customer_mode


def customer_full_menu_markup(chat_id):
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    btn1 = types.KeyboardButton("💳 خرید پلن")
    btn2 = types.KeyboardButton("📖 راهنما")
    btn3 = types.KeyboardButton("👨‍💼 پشتیبانی")
    btn4 = types.KeyboardButton("⚖️ قوانین")
    btn5 = types.KeyboardButton("📦 سفارش‌های من")
    btn_phone = types.KeyboardButton("📱 ثبت نام شماره موبایل", request_contact=True)
    btn_home = types.KeyboardButton("🏠 صفحه اصلی")
    btn_reset = types.KeyboardButton("🏁 شروع از نو")
    markup.add(btn1, btn2, btn3, btn4, btn5)
    markup.add(btn_phone)
    markup.add(btn_home, btn_reset)
    if chat_id in admin_in_customer_mode:
        markup.add(types.KeyboardButton("🔄 Back to Admin Mode"))
    return markup


def send_customer_primary_message(chat_id, user_id):
    """
    برای کاربران: فقط یک پیام (راهنمای وبسایت) + همان منوی کامل ریپلای
    (قبل و بعد از ثبت موبایل یکسان؛ بعد از اشتراک شماره، منوی بعد همان است).
    """
    try:
        bot.send_message(
            chat_id,
            WEBSITE_PURCHASE_NOTICE_HTML,
            reply_markup=customer_full_menu_markup(chat_id),
            parse_mode="HTML",
        )
    except Exception as e:
        logger.error(f"send_customer_primary_message failed: {e}")


# متن قوانین
rules_text = (
"📜 قوانین و حریم خصوصی\n\n"
"━━━━━━━━━━━━━━━━━\n\n"
"🔹 خدمات:\n"
"سرویس جهت امنیت و حفظ حریم خصوصی ارائه می‌شود. کاربر مسئولیت کامل فعالیت‌های خود را بر عهده دارد.\n\n"
"🔹 سقف مصرف منصفانه:\n"
"پهنای باند: ۱۰۰ گیگابایت در ماه.\n"
"محدودیت دستگاه: حداکثر 1 دستگاه. در صورت اتصال بیش از 1 دستگاه، سرویس تعلیق خواهد شد.\n\n"
"🔹 فعالیت‌های ممنوع:\n"
"تورنت، هک، اسپم، فعالیت‌های غیرقانونی و محتوای غیراخلاقی.\n\n"
"🔹 پرداخت:\n"
"کلیه خریدها قطعی است و امکان بازپرداخت وجود ندارد.\n\n"
"🔹 حریم خصوصی:\n"
"سیاست اکید عدم ثبت لاگ. رمزگذاری AES-256. اطلاعات شما هرگز فروخته نمی‌شود.\n\n"
"━━━━━━━━━━━━━━━━━\n\n"
"⚠️ با استفاده از این سرویس، تمامی قوانین فوق را می‌پذیرید."
)

# ---------- فانکشن‌های ذخیره‌سازی دیتابیس ----------
DB_FILE = "bot_database.json"

def save_database():
    """ذخیره تمام داده‌ها در فایل JSON"""
    try:
        # تبدیل sets به lists و user_ids به strings برای JSON compatibility
        data = {
            "user_names": {str(uid): name for uid, name in user_names.items()},
            "user_phone_numbers": {str(uid): phone for uid, phone in user_phone_numbers.items()},
            "user_orders": {str(uid): order for uid, order in user_orders.items()},
            "user_orders_history": {str(uid): history for uid, history in user_orders_history.items()},
            "registered_users": list(registered_users),
            "waiting_for_name": list(waiting_for_name),
            "waiting_for_receipt": list(waiting_for_receipt),
            "waiting_for_rules_confirm": list(waiting_for_rules_confirm),
        }
        with open(DB_FILE, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        logger.info(f"Database saved: {len(registered_users)} users, {len(user_names)} names registered")
    except Exception as e:
        logger.error(f"Error saving database: {str(e)}")

def load_database():
    """بارگذاری داده‌ها از فایل JSON"""
    try:
        if os.path.exists(DB_FILE):
            with open(DB_FILE, 'r', encoding='utf-8') as f:
                data = json.load(f)
            
            # بارگذاری Dictionaries - تبدیل string keys به integers
            for str_uid, value in data.get("user_names", {}).items():
                user_names[int(str_uid)] = value
            
            for str_uid, value in data.get("user_phone_numbers", {}).items():
                user_phone_numbers[int(str_uid)] = value
            
            for str_uid, value in data.get("user_orders", {}).items():
                user_orders[int(str_uid)] = value
            
            for str_uid, value in data.get("user_orders_history", {}).items():
                user_orders_history[int(str_uid)] = value
            
            # بارگذاری Sets
            for user_id in data.get("registered_users", []):
                registered_users.add(int(user_id) if isinstance(user_id, str) else user_id)
            
            for user_id in data.get("waiting_for_name", []):
                waiting_for_name.add(int(user_id) if isinstance(user_id, str) else user_id)
            
            for user_id in data.get("waiting_for_receipt", []):
                waiting_for_receipt.add(int(user_id) if isinstance(user_id, str) else user_id)
            
            for user_id in data.get("waiting_for_rules_confirm", []):
                waiting_for_rules_confirm.add(int(user_id) if isinstance(user_id, str) else user_id)
            
            logger.info(f"Database loaded: {len(registered_users)} users, {len(user_names)} names, {len(user_phone_numbers)} phones")
        else:
            logger.info("Database file does not exist. Starting with empty database")
    except Exception as e:
        logger.error(f"Error loading database: {str(e)}")


# ---------- بررسی ثبت‌نام موبایل ----------
def check_phone_registered(user_id):
    """بررسی اینکه کاربر شماره موبایل را ثبت‌نام کرده یا نه"""
    return user_id in user_phone_numbers

# ---------- صفحه اولیه — پیام وبسایت + منوی کامل (شماره از دکمهٔ «ثبت نام شماره موبایل») ----------
def welcome_phone_registration(chat_id):
    send_customer_primary_message(chat_id, chat_id)

# ---------- منوی اصلی (کاربر: فقط پیام وبسایت + کیبورد) ----------
def main_menu(chat_id):
    if chat_id == ADMIN_CHAT_ID and chat_id not in admin_in_customer_mode:
        return
    send_customer_primary_message(chat_id, chat_id)

# ---------- منوی ادمین ----------
def admin_menu(chat_id):
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    btn1 = types.KeyboardButton("📨 Send Message")
    btn2 = types.KeyboardButton("👥 User Stats")
    btn3 = types.KeyboardButton("📊 Order Stats")
    btn4 = types.KeyboardButton("📢 Broadcast Message")
    btn5 = types.KeyboardButton("🔄 Switch to Customer Mode")
    markup.add(btn1, btn2)
    markup.add(btn3, btn4)
    markup.add(btn5)
    bot.send_message(chat_id, "👨‍💼 Admin Panel - Select an option:", reply_markup=markup)
    send_website_purchase_notice(chat_id)

# ---------- start ----------
@bot.message_handler(commands=['start'])
def start(message):
    user_id = message.from_user.id
    # ثبت کاربر
    registered_users.add(user_id)
    logger.info(f"User {user_id} started the bot. Total users: {len(registered_users)}")
    save_database()
    
    if user_id == ADMIN_CHAT_ID:
        clear_all_admin_compose_states()
        # Admin menu
        bot.send_message(
            message.chat.id,
            "👨‍💼 Welcome Admin!\n\n"
            "دستورات:\n"
            "/send — ارسال پیام به یک کاربر\n"
            "/admin — پنل ادمین\n"
            "/cancel — لغو حالت ارسال تکی یا همگانی",
        )
        admin_menu(message.chat.id)
    else:
        # کاربر: فقط پیام وبسایت + کیبورد مناسب (بدون متن اضافه)
        send_customer_primary_message(message.chat.id, user_id)

# ---------- ارسال پیام مستقیم از ادمین ----------
@bot.message_handler(
    content_types=ADMIN_COMPOSE_CONTENT_TYPES,
    func=lambda message: message.chat.id == ADMIN_CHAT_ID and ADMIN_CHAT_ID in admin_send_state,
)
def admin_send_handler(message):
    state = admin_send_state.get(ADMIN_CHAT_ID)
    if not state:
        return

    if state["step"] == "waiting_id":
        if message.text:
            raw = message.text.strip()
            if raw == "/cancel":
                clear_admin_send_state()
                bot.send_message(ADMIN_CHAT_ID, "✅ ارسال پیام تکی لغو شد.")
                admin_menu(ADMIN_CHAT_ID)
                return
            try:
                user_id = int(raw)
                admin_send_state[ADMIN_CHAT_ID] = {"step": "waiting_message", "user_id": user_id}
                bot.send_message(
                    ADMIN_CHAT_ID,
                    f"✅ آیدی کاربر ذخیره شد: <code>{user_id}</code>\n\n"
                    "۲️⃣ حالا پیام، عکس، فایل یا ویدیو را بفرستید.\n"
                    "برای لغو: /cancel",
                    parse_mode="HTML",
                )
                logger.info(f"Admin send: target user_id={user_id}")
            except ValueError:
                bot.send_message(
                    ADMIN_CHAT_ID,
                    "❌ شناسهٔ نامعتبر. فقط یک عدد (مثل 123456789) بفرستید یا /cancel",
                )
        else:
            bot.send_message(
                ADMIN_CHAT_ID,
                "❌ در این مرحله فقط «شناسهٔ عددی کاربر» را به‌صورت متن بفرستید (یا /cancel).",
            )
        return

    if state["step"] == "waiting_message":
        user_id = state["user_id"]
        if message.text and message.text.strip() == "/cancel":
            clear_admin_send_state()
            bot.send_message(ADMIN_CHAT_ID, "✅ ارسال پیام تکی لغو شد.")
            admin_menu(ADMIN_CHAT_ID)
            return
        try:
            send_admin_media_to_user(user_id, message)
            bot.send_message(ADMIN_CHAT_ID, f"✅ پیام به کاربر <code>{user_id}</code> ارسال شد.", parse_mode="HTML")
            logger.info(f"Message sent to user {user_id}")
            clear_admin_send_state()
            admin_menu(ADMIN_CHAT_ID)
        except Exception as e:
            bot.send_message(ADMIN_CHAT_ID, f"❌ خطا در ارسال: {str(e)}\nدوباره تلاش کنید یا /cancel")
            logger.error(f"Error sending message to user {user_id}: {str(e)}")


# ---------- Broadcast Message Handler ----------
@bot.message_handler(
    content_types=ADMIN_COMPOSE_CONTENT_TYPES,
    func=lambda message: message.chat.id == ADMIN_CHAT_ID and ADMIN_CHAT_ID in broadcast_state,
)
def broadcast_handler(message):
    admin_id = ADMIN_CHAT_ID
    if broadcast_state.get(admin_id) != "waiting_message":
        return

    if message.text and message.text.strip() == "/cancel":
        clear_broadcast_state()
        bot.send_message(admin_id, "✅ حالت پیام همگانی لغو شد.")
        admin_menu(admin_id)
        return

    total = len(registered_users)
    bot.send_message(admin_id, f"⏳ در حال ارسال به {total} کاربر… لطفاً صبر کنید.")
    sent_count, failed_count = broadcast_message_to_all(message)

    bot.send_message(
        admin_id,
        f"✅ پایان همگانی\n\n"
        f"📤 موفق: {sent_count}\n"
        f"❌ ناموفق: {failed_count}\n"
        f"👥 هدف (ثبت‌شده در ربات): {total}",
    )
    logger.info(f"Broadcast done: sent={sent_count}, failed={failed_count}, total={total}")

    clear_broadcast_state()
    admin_menu(admin_id)


# ---------- دریافت رسید (قبل از منوی متنی تا متن رسید به‌اشتباه منو نشود) ----------
@bot.message_handler(
    content_types=["photo", "document", "video", "text"],
    func=is_waiting_receipt_message,
)
def receive_receipt(message):
    user_id = message.from_user.id

    message_id = message.message_id

    if message_id in received_receipts:
        send_customer_primary_message(message.chat.id, user_id)
        return

    received_receipts.add(message_id)
    waiting_for_receipt.remove(user_id)
    waiting_for_name.add(user_id)

    try:
        forwarded_msg = bot.forward_message(ADMIN_CHAT_ID, message.chat.id, message.message_id)
        admin_messages_map[forwarded_msg.message_id] = user_id

        name = user_names.get(user_id, "نام ثبت نشده")
        user_info_text = f"<b>آیدی کاربر:</b>\n<code>{user_id}</code>\n\n<b>نام:</b> {name}"

        info_msg = bot.send_message(
            ADMIN_CHAT_ID,
            user_info_text,
            reply_to_message_id=forwarded_msg.message_id,
            parse_mode="HTML",
        )
        admin_messages_map[info_msg.message_id] = user_id

        logger.info(f"Receipt from user {user_id} sent to admin (message_id: {forwarded_msg.message_id})")
    except Exception as e:
        logger.warning(f"Error forwarding receipt to admin for user {user_id}: {str(e)}")

    send_customer_primary_message(message.chat.id, user_id)


# ---------- لغو حالت ارسال / همگانی ----------
@bot.message_handler(commands=["cancel"], func=lambda m: m.from_user.id == ADMIN_CHAT_ID)
def admin_cancel_compose(m):
    if ADMIN_CHAT_ID not in admin_send_state and ADMIN_CHAT_ID not in broadcast_state:
        bot.send_message(ADMIN_CHAT_ID, "ℹ️ حالت ارسال تکی یا همگانی فعال نیست.")
        return
    clear_all_admin_compose_states()
    bot.send_message(ADMIN_CHAT_ID, "✅ لغو شد.")
    admin_menu(ADMIN_CHAT_ID)


# ---------- دریافت پاسخ ادمین (ریپلای روی پیام کاربر) — قبل از منوی ادمین تا با «متن تصادفی» قاطی نشود ----------
@bot.message_handler(
    func=lambda message: message.chat.id == ADMIN_CHAT_ID
    and message.reply_to_message
    and message.from_user.id == ADMIN_CHAT_ID
    and ADMIN_CHAT_ID not in admin_send_state
    and ADMIN_CHAT_ID not in broadcast_state,
)
def admin_reply(message):
    try:
        replied_to_msg_id = message.reply_to_message.message_id
        logger.info(
            f"Admin reply detected: replied_to_msg_id={replied_to_msg_id}, "
            f"admin_messages_map keys sample={list(admin_messages_map.keys())[:20]}"
        )

        if replied_to_msg_id in admin_messages_map:
            user_id = admin_messages_map[replied_to_msg_id]
            logger.info(f"Admin reply received for user {user_id}")

            try:
                send_admin_media_to_user(user_id, message)
                logger.info(f"Reply sent to user {user_id}")
                bot.send_message(ADMIN_CHAT_ID, "✅ پیام برای کاربر ارسال شد")
            except Exception as e:
                logger.error(f"Error sending reply to user {user_id}: {str(e)}")
                bot.send_message(ADMIN_CHAT_ID, f"❌ خطا در ارسال پیام برای کاربر: {str(e)}")
        else:
            logger.warning(f"Reply not in admin_messages_map: replied_to_msg_id={replied_to_msg_id}")
            bot.send_message(ADMIN_CHAT_ID, "⚠️ این ریپلای روی پیام ثبت‌شده‌ای در نقشهٔ ربات نیست (ریپلای را روی پیام فورواردشده/اطلاعات کاربر بزنید).")
    except Exception as e:
        logger.error(f"Error in admin reply handling: {str(e)}")


# ---------- مدیریت منو ----------
@bot.message_handler(
    content_types=["text"],
    func=lambda message: message.from_user.id != ADMIN_CHAT_ID
    or (
        message.from_user.id in admin_in_customer_mode
        and ADMIN_CHAT_ID not in admin_send_state
        and ADMIN_CHAT_ID not in broadcast_state
    ),
)
def menu(message):
    user_id = message.from_user.id
    text = (message.text or "").strip()

    if user_id == ADMIN_CHAT_ID and user_id in admin_in_customer_mode and text == "🔄 Back to Admin Mode":
        admin_in_customer_mode.remove(user_id)
        bot.send_message(ADMIN_CHAT_ID, "✅ Returned to admin mode")
        admin_menu(ADMIN_CHAT_ID)
        return

    if not is_customer_side(user_id):
        return

    if user_id in waiting_for_name and text:
        if user_id not in registered_users:
            registered_users.add(user_id)
            logger.info(f"User {user_id} registered (via name submission)")
        user_names[user_id] = text
        waiting_for_name.discard(user_id)
        save_database()
        try:
            name_msg = (
                f"👤 نام و فامیل کاربر:\n<code>{user_names[user_id]}</code>\n\n"
                f"کاربر ID (برای کپی کلیک کنید):\n<code>{user_id}</code>"
            )
            forwarded_msg = bot.send_message(ADMIN_CHAT_ID, name_msg, parse_mode="HTML")
            admin_messages_map[forwarded_msg.message_id] = user_id
            logger.info(f"User name {user_id} sent to admin (msg_id: {forwarded_msg.message_id})")
        except Exception as e:
            logger.warning(f"Error sending name to admin: {str(e)}")
        if user_id in user_orders:
            order = user_orders[user_id]
            save_order_history(user_id, order["months"], order["total_price"])
        send_customer_primary_message(message.chat.id, user_id)
        return

    if text == "🏁 شروع از نو":
        if user_id in waiting_for_receipt:
            waiting_for_receipt.discard(user_id)
        if user_id in waiting_for_name:
            waiting_for_name.discard(user_id)
        if user_id in user_orders:
            del user_orders[user_id]
        waiting_for_rules_confirm.discard(user_id)
        save_database()

    send_customer_primary_message(message.chat.id, user_id)

# ---------- منوی ادمین ----------
@bot.message_handler(
    content_types=["text"],
    func=lambda message: message.from_user.id == ADMIN_CHAT_ID
    and ADMIN_CHAT_ID not in admin_send_state
    and ADMIN_CHAT_ID not in broadcast_state
    and not message.reply_to_message,
)
def admin_menu_handler(message):
    text = (message.text or "").strip()
    logger.info(f"Admin menu handler - text: '{text}'")
    
    if text == "📨 Send Message":
        clear_broadcast_state()
        admin_send_state[ADMIN_CHAT_ID] = {"step": "waiting_id"}
        bot.send_message(
            ADMIN_CHAT_ID,
            "📨 ارسال پیام به یک کاربر\n\n"
            "۱️⃣ شناسهٔ عددی کاربر را بفرستید.\n"
            "برای لغو در هر مرحله: /cancel",
        )
        send_website_purchase_notice(ADMIN_CHAT_ID)
    
    elif text == "👥 User Stats":
        total_users = len(user_names)
        pending_names = len(waiting_for_name)
        bot.send_message(ADMIN_CHAT_ID, f"👥 User Statistics\n\nTotal registered users: {total_users}\nWaiting for names: {pending_names}")
        send_website_purchase_notice(ADMIN_CHAT_ID)
    
    elif text == "📊 Order Stats":
        total_orders = sum(len(orders) for orders in user_orders_history.values())
        total_revenue = sum(order['total_price'] for orders in user_orders_history.values() for order in orders)
        bot.send_message(ADMIN_CHAT_ID, f"📊 Order Statistics\n\nTotal orders: {total_orders}\nTotal revenue: {total_revenue:,} تومان")
        send_website_purchase_notice(ADMIN_CHAT_ID)
    
    elif text == "📢 Broadcast Message":
        clear_admin_send_state()
        broadcast_state[ADMIN_CHAT_ID] = "waiting_message"
        bot.send_message(
            ADMIN_CHAT_ID,
            f"📢 پیام همگانی\n\n"
            f"👥 تعداد کاربران ثبت‌شده: {len(registered_users)}\n\n"
            "💬 پیام، عکس، فایل یا ویدیو را بفرستید.\n"
            "برای لغو: /cancel",
        )
        logger.info("Broadcast mode activated for admin")
        send_website_purchase_notice(ADMIN_CHAT_ID)
    
    elif text == "🔄 Switch to Customer Mode":
        admin_in_customer_mode.add(ADMIN_CHAT_ID)
        bot.send_message(ADMIN_CHAT_ID, "Switched to customer mode. Use /admin to return to admin mode")
        main_menu(ADMIN_CHAT_ID)
    
    else:
        bot.send_message(ADMIN_CHAT_ID, "❓ Unknown command. Use admin menu buttons")
        send_website_purchase_notice(ADMIN_CHAT_ID)
        logger.warning(f"Unknown admin menu command: '{text}'")

# ---------- تأیید/انصراف قوانین (کاربر: فقط پیام وبسایت، بدون ادامهٔ جریان) ----------
@bot.callback_query_handler(func=lambda call: call.data in ["rules_agree", "rules_cancel"])
def handle_rules_response(call):
    user_id = call.from_user.id
    if not is_customer_side(user_id):
        try:
            bot.answer_callback_query(call.id)
        except Exception:
            pass
        return

    waiting_for_rules_confirm.discard(user_id)
    save_database()
    try:
        bot.edit_message_reply_markup(
            call.message.chat.id,
            call.message.message_id,
            reply_markup=types.InlineKeyboardMarkup(),
        )
    except Exception:
        pass
    try:
        bot.answer_callback_query(call.id)
    except Exception:
        pass
    send_customer_primary_message(call.message.chat.id, user_id)
    logger.info(f"User {user_id} rules callback -> website only")

# ---------- انتخاب پلن (قدیمی؛ برای کاربر فقط پیام وبسایت) ----------
@bot.callback_query_handler(func=lambda call: call.data.startswith("plan_"))
def plan_selected(call):
    user_id = call.from_user.id
    try:
        if not is_customer_side(user_id):
            bot.answer_callback_query(call.id)
            return
        try:
            bot.answer_callback_query(call.id)
        except Exception:
            pass
        try:
            bot.edit_message_reply_markup(
                call.message.chat.id,
                call.message.message_id,
                reply_markup=types.InlineKeyboardMarkup(),
            )
        except Exception:
            pass
        send_customer_primary_message(call.message.chat.id, user_id)
    except Exception as e:
        logger.error(f"Error in plan selection for user {user_id}: {str(e)}")

# ---------- handler دکمه واریز کردم (کاربر: فقط پیام وبسایت) ----------
@bot.callback_query_handler(func=lambda call: call.data == "payment_done")
def payment_done(call):
    user_id = call.from_user.id
    try:
        if not is_customer_side(user_id):
            try:
                bot.answer_callback_query(call.id)
            except Exception:
                pass
            return
        try:
            bot.answer_callback_query(call.id)
        except Exception:
            pass
        try:
            bot.edit_message_reply_markup(
                call.message.chat.id,
                call.message.message_id,
                reply_markup=types.InlineKeyboardMarkup(),
            )
        except Exception:
            pass
        send_customer_primary_message(call.message.chat.id, user_id)
        logger.info(f"User {user_id} payment_done callback -> website only")
    except Exception as e:
        logger.error(f"Error in payment button for user {user_id}: {str(e)}")

# ---------- handler دکمه کپی کارت (حذف شد) ----------

# ---------- ذخیره تاریخچه سفارش ----------
def save_order_history(user_id, months, total_price):
    order = {
        "months": months,
        "total_price": total_price,
        "date": datetime.now().strftime("%Y-%m-%d %H:%M")
    }
    if user_id not in user_orders_history:
        user_orders_history[user_id] = []
    user_orders_history[user_id].append(order)
    save_database()

# ---------- دریافت شماره موبایل ----------
@bot.message_handler(content_types=['contact'])
def handle_contact(message):
    try:
        user_id = message.from_user.id
        phone_number = message.contact.phone_number
        
        # اگر user قبلاً ثبت نشده، اضافه کن
        if user_id not in registered_users:
            registered_users.add(user_id)
            logger.info(f"User {user_id} registered (via phone share)")
        
        # ذخیره شماره موبایل
        user_phone_numbers[user_id] = phone_number
        logger.info(f"User {user_id} shared phone number: {phone_number}")
        save_database()
        
        send_customer_primary_message(user_id, user_id)

        # فوروارد به ادمین
        try:
            phone_msg = f"📱 کاربر شماره موبایل ارسال کرد:\n<code>{phone_number}</code>\n\nکاربر ID: {user_id}"
            forwarded_msg = bot.send_message(ADMIN_CHAT_ID, phone_msg, parse_mode="HTML")
            admin_messages_map[forwarded_msg.message_id] = user_id
            logger.info(f"User phone number {user_id} sent to admin (msg_id: {forwarded_msg.message_id})")
        except Exception as e:
            logger.warning(f"Error sending phone number to admin: {str(e)}")
    
    except Exception as e:
        logger.error(f"Error handling contact for user {message.from_user.id}: {str(e)}")
        if is_customer_side(message.from_user.id):
            send_customer_primary_message(message.chat.id, message.from_user.id)
        else:
            bot.send_message(message.chat.id, "❌ خطا در ثبت شماره موبایل")

# ---------- handler دکمه کپی آیدی کاربر ----------
@bot.callback_query_handler(func=lambda call: call.data.startswith("copy_user_id_"))
def copy_user_id(call):
    try:
        user_id = int(call.data.split("_")[3])
        bot.answer_callback_query(call.id, f"✅ آیدی {user_id} کپی شد!", show_alert=False)
        logger.info(f"Admin copied user ID: {user_id}")
    except Exception as e:
        logger.error(f"Error in copy user ID: {str(e)}")

# ---------- Admin mode command ----------
@bot.message_handler(commands=['admin'])
def admin_mode_command(message):
    if message.from_user.id != ADMIN_CHAT_ID:
        bot.send_message(message.chat.id, "❌ This command is only for admin")
        return
    
    admin_in_customer_mode.discard(ADMIN_CHAT_ID)
    clear_all_admin_compose_states()
    bot.send_message(ADMIN_CHAT_ID, "✅ حالت ادمین فعال شد (حالت ارسال/همگانی در صورت وجود بسته شد).")
    admin_menu(ADMIN_CHAT_ID)

# ---------- Send direct message command for admin ----------
@bot.message_handler(commands=['send'])
def send_message_command(message):
    if message.chat.id != ADMIN_CHAT_ID:
        bot.send_message(message.chat.id, "❌ This command is only for admin")
        return
    
    clear_broadcast_state()
    admin_send_state[ADMIN_CHAT_ID] = {"step": "waiting_id"}
    bot.send_message(
        ADMIN_CHAT_ID,
        "📨 ارسال پیام به یک کاربر\n\n"
        "۱️⃣ شناسهٔ عددی کاربر را بفرستید.\n"
        "برای لغو: /cancel",
    )
    send_website_purchase_notice(ADMIN_CHAT_ID)

# ---------- اجرای ربات ----------
# بارگذاری دیتابیس
load_database()

# اگر database file وجود ندارد، یک database خالی ایجاد کن
if not os.path.exists(DB_FILE):
    save_database()
    logger.info("Initial database created")

logger.info("Bot started")

# حلقه retry برای مدیریت خطاهای شبکه
retry_count = 0
max_retries = 5
retry_delay = 5  # ثانیه

while True:
    try:
        logger.info("Starting bot polling...")
        bot.polling(timeout=30, long_polling_timeout=30, non_stop=True)
    except KeyboardInterrupt:
        logger.info("Bot stopped by user")
        save_database()
        break
    except Exception as e:
        retry_count += 1
        logger.error(f"Bot error (attempt {retry_count}): {str(e)}")
        
        if retry_count >= max_retries:
            logger.critical("Max retries reached. Stopping bot.")
            save_database()
            break
        
        wait_time = retry_delay * (2 ** (retry_count - 1))  # exponential backoff
        logger.warning(f"Retrying in {wait_time} seconds...")
        save_database()
        time.sleep(wait_time)
        retry_count = 0  # Reset on successful reconnection
