import telebot
import json
import os
import requests
import csv
import io
import re
from telebot import types

BOT_TOKEN = '8696903236:AAEQEXh3xZGU8PmrGE2u14hFVaWsCmAxkXE'
ADMIN_ID = 7259690721
ADMIN_USERNAME = "@Sadekul_me"
DB_FILE = 'numbers.json'
USERS_FILE = 'users.json'

# 🔗 OTP Group Link & Chat ID (for checking membership)
OTP_GROUP_LINK = "https://t.me/+vv6s70Qwbc81YTJl"
OTP_GROUP_CHAT_ID = "@vv6s70Qwbc81YTJl" 

# 🌐 Lamix API Configuration
API_KEY = "X5N4WohnVEFUbnOIVItviHORlWV7mHZSSoxVW2qLmWY="
API_BASE_URL = "http://51.77.216.195/crapi/lamix/viewstats"

bot = telebot.TeleBot(BOT_TOKEN)

# 🌍 Country Prefix List
COUNTRY_PREFIXES = {
    "93": "AF", "355": "AL", "213": "DZ", "376": "AD", "244": "AO", "1264": "AI", "1268": "AG", "54": "AR", 
    "374": "AM", "297": "AW", "61": "AU", "43": "AT", "994": "AZ", "1242": "BS", "973": "BH", "880": "BD", 
    "1246": "BB", "375": "BY", "32": "BE", "501": "BZ", "229": "BJ", "1441": "BM", "975": "BT", "591": "BO", 
    "387": "BA", "267": "BW", "55": "BR", "1284": "VG", "673": "BN", "359": "BG", "226": "BF", "257": "BI", 
    "238": "CV", "855": "KH", "237": "CM", "1": "US", "1684": "AS", "1345": "KY", "236": "CF", "235": "TD", 
    "56": "CL", "86": "CN", "618": "CX", "619": "CC", "57": "CO", "269": "KM", "242": "CG", "243": "CD", 
    "682": "CK", "506": "CR", "225": "CI", "385": "HR", "53": "CU", "357": "CY", "420": "CZ", "45": "DK", 
    "253": "DJ", "1767": "DM", "1809": "DO", "1829": "DO", "1849": "DO", "593": "EC", "20": "EG", "503": "SV", 
    "240": "GQ", "291": "ER", "372": "EE", "251": "ET", "1340": "VI", "500": "FK", "298": "FO", "679": "FJ", 
    "358": "FI", "33": "FR", "594": "GF", "689": "PF", "241": "GA", "220": "GM", "995": "GE", "49": "DE", 
    "233": "GH", "350": "GI", "30": "GR", "299": "GL", "1473": "GD", "590": "GP", "1671": "GU", "502": "GT", 
    "224": "GN", "245": "GW", "592": "GY", "509": "HT", "504": "HN", "852": "HK", "36": "HU", "354": "IS", 
    "91": "IN", "62": "ID", "98": "IR", "964": "IQ", "353": "IE", "972": "IL", "39": "IT", "1876": "JM", 
    "81": "JP", "962": "JO", "77": "KZ", "76": "KZ", "254": "KE", "686": "KI", "965": "KW", "996": "KG", 
    "856": "LA", "371": "LV", "961": "LB", "266": "LS", "231": "LR", "218": "LY", "423": "LI", "370": "LT", 
    "352": "LU", "853": "MO", "389": "MK", "261": "MG", "265": "MW", "60": "MY", "960": "MV", "223": "ML", 
    "356": "MT", "692": "MH", "596": "MQ", "222": "MR", "230": "MU", "262": "RE", "52": "MX", "691": "FM", 
    "373": "MD", "377": "MC", "976": "MN", "382": "ME", "1664": "MS", "212": "MA", "258": "MZ", "95": "MM", 
    "264": "NA", "674": "NR", "977": "NP", "31": "NL", "599": "AN", "687": "NC", "64": "NZ", "505": "NI", 
    "227": "NE", "234": "NG", "683": "NU", "672": "NF", "1670": "MP", "47": "NO", "968": "OM", "92": "PK", 
    "680": "PW", "970": "PS", "507": "PA", "675": "PG", "595": "PY", "51": "PE", "63": "PH", "48": "PL", 
    "351": "PT", "1787": "PR", "1939": "PR", "974": "QA", "40": "RO", "7": "RU", "250": "RW", "290": "SH", 
    "1869": "KN", "1758": "LC", "508": "PM", "1784": "VC", "685": "WS", "378": "SM", "239": "ST", "966": "SA", 
    "221": "SN", "381": "RS", "248": "SC", "232": "SL", "65": "SG", "421": "SK", "386": "SI", "677": "SB", 
    "252": "SO", "27": "ZA", "82": "KR", "34": "ES", "94": "LK", "249": "SD", "597": "SR", "268": "SZ", 
    "46": "SE", "41": "CH", "963": "SY", "886": "TW", "992": "TJ", "255": "TZ", "66": "TH", "228": "TG", 
    "690": "TK", "676": "TO", "1868": "TT", "216": "TN", "90": "TR", "993": "TM", "1649": "TC", "688": "TV", 
    "256": "UG", "380": "UA", "971": "AE", "44": "GB", "598": "UY", "998": "UZ", "678": "VU", "3906": "VA", 
    "58": "VE", "84": "VN", "1340": "VI", "681": "WF", "967": "YE", "260": "ZM", "263": "ZW"
}

COUNTRIES = {
    "AF": "Afghanistan 🇦🇫", "AL": "Albania 🇦🇱", "DZ": "Algeria 🇩🇿", "AD": "Andorra 🇦🇩", "AO": "Angola 🇦🇴", 
    "AR": "Argentina 🇦🇷", "AM": "Armenia 🇦🇲", "AU": "Australia 🇦🇺", "AT": "Austria 🇦🇹", "AZ": "Azerbaijan 🇦🇿", 
    "BS": "Bahamas 🇧🇸", "BH": "Bahrain 🇧🇭", "BD": "Bangladesh 🇧🇩", "BB": "Barbados 🇧🇧", "BY": "Belarus 🇧🇾", 
    "BE": "Belgium 🇧🇪", "BZ": "Belize 🇧🇿", "BJ": "Benin 🇧🇯", "BT": "Bhutan 🇧🇹", "BO": "Bolivia 🇧🇴", 
    "BA": "Bosnia and Herzegovina 🇧🇦", "BW": "Botswana 🇧🇼", "BR": "Brazil 🇧🇷", "BN": "Brunei 🇧🇳", 
    "BG": "Bulgaria 🇧🇬", "BF": "Burkina Faso 🇧🇫", "BI": "Burundi 🇧🇮", "KH": "Cambodia 🇰🇭", "CM": "Cameroon 🇨🇲", 
    "CA": "Canada 🇨🇦", "CV": "Cape Verde 🇨🇻", "CF": "Central African Republic 🇨🇫", "TD": "Chad 🇹🇩", "CL": "Chile 🇨🇱", 
    "CN": "China 🇨🇳", "CO": "Colombia 🇨🇴", "KM": "Comoros 🇰🇲", "CG": "Congo (Brazzaville) 🇨🇬", "CD": "Congo (Kinshasa) 🇨🇩", 
    "CR": "Costa Rica 🇨🇷", "HR": "Croatia 🇭🇷", "CU": "Cuba 🇨🇺", "CY": "Cyprus 🇨🇾", "CZ": "Czech Republic 🇨🇿", 
    "DK": "Denmark 🇩🇰", "DJ": "Djibouti 🇩🇯", "DM": "Dominica 🇩🇲", "DO": "Dominican Republic 🇩🇴", "EC": "Ecuador 🇪🇨", 
    "EG": "Egypt 🇪🇬", "SV": "El Salvador 🇸🇻", "GQ": "Equatorial Guinea 🇬🇶", "ER": "Eritrea 🇪🇷", "EE": "Estonia 🇪🇪", 
    "ET": "Ethiopia 🇪🇹", "FJ": "Fiji 🇫ジタル", "FI": "Finland 🇫🇮", "FR": "France 🇫🇷", "GA": "Gabon 🇬🇦", "GM": "Gambia 🇬🇲", 
    "GE": "Georgia 🇬🇪", "DE": "Germany 🇩🇪", "GH": "Ghana 🇬🇭", "GR": "Greece 🇬🇷", "GD": "Grenada 🇬🇩", "GT": "Guatemala 🇬🇹", 
    "GN": "Guinea 🇬🇳", "GW": "Guinea-Bissau 🇬🇼", "GY": "Guyana 🇬🇾", "HT": "Haiti 🇭🇹", "HN": "Honduras 🇭🇳", 
    "HU": "Hungary 🇭🇺", "IS": "Iceland 🇮🇸", "IN": "India 🇮🇳", "ID": "Indonesia 🇮🇩", "IR": "Iran 🇮🇷", "IQ": "Iraq 🇮🇶", 
    "IE": "Ireland 🇮🇪", "IL": "Israel 🇮🇱", "IT": "Italy 🇮🇹", "JM": "Jamaica 🇯🇲", "JP": "Japan 🇯🇵", "JO": "Jordan 🇯🇴", 
    "KZ": "Kazakhstan 🇰🇿", "KE": "Kenya 🇰🇪", "KI": "Kiribati 🇰🇮", "KW": "Kuwait 🇰🇼", "KG": "Kyrgyzstan 🇰🇬", 
    "LA": "Laos 🇱🇦", "LV": "Latvia 🇱🇻", "LB": "Lebanon 🇱🇧", "LS": "Lesotho 🇱🇸", "LR": "Liberia 🇱🇷", "LY": "Libya 🇱🇾", 
    "LI": "Liechtenstein 🇱🇮", "LT": "Lithuania 🇱🇹", "LU": "Luxembourg 🇱🇺", "MG": "Madagascar 🇲🇬", "MW": "Malawi 🇲🇼", 
    "MY": "Malaysia 🇲🇾", "MV": "Maldives 🇲🇻", "ML": "Mali 🇲🇱", "MT": "Malta 🇲🇹", "MH": "Marshall Islands 🇲🇭", 
    "MR": "Mauritania 🇲🇷", "MU": "Mauritius 🇲🇺", "MX": "Mexico 🇲🇽", "FM": "Micronesia 🇫🇲", "MD": "Moldova 🇲🇩", 
    "MC": "Monaco 🇲🇨", "MN": "Mongolia 🇲🇳", "ME": "Montenegro 🇲🇪", "MA": "Morocco 🇲🇦", "MZ": "Mozambique 🇲🇿", 
    "MM": "Myanmar 🇲🇲", "NA": "Namibia 🇳🇦", "NR": "Nauru 🇳🇷", "NP": "Nepal 🇳🇵", "NL": "Netherlands 🇳🇱", 
    "NZ": "New Zealand 🇳🇿", "NI": "Nicaragua 🇳🇮", "NE": "Niger 🇳🇪", "NG": "Nigeria 🇳🇬", "KP": "North Korea 🇰🇵", 
    "MK": "North Macedonia 🇲🇰", "NO": "Norway 🇳🇴", "OM": "Oman 🇴🇲", "PK": "Pakistan 🇵🇰", "PW": "Palau 🇵🇼", 
    "PA": "Panama 🇵🇦", "PG": "Papua New Guinea 🇵🇬", "PY": "Paraguay 🇵🇾", "PE": "Peru 🇵🇪", "PH": "Philippines 🇵🇭", 
    "PL": "Poland 🇵🇱", "PT": "Portugal 🇵🇹", "QA": "Qatar 🇶🇦", "RO": "Romania 🇷🇴", "RU": "Russia 🇷🇺", 
    "RW": "Rwanda 🇷🇼", "KN": "Saint Kitts and Nevis 🇰🇳", "LC": "Saint Lucia 🇱🇨", "VC": "Saint Vincent 🇻🇨", 
    "WS": "Samoa 🇼🇸", "SM": "San Marino 🇸🇲", "SA": "Saudi Arabia 🇸🇦", "SN": "Senegal 🇸🇳", "RS": "Serbia 🇷🇸", 
    "SC": "Seychelles 🇸🇨", "SL": "Sierra Leone 🇸🇱", "SG": "Singapore 🇸🇬", "SK": "Slovakia 🇸🇰", "SI": "Slovenia 🇸🇮", 
    "SB": "Solomon Islands 🇸🇧", "ZA": "South Africa 🇿🇦", "KR": "South Korea 🇰🇷", "SS": "South Sudan 🇸🇸", 
    "ES": "Spain 🇪🇸", "LK": "Sri Lanka 🇱🇰", "SD": "Sudan 🇸🇩", "SR": "Suriname 🇸🇷", "SE": "Sweden 🇸🇪", 
    "CH": "Switzerland 🇨🇭", "SY": "Syria 🇸🇾", "TW": "Taiwan 🇹🇼", "TJ": "Tajikistan 🇹🇯", "TZ": "Tanzania 🇹🇿", 
    "TH": "Thailand 🇹🇭", "TG": "Togo 🇹🇬", "TO": "Tonga 🇹🇴", "TN": "Tunisia 🇹🇳", "TM": "Turkmenistan 🇹🇲", 
    "TV": "Tuvalu 🇹🇻", "UG": "Uganda 🇺🇬", "UA": "Ukraine 🇺🇦", "AE": "United Arab Emirates 🇦🇪", 
    "GB": "United Kingdom 🇬🇧", "US": "United States 🇺🇸", "UY": "Uruguay 🇺🇾", "UZ": "Uzbekistan 🇺🇿", 
    "VU": "Vanuatu 🇻🇺", "VA": "Vatican City 🇻🇦", "VE": "Venezuela 🇻🇪", "VN": "Vietnam 🇻🇳", "YE": "Yemen 🇾🇪", "ZM": "Zambia 🇿🇲"
}

def load_db():
    if not os.path.exists(DB_FILE): return {}
    with open(DB_FILE, 'r') as f:
        try: return json.load(f)
        except: return {}

def save_db(data):
    with open(DB_FILE, 'w') as f: json.dump(data, f, indent=4)

def load_users():
    if not os.path.exists(USERS_FILE): return {}
    with open(USERS_FILE, 'r') as f:
        try: return json.load(f)
        except: return {}

def save_users(data):
    with open(USERS_FILE, 'w') as f: json.dump(data, f, indent=4)

def register_user(user_id, name):
    users = load_users()
    uid_str = str(user_id)
    if uid_str not in users:
        users[uid_str] = {"name": name, "otp_count": 0}
        save_users(users)

def increment_user_otp(user_id):
    users = load_users()
    uid_str = str(user_id)
    if uid_str in users:
        users[uid_str]["otp_count"] += 1
        save_users(users)

# 🛑 Function to check if user joined the Telegram group
def check_membership(user_id):
    if int(user_id) == ADMIN_ID:
        return True
    try:
        member = bot.get_chat_member(OTP_GROUP_CHAT_ID, user_id)
        if member.status in ['member', 'administrator', 'creator']:
            return True
        else:
            return False
    except Exception:
        return True

# 🚫 Send Join Force Message
def send_force_join_msg(chat_id):
    markup = types.InlineKeyboardMarkup(row_width=1)
    btn_join = types.InlineKeyboardButton("💬 Join OTP Group", url=OTP_GROUP_LINK)
    btn_check = types.InlineKeyboardButton("✅ Joined (Check)", callback_data="check_join")
    markup.add(btn_join, btn_check)
    
    text = (
        "⚠️ **Access Denied!**\n\n"
        "You must join our official OTP group to use this bot. "
        "Please click the link below to join, then click on the check button."
    )
    bot.send_message(chat_id, text, reply_markup=markup, parse_mode='Markdown')

def main_menu(message):
    if not check_membership(message.from_user.id):
        send_force_join_msg(message.chat.id)
        return
        
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)
    markup.add(types.KeyboardButton("Get Number"), types.KeyboardButton("Support"))
    
    if int(message.from_user.id) == ADMIN_ID:
        markup.add(types.KeyboardButton("💎 Add Number"), types.KeyboardButton("🗑 Remove Number"))
        markup.add(types.KeyboardButton("📁 Add File"), types.KeyboardButton("🗑 Remove File"))
        markup.add(types.KeyboardButton("📊 Status"), types.KeyboardButton("📢 Broadcast"))
        
    markup.add(types.KeyboardButton("Menu"))
    bot.send_message(message.chat.id, "⚡ **Main Menu Opened. Choose an option:**", reply_markup=markup, parse_mode='Markdown')

@bot.message_handler(commands=['start'])
def start(message):
    bot.clear_step_handler_by_chat_id(chat_id=message.chat.id)
    register_user(message.from_user.id, message.from_user.first_name)
    
    if not check_membership(message.from_user.id):
        send_force_join_msg(message.chat.id)
        return
        
    user_name = message.from_user.first_name
    safe_admin_username = ADMIN_USERNAME.replace('_', '\\_')
    welcome_text = (
        f"👑 **Welcome to DTS OTP Bot, {user_name}!**\n\n"
        "✨ Welcome to our elite service bot. Use the premium options below to get your desired numbers instantly.\n\n"
        "👤 **Bot Developer:** Sadekul Islam\n"
        f"🛠 **Admin:** {safe_admin_username}\n\n"
        "⚡ Please navigate using the keyboard menu below."
    )
    
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)
    markup.add(types.KeyboardButton("Get Number"), types.KeyboardButton("Support"))
    if int(message.from_user.id) == ADMIN_ID:
        markup.add(types.KeyboardButton("💎 Add Number"), types.KeyboardButton("🗑 Remove Number"))
        markup.add(types.KeyboardButton("📁 Add File"), types.KeyboardButton("🗑 Remove File"))
        markup.add(types.KeyboardButton("📊 Status"), types.KeyboardButton("📢 Broadcast"))
    markup.add(types.KeyboardButton("Menu"))
    
    bot.send_message(message.chat.id, welcome_text, reply_markup=markup, parse_mode='Markdown', disable_web_page_preview=True)

@bot.message_handler(func=lambda message: message.text == "Menu")
def handle_menu(message):
    bot.clear_step_handler_by_chat_id(chat_id=message.chat.id)
    main_menu(message)

@bot.message_handler(func=lambda message: message.text == "Support")
def send_support(message):
    safe_admin_username = ADMIN_USERNAME.replace('_', '\\_')
    support_text = (
        "📩 সহায়তার প্রয়োজন?\n\n"
        "আপনার যদি কোনো প্রশ্ন থাকে, কোনো সমস্যায় পড়েন বা নাম্বার সংক্রান্ত কোনো সাহায্যের প্রয়োজন হয়, "
        "তবে নির্দ্বিধায় আমাদের এডমিনের সাথে যোগাযোগ করুন Executive।\n\n"
        f"👤 এডমিন: {safe_admin_username}\n\n"
        "সরাসরি এডমিনের সাথে চ্যাট করতে নিচের বাটনে ক্লিক করুন।"
    )
    markup = types.InlineKeyboardMarkup()
    markup.add(types.InlineKeyboardButton("💬 এডমিনের সাথে যোগাযোগ", url=f"https://t.me/{ADMIN_USERNAME.replace('@', '')}"))
    bot.send_message(message.chat.id, support_text, reply_markup=markup, parse_mode='Markdown')

# ----------------- Admin Status & Broadcast Section -----------------
@bot.message_handler(func=lambda message: int(message.from_user.id) == ADMIN_ID and message.text == "📊 Status")
def show_status(message):
    bot.clear_step_handler_by_chat_id(chat_id=message.chat.id)
    users = load_users()
    total_users = len(users)
    
    status_text = f"📊 **Bot Premium Status Report:**\n\n👥 **Total Active Users:** {total_users}\n\n"
    status_text += "📝 **User OTP Receipt History:**\n"
    
    if total_users == 0:
        status_text += "_No users found in database yet._"
    else:
        for uid, info in users.items():
            name = info.get("name", "Unknown")
            otp = info.get("otp_count", 0)
            status_text += f"• `{uid}` ({name}) -> **{otp}** OTPs Received\n"
            
    bot.send_message(message.chat.id, status_text, parse_mode='Markdown')

@bot.message_handler(func=lambda message: int(message.from_user.id) == ADMIN_ID and message.text == "📢 Broadcast")
def ask_broadcast_msg(message):
    bot.clear_step_handler_by_chat_id(chat_id=message.chat.id)
    msg = bot.send_message(message.chat.id, "📢 **Enter your notice/message to broadcast to all users:**", parse_mode='Markdown')
    bot.register_next_step_handler(msg, start_broadcast)

def start_broadcast(message):
    if int(message.from_user.id) != ADMIN_ID: return
    
    if not message.text or message.text.startswith("/") or message.text in ["Menu", "Get Number", "📊 Status", "📢 Broadcast"]:
        bot.send_message(message.chat.id, "❌ **Broadcast Canceled.**", parse_mode='Markdown')
        main_menu(message)
        return
        
    broadcast_text = message.text
    users = load_users()
    success = 0
    failed = 0
    
    sending_msg = bot.send_message(message.chat.id, "⏳ **Broadcasting started, please wait...**", parse_mode='Markdown')
    
    for uid in users.keys():
        try:
            bot.send_message(int(uid), broadcast_text)
            success += 1
        except Exception:
            failed += 1
            
    bot.delete_message(message.chat.id, sending_msg.message_id)
    bot.send_message(message.chat.id, f"👑 **Broadcast Finished!**\n\n🚀 Sent successfully: **{success}** users\n❌ Failed: **{failed}** users (Blocked bot).", parse_mode='Markdown')

# ----------------- Admin Add/Remove Number -----------------
@bot.message_handler(func=lambda message: int(message.from_user.id) == ADMIN_ID and message.text == "💎 Add Number")
def ask_for_add(message):
    bot.clear_step_handler_by_chat_id(chat_id=message.chat.id)
    msg = bot.send_message(message.chat.id, "📞 **Paste the phone number directly (e.g., 88017XXXXXXXX):**", parse_mode='Markdown')
    bot.register_next_step_handler(msg, process_add_number)

def process_add_number(message):
    if int(message.from_user.id) != ADMIN_ID: return
    
    if not message.text or message.text.startswith("/") or message.text in ["Menu", "Get Number", "📁 Add File", "🗑 Remove File", "💎 Add Number", "🗑 Remove Number"]:
        bot.send_message(message.chat.id, "❌ **Operation canceled. Please try again.**", parse_mode='Markdown')
        main_menu(message)
        return

    number = message.text.strip().replace("+", "")
    if len(number) < 7 or not number.isdigit():
        bot.send_message(message.chat.id, "❌ **Invalid Number! Minimum 7 digits required.**", parse_mode='Markdown')
        return

    detected_code = None
    for prefix in sorted(COUNTRY_PREFIXES.keys(), key=len, reverse=True):
        if number.startswith(prefix):
            detected_code = COUNTRY_PREFIXES[prefix]
            break
            
    if detected_code and detected_code in COUNTRIES:
        country_full = COUNTRIES[detected_code]
        db = load_db()
        if country_full not in db: db[country_full] = []
        
        if number in db[country_full]:
            bot.send_message(message.chat.id, "⚠️ **This number is already in the database!**", parse_mode='Markdown')
            return
            
        db[country_full].append(number)
        save_db(db)
        bot.send_message(message.chat.id, f"💎 **Number Added Successfully!**\n📞 Phone: `{number}`\n🌍 Country: **{country_full}**", parse_mode='Markdown')
    else:
        bot.send_message(message.chat.id, "❌ **Country prefix mismatch! Please include correct country code.**", parse_mode='Markdown')

@bot.message_handler(func=lambda message: int(message.from_user.id) == ADMIN_ID and message.text == "🗑 Remove Number")
def ask_remove(message):
    bot.clear_step_handler_by_chat_id(chat_id=message.chat.id)
    db = load_db()
    markup = types.InlineKeyboardMarkup()
    has_keys = False
    for country in db.keys():
        if len(db[country]) > 0:
            markup.add(types.InlineKeyboardButton(f"{country} ({len(db[country])}) 🗑", callback_data=f"del_{country}"))
            has_keys = True
    if not has_keys:
        bot.send_message(message.chat.id, "❌ No numbers available to remove.")
    else:
        bot.send_message(message.chat.id, "👑 **Select a country to clear all numbers:**", reply_markup=markup, parse_mode='Markdown')

# ----------------- File Handling Section -----------------
@bot.message_handler(func=lambda message: int(message.from_user.id) == ADMIN_ID and message.text == "📁 Add File")
def ask_for_file_add(message):
    bot.clear_step_handler_by_chat_id(chat_id=message.chat.id)
    msg = bot.send_message(message.chat.id, "📁 **Please upload your `.txt` or `.csv` file containing phone numbers:**", parse_mode='Markdown')
    bot.register_next_step_handler(msg, process_file_add)

def process_file_add(message):
    if int(message.from_user.id) != ADMIN_ID: return
    if not message.document:
        bot.send_message(message.chat.id, "❌ **This is not a valid file! Operation canceled.**", parse_mode='Markdown')
        main_menu(message)
        return
    
    try:
        file_info = bot.get_file(message.document.file_id)
        downloaded_file = bot.download_file(file_info.file_path)
        
        try: content = downloaded_file.decode("utf-8")
        except UnicodeDecodeError: content = downloaded_file.decode("latin-1")
        
        file_name = message.document.file_name.lower()
        raw_numbers = []
        
        if file_name.endswith('.csv'):
            csv_data = csv.reader(io.StringIO(content))
            for row in csv_data:
                for cell in row:
                    clean_cell = re.sub(r'\D', '', cell.strip())
                    if len(clean_cell) >= 7: 
                        raw_numbers.append(clean_cell)
        else:
            tokens = content.split()
            for token in tokens:
                clean_token = re.sub(r'\D', '', token.strip())
                if len(clean_token) >= 7:
                    raw_numbers.append(clean_token)
            
        db = load_db()
        success_count = 0
        duplicate_count = 0
        failed_count = 0
        
        for clean_num in raw_numbers:
            detected_code = None
            for prefix in sorted(COUNTRY_PREFIXES.keys(), key=len, reverse=True):
                if clean_num.startswith(prefix):
                    detected_code = COUNTRY_PREFIXES[prefix]
                    break
                    
            if detected_code and detected_code in COUNTRIES:
                country_full = COUNTRIES[detected_code]
                if country_full not in db: db[country_full] = []
                
                if clean_num not in db[country_full]:
                    db[country_full].append(clean_num)
                    success_count += 1
                else:
                    duplicate_count += 1
            else:
                failed_count += 1
                
        save_db(db)
        report = (
            f"📊 **File Import Report:**\n\n"
            f"✅ Successfully added: **{success_count}** pcs\n"
            f"⚠️ Duplicate numbers: **{duplicate_count}** pcs\n"
            f"❌ Failed/Unknown code: **{failed_count}** pcs"
        )
        bot.send_message(message.chat.id, report, parse_mode='Markdown')
    except Exception as e:
        bot.send_message(message.chat.id, f"❌ **Failed to process file! Error:** {e}")

@bot.message_handler(func=lambda message: int(message.from_user.id) == ADMIN_ID and message.text == "🗑 Remove File")
def ask_for_file_remove_list(message):
    bot.clear_step_handler_by_chat_id(chat_id=message.chat.id)
    db = load_db()
    markup = types.InlineKeyboardMarkup(row_width=1)
    has_stock = False
    
    for country, numbers in db.items():
        if len(numbers) > 0:
            markup.add(types.InlineKeyboardButton(f"🌍 {country} ({len(numbers)} pcs) 🗑 Delete", callback_data=f"del_{country}"))
            has_stock = True
            
    if not has_stock:
        bot.send_message(message.chat.id, "⚠️ **No data or countries available in database to delete!**", parse_mode='Markdown')
    else:
        bot.send_message(message.chat.id, "📁 **Select the country to delete all its files/numbers from the database:**", reply_markup=markup, parse_mode='Markdown')


# ----------------- User Panel (Get Number UI) -----------------
@bot.message_handler(func=lambda message: message.text == "Get Number")
def show_countries(message):
    bot.clear_step_handler_by_chat_id(chat_id=message.chat.id)
    if not check_membership(message.from_user.id):
        send_force_join_msg(message.chat.id)
        return
        
    db = load_db()
    markup = types.InlineKeyboardMarkup(row_width=2)
    has_stock = False
    for country, numbers in db.items():
        if len(numbers) > 0:
            markup.add(types.InlineKeyboardButton(f"✨ {country} ({len(numbers)})", callback_data=f"buy_{country}"))
            has_stock = True
    if not has_stock:
        bot.send_message(message.chat.id, "⚠️ **Sorry, no numbers currently in stock.**", parse_mode='Markdown')
    else:
        bot.send_message(message.chat.id, "👑 **Select a country to get premium numbers:**", reply_markup=markup, parse_mode='Markdown')


# 🎨 VIP Tapped-to-Copy UI Logic
def generate_numbers_response(user_id, country):
    db = load_db()
    if country in db and len(db[country]) > 0:
        num_count = min(3, len(db[country]))
        selected_numbers = [db[country].pop(0) for _ in range(num_count)]
        save_db(db)
        
        for _ in range(num_count):
            increment_user_otp(user_id)
        
        headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
        for phone_number in selected_numbers:
            payload = {"phone": phone_number, "country": country, "status": "active"}
            try: requests.post(API_BASE_URL, json=payload, headers=headers, timeout=5)
            except: pass
        
        flag = ""
        match = re.search(r'[\U0001F1E6-\U0001F1FF]{2}', country)
        if match:
            flag = match.group(0)
            
        markup = types.InlineKeyboardMarkup()
        
        # OTP_LINK defined natively inside to prevent undefined variables
        OTP_LINK = "https://t.me/+vv6s70Qwbc81YTJl"
        btn_change_country = types.InlineKeyboardButton("👑 Change Country", callback_data="change_country")
        btn_otp_group = types.InlineKeyboardButton("💬 Otp Group", url=OTP_LINK)
        markup.row(btn_change_country, btn_otp_group)
        
        btn_refresh = types.InlineKeyboardButton("Refresh", callback_data=f"refresh_{country}")
        markup.row(btn_refresh)
        
        response_text = (
            "⭐ **Dts New Telegram** ⭐\n\n"
            "👇 **Tap on the numbers below to copy them instantly:**\n\n"
        )
        
        for num in selected_numbers:
            response_text += f"{flag} `{num}`\n\n"
            
        return response_text, markup
    else:
        return None, None

@bot.callback_query_handler(func=lambda call: True)
def callback(call):
    db = load_db()
    register_user(call.from_user.id, call.from_user.first_name)
    
    # Check join status dynamically on button press
    if call.data == "check_join":
        if check_membership(call.from_user.id):
            bot.delete_message(call.message.chat.id, call.message.message_id)
            user_name = call.from_user.first_name
            safe_admin_username = ADMIN_USERNAME.replace('_', '\\_')
            welcome_text = (
                f"👑 **Welcome to DTS OTP Bot, {user_name}!**\n\n"
                "✨ Welcome to our elite service bot. Use the premium options below to get your desired numbers instantly.\n\n"
                "👤 **Bot Developer:** Sadekul Islam\n"
                f"🛠 **Admin:** {safe_admin_username}\n\n"
                "⚡ Please navigate using the keyboard menu below."
            )
            markup = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)
            markup.add(types.KeyboardButton("Get Number"), types.KeyboardButton("Support"))
            if int(call.from_user.id) == ADMIN_ID:
                markup.add(types.KeyboardButton("💎 Add Number"), types.KeyboardButton("🗑 Remove Number"))
                markup.add(types.KeyboardButton("📁 Add File"), types.KeyboardButton("🗑 Remove File"))
                markup.add(types.KeyboardButton("📊 Status"), types.KeyboardButton("📢 Broadcast"))
            markup.add(types.KeyboardButton("Menu"))
            bot.send_message(call.message.chat.id, welcome_text, reply_markup=markup, parse_mode='Markdown')
        else:
            bot.answer_callback_query(call.id, "❌ You haven't joined the group yet! Please join first.", show_alert=True)
        return

    # Check join restriction for other callbacks too
    if not check_membership(call.from_user.id):
        bot.answer_callback_query(call.id, "⚠️ Please join the group first!", show_alert=True)
        send_force_join_msg(call.message.chat.id)
        return

    if call.data.startswith("del_"):
        country = call.data.replace("del_", "")
        markup = types.InlineKeyboardMarkup()
        markup.add(
            types.InlineKeyboardButton("✅ Yes, Delete", callback_data=f"confirm_{country}"),
            types.InlineKeyboardButton("❌ Cancel", callback_data="cancel")
        )
        safe_country = country.replace('_', '\\_')
        bot.edit_message_text(f"⚠️ Are you sure you want to completely erase **{safe_country}** from the database?", call.message.chat.id, call.message.id, reply_markup=markup, parse_mode='Markdown')
            
    elif call.data.startswith("confirm_"):
        country = call.data.replace("confirm_", "")
        if country in db:
            del db[country]
            save_db(db)
            safe_country = country.replace('_', '\\_')
            bot.edit_message_text(f"🗑 Successfully deleted all data for **{safe_country}**.", call.message.chat.id, call.message.id, parse_mode='Markdown')
            
    elif call.data == "cancel":
        bot.edit_message_text("❌ **Operation canceled. Data remains untouched.**", call.message.chat.id, call.message.id, parse_mode='Markdown')
        
    elif call.data.startswith("buy_"):
        country = call.data.replace("buy_", "")
        text, markup = generate_numbers_response(call.from_user.id, country)
        if text:
            bot.edit_message_text(text, call.message.chat.id, call.message.id, reply_markup=markup, parse_mode='Markdown')
        else:
            bot.answer_callback_query(call.id, "No numbers available in this country!")
            
    elif call.data.startswith("refresh_"):
        country = call.data.replace("refresh_", "")
        text, markup = generate_numbers_response(call.from_user.id, country)
        if text:
            bot.edit_message_text(text, call.message.chat.id, call.message.id, reply_markup=markup, parse_mode='Markdown')
            bot.answer_callback_query(call.id, "Numbers refreshed successfully!")
        else:
            bot.answer_callback_query(call.id, "⚠️ No more premium numbers available in this country!", show_alert=True)
            
    elif call.data == "change_country":
        markup = types.InlineKeyboardMarkup(row_width=2)
        has_stock = False
        for country, numbers in db.items():
            if len(numbers) > 0:
                markup.add(types.InlineKeyboardButton(f"✨ {country} ({len(numbers)})", callback_data=f"buy_{country}"))
                has_stock = True
        if not has_stock:
            bot.edit_message_text("⚠️ No numbers currently in stock.", call.message.chat.id, call.message.id)
        else:
            bot.edit_message_text("👑 **Select a country to get premium numbers:**", call.message.chat.id, call.message.id, reply_markup=markup, parse_mode='Markdown')

bot.delete_my_commands()
bot.set_my_commands([telebot.types.BotCommand("start", "Start the bot")])
bot.polling(none_stop=True)