import logging
import httpx
import json
import asyncio
import os
import random
import string
import time
from datetime import datetime, timedelta
from telethon import TelegramClient
from telethon.errors import UsernameNotOccupiedError, UsernameInvalidError

logging.basicConfig(level=logging.INFO)

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# CONFIG
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
BOT_TOKEN        = "8969062982:AAHWTcxzkfTA-2-IM2Cjfg2GCNJ3nhlAqrE"
BOT_USERNAME     = "AvonHost_bot"
ADMIN_IDS        = {8855146797}  # Apna Telegram ID yahan daalo (set me, comma se multiple)

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# FORCE JOIN CHANNELS
# Yahan apne 3 channels daalo. Format:
#   "username"  -> public channel ka username (without @)  -> link auto banega
#   "id"        -> bot ko us channel me ADMIN hona ZARURI hai (membership check ke liye)
#   "title"     -> button par dikhne wala naam
#   "link"      -> (optional) private channel ke liye invite link
# IMPORTANT: Membership check ke liye BOT ko har channel me ADMIN banana padega.
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
FORCE_JOIN_CHANNELS = [
    {"id": "@MJ_SARKAR_OFFICIAL",   "title": "JOIN", "link": "https://t.me/MJ_SARKAR_OFFICIAL"},
]

NUMBER_API_KEY   = "mjsarkar"
NUMBER_API_URL   = "https://numinfo.eu.cc/api/check?apikey={key}&number={number}"

USERNAME_API_KEY = "mjsarkarid"
USERNAME_API_URL = "https://numinfo.eu.cc/api/tgid?apikey={key}&id={id}"

TGID_API_KEY     = "mjsarkarid"
TGID_API_URL     = "https://numinfo.eu.cc/api/tgid?apikey={key}&id={id}"

VEHICLE_API_KEY  = "Mjsarkarveh"
VEHICLE_API_URL  = "https://numinfo.eu.cc/api/vehiclev2?apikey={key}&rc={rc}"

GST_API_KEY      = "gw_YJ2yYshkLfThzM4qnRLAho0ch29G5c8W"
GST_API_URL      = "https://numinfo.eu.cc/api/gst?apikey={key}&gst={gst}"

PAN_API_KEY      = "gw_3cfSOkxaO_X_PcEZ_nITVxmNueYlhEJO"
PAN_API_URL      = "https://numinfo.eu.cc/api/pangst?apikey={key}&pan={pan}"

TELETHON_API_ID   = 36406173
TELETHON_API_HASH = "39a8af09b553d0a09c961a4059fecc16"
TELETHON_SESSION  = "personal_session"

API_URL       = f"https://api.telegram.org/bot{BOT_TOKEN}"
USERS_JSON    = "users.json"
SETTINGS_JSON = "settings.json"

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# GLOBAL SHARED HTTP CLIENT (connection pool reuse = bahut fast)
# Har request pe naya client banane ki jagah ek hi client reuse hota hai.
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
http = httpx.AsyncClient(
    timeout=httpx.Timeout(30.0, connect=10.0),
    limits=httpx.Limits(max_connections=200, max_keepalive_connections=100),
)

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# RATE LIMIT / ANTI-SPAM
# Har user ke liye 1.5 second ka message gap. Bulk automation ko rok deta hai.
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
RATE_LIMIT_SECONDS = 1.5
user_last_action = {}     # user_id -> last action timestamp (monotonic)
user_processing = set()   # abhi process ho rahe users (double-fire rokta hai)

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# MONOSPACE FONT
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
MONO_MAP = {
    'A':'𝙰','B':'𝙱','C':'𝙲','D':'𝙳','E':'𝙴','F':'𝙵','G':'𝙶','H':'𝙷','I':'𝙸',
    'J':'𝙹','K':'𝙺','L':'𝙻','M':'𝙼','N':'𝙽','O':'𝙾','P':'𝙿','Q':'𝚀','R':'𝚁',
    'S':'𝚂','T':'𝚃','U':'𝚄','V':'𝚅','W':'𝚆','X':'𝚇','Y':'𝚈','Z':'𝚉',
    'a':'𝚊','b':'𝚋','c':'𝚌','d':'𝚍','e':'𝚎','f':'𝚏','g':'𝚐','h':'𝚑','i':'𝚒',
    'j':'𝚓','k':'𝚔','l':'𝚕','m':'𝚖','n':'𝚗','o':'𝚘','p':'𝚙','q':'𝚚','r':'𝚛',
    's':'𝚜','t':'𝚝','u':'𝚞','v':'𝚟','w':'𝚠','x':'𝚡','y':'𝚢','z':'𝚣',
    '0':'𝟶','1':'𝟷','2':'𝟸','3':'𝟹','4':'𝟺','5':'𝟻','6':'𝟼','7':'𝟽','8':'𝟾','9':'𝟿'
}
def M(text):
    return ''.join(MONO_MAP.get(c, c) for c in text)

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# SETTINGS JSON
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
DEFAULT_SETTINGS = {
    "daily_free_search_limit": 0,
    "daily_claim_credits": 1,
    "referral_credits": 5,       # FIX: Admin se set ho sake
    "redeem_codes": {}
}

def load_settings():
    if os.path.exists(SETTINGS_JSON):
        with open(SETTINGS_JSON, "r") as f:
            data = json.load(f)
        for k, v in DEFAULT_SETTINGS.items():
            if k not in data:
                data[k] = v
        return data
    return DEFAULT_SETTINGS.copy()

def save_settings(settings):
    with open(SETTINGS_JSON, "w") as f:
        json.dump(settings, f, indent=2, ensure_ascii=False)

settings = load_settings()

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# USERS JSON DB
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
def load_users_json():
    if os.path.exists(USERS_JSON):
        with open(USERS_JSON, "r") as f:
            return json.load(f)
    return {}

def save_users_json(data=None):
    # Ab ye sirf "save karna hai" flag set karta hai -> instant return.
    # Asli disk write background loop (users_flush_loop) har 5s me thread me karta hai.
    # Isse har message pe poori file likhne wala block hat jata hai.
    global _users_dirty
    _users_dirty = True

_users_dirty = False

def _write_users_to_disk():
    try:
        tmp = USERS_JSON + ".tmp"
        with open(tmp, "w", encoding="utf-8") as f:
            json.dump(users_db, f, ensure_ascii=False)  # indent hata diya = fast + chhoti file
        os.replace(tmp, USERS_JSON)  # atomic replace -> corruption safe
    except Exception as e:
        logging.error(f"users save error: {e}")

async def users_flush_loop():
    global _users_dirty
    while True:
        await asyncio.sleep(5)
        if _users_dirty:
            _users_dirty = False
            await asyncio.to_thread(_write_users_to_disk)  # disk write event loop ko block nahi karega

users_db = load_users_json()

def get_user_json(user_id, user_name="User", username=None):
    uid = str(user_id)
    now = datetime.now().strftime("%Y-%m-%d %H:%M")
    today = datetime.now().strftime("%Y-%m-%d")
    if uid not in users_db:
        users_db[uid] = {
            "username": username or "",
            "name": user_name,
            "joined_at": now,
            "banned": False,
            "search_data": {"date": today, "count": 0},
            "bonus_searches": 0,
            "premium_until": None,
            "credits": 5,          # FIX: New user ko 10 credits
            "money": 5,
            "daily_last": None,
            "referrals": 0,
            "referred_by": None,
            "used_codes": []
        }
    else:
        defaults = {
            "username": username or users_db[uid].get("username", ""),
            "name": user_name,
            "banned": False,
            "search_data": {"date": today, "count": 0},
            "bonus_searches": 0,
            "premium_until": None,
            "credits": 5,
            "money": 0,
            "daily_last": None,
            "referrals": 0,
            "referred_by": None,
            "used_codes": []
        }
        for k, v in defaults.items():
            if k not in users_db[uid]:
                users_db[uid][k] = v
        if username:
            users_db[uid]["username"] = username
        users_db[uid]["name"] = user_name
    save_users_json(users_db)
    return users_db[uid]

def is_premium(user_id):
    u = users_db.get(str(user_id), {})
    pt = u.get("premium_until")
    if pt is None:
        return False
    try:
        return datetime.strptime(pt, "%Y-%m-%d %H:%M") > datetime.now()
    except:
        return False

def is_banned(user_id):
    return users_db.get(str(user_id), {}).get("banned", False)

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# TELETHON CLIENT
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
telethon_client = TelegramClient(TELETHON_SESSION, TELETHON_API_ID, TELETHON_API_HASH)

async def get_id_from_username(username):
    username = username.strip().lstrip("@")
    try:
        entity = await telethon_client.get_entity(username)
        return entity.id
    except (UsernameNotOccupiedError, UsernameInvalidError):
        return None
    except Exception as e:
        logging.error(f"Telethon error: {e}")
        return None

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# USER STATE
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
user_state = {}
number_results_cache = {}
RECORDS_PER_PAGE = 3

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# KEYBOARDS — Inline style with colors via emoji
# (Telegram ReplyKeyboard me color support nahi, 
#  lekin screenshot jaisi look ke liye emojis use karenge)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# KEYBOARDS — Updated with Telegram's New Button Styles
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
def page1_keyboard(user_id=None):
    kb = [
        [{"text": "📱 NUMBER INFO", "style": "primary"}, {"text": "👤 AADHAR INFO", "style": "primary"}],
        [{"text": "🔍 USERNAME INFO", "style": "primary"}, {"text": "🆔 TG ID INFO", "style": "primary"}],
        [{"text": "🚗 VEHICLE INFO", "style": "primary"}, {"text": "🧾 GST INFO", "style": "primary"}],
        [{"text": "🪪 PAN INFO", "style": "primary"}, {"text": "💰 BALANCE", "style": "success"}],
        [{"text": "➡️ NEXT PAGE", "style": "primary"}]
    ]
    if user_id and user_id in ADMIN_IDS:
        kb.insert(0, [{"text": "🛡️ ADMIN PANEL", "style": "danger"}])
    return {"keyboard": kb, "resize_keyboard": True, "one_time_keyboard": False}

def page2_keyboard():
    return {
        "keyboard": [
            [{"text": "🎁 DAILY CLAIM", "style": "success"}, {"text": "💎 PREMIUM", "style": "primary"}],
            [{"text": "💳 PURCHASE PREMIUM", "style": "primary"}, {"text": "👥 REFERRALS", "style": "success"}],
            [{"text": "🎟️ REDEEM CODE", "style": "primary"}, {"text": "📢 CHANNELS", "style": "primary"}],
            [{"text": "❓ HELP", "style": "primary"}, {"text": "🏠 BACK HOME", "style": "danger"}]
        ],
        "resize_keyboard": True, "one_time_keyboard": False
    }

def number_nav_keyboard(page, total_pages):
    row = [{"text": f"📄 {page} / {total_pages}", "style": "primary"}]
    if page < total_pages:
        row.append({"text": "Next ➡️", "style": "success"})
    return {
        "keyboard": [row, [{"text": "🏠 BACK HOME", "style": "danger"}]],
        "resize_keyboard": True
    }

def admin_keyboard():
    # 🟢 Emojis removed, actual colors applied via 'style'
    return {
        "keyboard": [
            [{"text": "👥 USERS LIST", "style": "primary"}, {"text": "📢 BROADCAST", "style": "primary"}],
            [{"text": "🚫 BAN USER", "style": "danger"}, {"text": "✅ UNBAN USER", "style": "success"}],
            [{"text": "🎟️ GEN REDEEM", "style": "primary"}, {"text": "🔍 SEARCH LIMIT", "style": "primary"}],
            [{"text": "🎁 DAILY LIMIT", "style": "primary"}, {"text": "💎 GIVE PREMIUM", "style": "success"}],
            [{"text": "❌ REMOVE PREMIUM", "style": "danger"}, {"text": "👥 REFERRAL CREDIT", "style": "primary"}],
            [{"text": "🏠 BACK HOME", "style": "danger"}]
        ],
        "resize_keyboard": True, "one_time_keyboard": False
    }


# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# SEND / DELETE HELPERS
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async def send_msg(chat_id, text, reply_markup=None):
    payload = {"chat_id": chat_id, "text": text, "parse_mode": "HTML"}
    if reply_markup:
        payload["reply_markup"] = json.dumps(reply_markup)
    try:
        r = await http.post(f"{API_URL}/sendMessage", json=payload)
        return r.json()
    except Exception as e:
        logging.error(f"send_msg error: {e}")
        return {}

async def delete_msg(chat_id, message_id):
    """Message delete karo"""
    try:
        await http.post(f"{API_URL}/deleteMessage",
            json={"chat_id": chat_id, "message_id": message_id})
    except:
        pass

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# FORCE JOIN — MEMBERSHIP CHECK
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async def is_user_in_channel(channel_id, user_id):
    """Check karo user channel ka member hai ya nahi.
    Bot us channel me ADMIN hona chahiye warna check fail hoga."""
    try:
        r = await http.get(
            f"{API_URL}/getChatMember",
            params={"chat_id": channel_id, "user_id": user_id},
            timeout=15
        )
        data = r.json()
        if not data.get("ok"):
            # Bot channel me admin nahi hai ya channel galat hai
            logging.error(f"getChatMember failed for {channel_id}: {data.get('description')}")
            return False
        status = data.get("result", {}).get("status", "")
        # member, administrator, creator = joined hai
        return status in ("member", "administrator", "creator")
    except Exception as e:
        logging.error(f"Membership check error for {channel_id}: {e}")
        return False

async def get_not_joined_channels(user_id):
    """Un channels ki list do jo user ne abhi join nahi kiye."""
    not_joined = []
    for ch in FORCE_JOIN_CHANNELS:
        joined = await is_user_in_channel(ch["id"], user_id)
        if not joined:
            not_joined.append(ch)
    return not_joined

def force_join_keyboard(channels):
    """Inline keyboard with channel join buttons + verify button."""
    rows = []
    for ch in channels:
        link = ch.get("link")
        if not link and isinstance(ch.get("id"), str) and ch["id"].startswith("@"):
            link = f"https://t.me/{ch['id'].lstrip('@')}"
        rows.append([{"text": f"📢 {ch.get('title', 'Join Channel')}", "url": link}])
    rows.append([{"text": "✅ I'VE JOINED — VERIFY", "callback_data": "check_join"}])
    return {"inline_keyboard": rows}

async def send_force_join_message(chat_id, channels):
    await send_msg(chat_id,
        "<blockquote>"
        "🔒 <b>ACCESS LOCKED</b>\n"
        "━━━━━━━━━━━━━━━━━━\n"
        "Bot use karne ke liye neeche diye gaye "
        "<b>sabhi channels</b> ko join karna zaruri hai.\n\n"
        "Join karne ke baad <b>✅ I'VE JOINED — VERIFY</b> "
        "button dabao.\n"
        "━━━━━━━━━━━━━━━━━━\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER"
        "</blockquote>", force_join_keyboard(channels))

async def check_force_join(chat_id, user_id):
    """True return kare agar user sab channels me hai.
    Warna force-join message bhej kar False return kare.
    Admins ko hamesha allow karo."""
    if user_id in ADMIN_IDS:
        return True
    not_joined = await get_not_joined_channels(user_id)
    if not_joined:
        await send_force_join_message(chat_id, not_joined)
        return False
    return True

async def answer_callback(callback_id, text="", show_alert=False):
    try:
        await http.post(f"{API_URL}/answerCallbackQuery",
            json={"callback_query_id": callback_id, "text": text,
                  "show_alert": show_alert})
    except:
        pass

async def send_document(chat_id, file_path, caption=""):
    with open(file_path, "rb") as f:
        r = await http.post(
            f"{API_URL}/sendDocument",
            data={"chat_id": chat_id, "caption": caption},
            files={"document": f}
        )
        return r.json()

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# FORMAT FUNCTIONS
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
def format_number_page(number, all_records, page, credits_left=None, is_prem=False):
    now = datetime.now().strftime("%d %b %Y %I:%M %p")
    total = len(all_records)
    total_pages = max(1, (total + RECORDS_PER_PAGE - 1) // RECORDS_PER_PAGE)
    start = (page - 1) * RECORDS_PER_PAGE
    end = min(start + RECORDS_PER_PAGE, total)
    page_records = all_records[start:end]
    lines = [
        "📋 <b>MOBILE NUMBER INFO</b>",
        "━━━━━━━━━━━━━━━━━━",
        f"🕐 {now}", f"📱 NUMBER: {number}",
        f"📊 TOTAL RECORDS: <b>{total}</b>",
        "━━━━━━━━━━━━━━━━━━",
    ]
    for i, rec in enumerate(page_records, start=start + 1):
        lines.append(f"👤 <b>RECORD {i}/{total}</b>")
        if rec.get("name"):                lines.append(f"├👤 <b>NAME</b>: {rec['name']}")
        if rec.get("father name"):         lines.append(f"├😊 <b>FATHER</b>: {rec['father name']}")
        if rec.get("mobile"):              lines.append(f"├📱 <b>MOBILE</b>: {rec['mobile']}")
        if rec.get("alternative mobile"):  lines.append(f"├📞 <b>ALT NUMBER</b>: {rec['alternative mobile']}")
        if rec.get("address"):             lines.append(f"├🏠 <b>ADDRESS</b>: {rec['address']}")
        if rec.get("circle/sim"):          lines.append(f"├📡 <b>CIRCLE</b>: {rec['circle/sim']}")
        if rec.get("id number"):           lines.append(f"└🪪 <b>AADHAAR</b>: {rec['id number']}")
        if rec.get("mail") and str(rec.get("mail","")).strip():
            lines.append(f"└📧 <b>EMAIL</b>: {rec['mail']}")
    lines.append("")
    # FIX: Credits info result me hi dikhao
    if is_prem:
        lines.append("💎 <b>PREMIUM:</b> UNLIMITED SEARCHES")
    elif credits_left is not None:
        lines.append(f"💰 <b>CREDITS LEFT: {credits_left}</b>")
    lines += ["👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER", f"📄 PART {page} / {total_pages}"]
    return f"<blockquote>{chr(10).join(lines)}</blockquote>", total_pages

def format_tg_result(data, query_type="username", resolved_username=None,
                     credits_left=None, is_prem=False):
    sources = data.get("data", {})
    records = []
    for src_val in sources.values():
        for rec in src_val.get("records", []):
            records.append(rec)
    target_id = data.get("target_id", "N/A")
    target_username = data.get("target_username") or resolved_username or "N/A"
    title = "🔍 <b>USERNAME INFO</b>" if query_type == "username" else "🆔 <b>TG ID INFO</b>"
    lines = [
        title, "━━━━━━━━━━━━━━━━━━",
        f"👤 <b>USERNAME</b>: @{target_username}",
        f"🆔 <b>TG ID</b>: <code>{target_id}</code>",
        "━━━━━━━━━━━━━━━━━━",
    ]
    if records:
        for i, rec in enumerate(records, 1):
            lines.append(f"📋 <b>RECORD {i}</b>")
            if rec.get("tg_id"):        lines.append(f"├🆔 <b>TG ID</b>: <code>{rec['tg_id']}</code>")
            if rec.get("country"):      lines.append(f"├🌍 <b>COUNTRY</b>: {rec['country']}")
            if rec.get("country_code"): lines.append(f"├📡 <b>COUNTRY CODE</b>: {rec['country_code']}")
            if rec.get("phone"):        lines.append(f"└📱 <b>PHONE</b>: <code>{rec['phone']}</code>")
    else:
        lines.append("❌ No phone records found.")
    lines.append("")
    if is_prem:
        lines.append("💎 <b>PREMIUM:</b> UNLIMITED SEARCHES")
    elif credits_left is not None:
        lines.append(f"💰 <b>CREDITS LEFT: {credits_left}</b>")
    lines.append("👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER")
    return f"<blockquote>{chr(10).join(lines)}</blockquote>"

def format_vehicle_result(data, credits_left=None, is_prem=False):
    now = datetime.now().strftime("%d %b %Y %I:%M %p")
    vd = data.get("vehicle_details", {})
    lines = [
        "🚗 <b>VEHICLE INFO</b>", "━━━━━━━━━━━━━━━━━━",
        f"🕐 {now}", f"🔢 <b>REG NUMBER</b>: {data.get('vehicle_number','N/A')}",
        "━━━━━━━━━━━━━━━━━━",
    ]
    if vd.get("owner_name"):              lines.append(f"├👤 <b>OWNER NAME</b>: {vd['owner_name']}")
    if vd.get("father_name"):             lines.append(f"├😊 <b>FATHER NAME</b>: {vd['father_name']}")
    if data.get("mobile_found") and data.get("mobile_number"):
        lines.append(f"├📱 <b>MOBILE</b>: {data['mobile_number']}")
    if vd.get("owner_serial_no"):         lines.append(f"├🔢 <b>OWNER NO</b>: {vd['owner_serial_no']}")
    if vd.get("maker"):                   lines.append(f"├🏭 <b>MAKER</b>: {vd['maker']}")
    if vd.get("model"):                   lines.append(f"├🚘 <b>MODEL</b>: {vd['model']}")
    if vd.get("vehicle_class"):           lines.append(f"├🏷️ <b>CLASS</b>: {vd['vehicle_class']}")
    if vd.get("vehicle_color"):           lines.append(f"├🎨 <b>COLOR</b>: {vd['vehicle_color']}")
    if vd.get("fuel_type"):               lines.append(f"├⛽ <b>FUEL</b>: {vd['fuel_type']}")
    if vd.get("engine_number"):           lines.append(f"├🔧 <b>ENGINE NO</b>: {vd['engine_number']}")
    if vd.get("chassis_number"):          lines.append(f"├🔩 <b>CHASSIS NO</b>: {vd['chassis_number']}")
    if vd.get("registration_date"):       lines.append(f"├📅 <b>REG DATE</b>: {vd['registration_date']}")
    if vd.get("rto"):                     lines.append(f"├🏢 <b>RTO</b>: {vd['rto']}")
    if vd.get("insurance_company"):       lines.append(f"├🛡️ <b>INSURANCE</b>: {vd['insurance_company']}")
    if vd.get("insurance_upto"):          lines.append(f"├📆 <b>INS UPTO</b>: {vd['insurance_upto']}")
    if vd.get("insurance_expiry_status"): lines.append(f"├⚠️ <b>INS STATUS</b>: {vd['insurance_expiry_status']}")
    if vd.get("fitness_upto"):            lines.append(f"├🔍 <b>FITNESS UPTO</b>: {vd['fitness_upto']}")
    if vd.get("tax_upto"):                lines.append(f"├💰 <b>TAX UPTO</b>: {vd['tax_upto']}")
    if vd.get("puc_upto"):                lines.append(f"├🌿 <b>PUC UPTO</b>: {vd['puc_upto']}")
    if vd.get("puc_expiry_status"):       lines.append(f"├⚠️ <b>PUC STATUS</b>: {vd['puc_expiry_status']}")
    if vd.get("vehicle_age"):             lines.append(f"└🕰️ <b>VEHICLE AGE</b>: {vd['vehicle_age']}")
    lines.append("")
    if is_prem:
        lines.append("💎 <b>PREMIUM:</b> UNLIMITED SEARCHES")
    elif credits_left is not None:
        lines.append(f"💰 <b>CREDITS LEFT: {credits_left}</b>")
    lines.append("👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER")
    return f"<blockquote>{chr(10).join(lines)}</blockquote>"

def format_gst_result(data, credits_left=None, is_prem=False):
    now = datetime.now().strftime("%d %b %Y %I:%M %p")
    d = data.get("data", {})
    bi = d.get("business_info", {})
    addr = d.get("address", {})
    nob = d.get("nature_of_business", [])
    lines = [
        "🧾 <b>GST INFO</b>", "━━━━━━━━━━━━━━━━━━",
        f"🕐 {now}", f"🔢 <b>GST NUMBER</b>: {d.get('gst_number','N/A')}",
        "━━━━━━━━━━━━━━━━━━",
    ]
    if bi.get("legal_name"):        lines.append(f"├👤 <b>LEGAL NAME</b>: {bi['legal_name']}")
    if bi.get("trade_name"):        lines.append(f"├🏪 <b>TRADE NAME</b>: {bi['trade_name']}")
    if d.get("pan_number"):         lines.append(f"├🪪 <b>PAN</b>: {d['pan_number']}")
    if bi.get("constitution"):      lines.append(f"├🏢 <b>CONSTITUTION</b>: {bi['constitution']}")
    if bi.get("taxpayer_type"):     lines.append(f"├📋 <b>TAXPAYER TYPE</b>: {bi['taxpayer_type']}")
    if bi.get("status"):            lines.append(f"├✅ <b>STATUS</b>: {bi['status']}")
    if bi.get("registration_date"): lines.append(f"├📅 <b>REG DATE</b>: {bi['registration_date']}")
    if bi.get("cancellation_date") and bi["cancellation_date"].strip():
        lines.append(f"├❌ <b>CANCEL DATE</b>: {bi['cancellation_date']}")
    addr_parts = [addr.get("bno",""), addr.get("flno",""), addr.get("st",""),
                  addr.get("loc",""), addr.get("dst",""), addr.get("stcd",""), addr.get("pncd","")]
    full_addr = ", ".join(p for p in addr_parts if p.strip())
    if full_addr: lines.append(f"├🏠 <b>ADDRESS</b>: {full_addr}")
    if nob:       lines.append(f"└🏭 <b>BUSINESS TYPE</b>: {', '.join(nob)}")
    lines.append("")
    if is_prem:
        lines.append("💎 <b>PREMIUM:</b> UNLIMITED SEARCHES")
    elif credits_left is not None:
        lines.append(f"💰 <b>CREDITS LEFT: {credits_left}</b>")
    lines.append("👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER")
    return f"<blockquote>{chr(10).join(lines)}</blockquote>"

def format_pan_result(data, credits_left=None, is_prem=False):
    now = datetime.now().strftime("%d %b %Y %I:%M %p")
    items = data.get("items", [])
    pan = data.get("pan", "N/A")
    lines = [
        "🪪 <b>PAN INFO</b>", "━━━━━━━━━━━━━━━━━━",
        f"🕐 {now}", f"🔢 <b>PAN NUMBER</b>: {pan}",
        f"📊 <b>TOTAL RECORDS</b>: {data.get('count',0)}",
        "━━━━━━━━━━━━━━━━━━",
    ]
    if items:
        for i, item in enumerate(items, 1):
            lines.append(f"📋 <b>RECORD {i}</b>")
            if item.get("gstin"):       lines.append(f"├🧾 <b>GSTIN</b>: {item['gstin']}")
            if item.get("state"):       lines.append(f"├🗺️ <b>STATE</b>: {item['state']}")
            if item.get("auth_status"): lines.append(f"└✅ <b>AUTH STATUS</b>: {item['auth_status']}")
    else:
        lines.append("❌ No records found.")
    lines.append("")
    if is_prem:
        lines.append("💎 <b>PREMIUM:</b> UNLIMITED SEARCHES")
    elif credits_left is not None:
        lines.append(f"💰 <b>CREDITS LEFT: {credits_left}</b>")
    lines.append("👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER")
    return f"<blockquote>{chr(10).join(lines)}</blockquote>"

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# API CALLS
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async def api_number_lookup(number):
    url = NUMBER_API_URL.format(key=NUMBER_API_KEY, number=number)
    return (await http.get(url, timeout=15)).json()

async def api_username_lookup(tg_id):
    url = USERNAME_API_URL.format(key=USERNAME_API_KEY, id=tg_id)
    return (await http.get(url, timeout=15)).json()

async def api_tgid_lookup(tg_id):
    url = TGID_API_URL.format(key=TGID_API_KEY, id=tg_id)
    return (await http.get(url, timeout=15)).json()

async def api_vehicle_lookup(rc):
    url = VEHICLE_API_URL.format(key=VEHICLE_API_KEY, rc=rc)
    return (await http.get(url, timeout=15)).json()

async def api_gst_lookup(gst):
    url = GST_API_URL.format(key=GST_API_KEY, gst=gst)
    return (await http.get(url, timeout=15)).json()

async def api_pan_lookup(pan):
    url = PAN_API_URL.format(key=PAN_API_KEY, pan=pan)
    return (await http.get(url, timeout=15)).json()

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# SEARCH LIMIT HELPERS — FIX: Proper credit deduction
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
def can_search(user_id):
    """Premium users ko unlimited, free users ko limit check karo"""
    if is_premium(user_id):
        return True, ""
    u = users_db.get(str(user_id), {})
    today = datetime.now().strftime("%Y-%m-%d")
    sd = u.get("search_data", {"date": today, "count": 0})
    if sd.get("date") != today:
        sd = {"date": today, "count": 0}
        users_db[str(user_id)]["search_data"] = sd
    free_limit = settings.get("daily_free_search_limit", 5)
    credits = u.get("credits", 0)
    bonus = u.get("bonus_searches", 0)
    used_today = sd["count"]
    # Free searches pehle, phir bonus, phir credits
    if used_today < free_limit + bonus:
        return True, ""
    elif credits > 0:
        return True, ""
    else:
        return False, f"❌ <b>Searches khatam!</b>\n💰 Credits: {credits} | 🎁 Daily limit: {free_limit}\n\n🎟️ Use Redeem code Or Get 💳 Premium!"

def consume_search(user_id):
    """FIX: Sahi tarike se credit deduct karo"""
    if is_premium(user_id):
        return 0  # Premium = no deduction
    uid = str(user_id)
    today = datetime.now().strftime("%Y-%m-%d")
    sd = users_db[uid].get("search_data", {"date": today, "count": 0})
    if sd.get("date") != today:
        sd = {"date": today, "count": 0}
    sd["count"] += 1
    users_db[uid]["search_data"] = sd

    free_limit = settings.get("daily_free_search_limit", 5)
    bonus = users_db[uid].get("bonus_searches", 0)
    # Agar free + bonus searches khatam ho gayi to credit deduct karo
    if sd["count"] > (free_limit + bonus):
        prev = users_db[uid].get("credits", 0)
        users_db[uid]["credits"] = max(0, prev - 1)

    save_users_json(users_db)
    return users_db[uid].get("credits", 0)

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# ADMIN PANEL HANDLERS
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async def handle_admin_panel(chat_id, user_id):
    total = len(users_db)
    premium_count = sum(1 for uid in users_db if is_premium(int(uid)))
    banned_count = sum(1 for u in users_db.values() if u.get("banned"))
    await send_msg(chat_id,
        "<blockquote>"
        "🛡️ <b>ADMIN PANEL</b>\n"
        "━━━━━━━━━━��━━━━━━━\n"
        f"👥 <b>TOTAL USERS:</b> {total}\n"
        f"💎 <b>PREMIUM USERS:</b> {premium_count}\n"
        f"🚫 <b>BANNED USERS:</b> {banned_count}\n"
        f"🔍 <b>FREE SEARCH LIMIT:</b> {settings.get('daily_free_search_limit', 5)}/day\n"
        f"🎁 <b>DAILY CLAIM:</b> +{settings.get('daily_claim_credits', 2)} credits\n"
        f"👥 <b>REFERRAL CREDIT:</b> +{settings.get('referral_credits', 5)} credits\n"
        "━━━━━━━━━━━━━━━━━━\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER"
        "</blockquote>", admin_keyboard())

async def handle_admin_users_list(chat_id):
    lines = ["=" * 50, "MJ SARKAR BOT — USERS LIST",
             f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
             f"Total Users: {len(users_db)}", "=" * 50, ""]
    for uid, u in users_db.items():
        prem = "YES" if is_premium(int(uid)) else "NO"
        banned = "YES" if u.get("banned") else "NO"
        lines += [
            f"ID       : {uid}",
            f"Name     : {u.get('name','N/A')}",
            f"Username : @{u.get('username','N/A')}",
            f"Joined   : {u.get('joined_at','N/A')}",
            f"Credits  : {u.get('credits', 0)}",
            f"Premium  : {prem} (Until: {u.get('premium_until','N/A')})",
            f"Banned   : {banned}",
            f"Searches : {u.get('search_data',{}).get('count',0)} today",
            "-" * 40
        ]
    txt_path = "users_export.txt"
    with open(txt_path, "w", encoding="utf-8") as f:
        f.write("\n".join(lines))
    await send_document(chat_id, txt_path, caption=f"👥 <b>Users List</b>\nTotal: {len(users_db)} users")

async def handle_broadcast(chat_id, user_id):
    user_state[user_id] = "awaiting_broadcast"
    await send_msg(chat_id,
        "<blockquote>📢 <b>BROADCAST</b>\n\nWoh message type karo jo sab users ko bhejna hai.\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

async def process_broadcast(chat_id, user_id, text):
    user_state[user_id] = None
    # Turant confirm bhejo, phir broadcast background me chalega.
    # Isse broadcast ke dauraan baaki sab users ko normal reply milta rahega.
    await send_msg(chat_id,
        f"<blockquote>⏳ <b>Broadcasting...</b>\n{len(users_db)} users ko background me ja raha hai...</blockquote>")
    asyncio.create_task(_run_broadcast(chat_id, text))

async def _run_broadcast(chat_id, text):
    msg = (f"<blockquote>📢 <b>BROADCAST MESSAGE</b>\n━━━━━━━━━━━━━━━━━━\n"
           f"{text}\n━━━━━━━━━━━━━━━━━━\n"
           f"👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
    success = fail = 0
    uids = list(users_db.keys())
    BATCH = 25  # ek saath 25 users (Telegram safe ~30/sec)

    async def _one(uid):
        nonlocal success, fail
        try:
            await send_msg(int(uid), msg)
            success += 1
        except:
            fail += 1

    # Batch-wise parallel bhejo -> tez aur rate-limit safe
    for i in range(0, len(uids), BATCH):
        batch = uids[i:i + BATCH]
        await asyncio.gather(*[_one(u) for u in batch])
        await asyncio.sleep(1)  # har batch ke beech safe gap

    await send_msg(chat_id,
        f"<blockquote>✅ <b>Broadcast Done!</b>\n✅ Sent: {success}\n❌ Failed: {fail}\n\n"
        f"👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>", admin_keyboard())

async def handle_ban_user(chat_id, user_id):
    user_state[user_id] = "awaiting_ban_id"
    await send_msg(chat_id,
        "<blockquote>🚫 <b>BAN USER</b>\n\nUser ka Telegram ID bhejo.\nEXAMPLE: 123456789\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

async def process_ban_user(chat_id, user_id, target_id_str):
    target_id_str = target_id_str.strip()
    if not target_id_str.isdigit():
        await send_msg(chat_id, "<blockquote>❌ Give Numeric ID!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    tid = target_id_str
    if tid not in users_db:
        await send_msg(chat_id, "<blockquote>❌ User Not Found!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    users_db[tid]["banned"] = True
    save_users_json(users_db)
    uname = users_db[tid].get("name", "N/A")
    user_state[user_id] = None
    await send_msg(chat_id,
        f"<blockquote>🚫 <b>User Banned!</b>\n👤 Name: {uname}\n🆔 ID: {tid}\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>", admin_keyboard())
    try:
        await send_msg(int(tid),
            "<blockquote>🚫 <b>You have been BANNED!</b>\nContact: @MJ_SARKAR_OWNER</blockquote>")
    except: pass

async def handle_unban_user(chat_id, user_id):
    user_state[user_id] = "awaiting_unban_id"
    await send_msg(chat_id,
        "<blockquote>✅ <b>UNBAN USER</b>\n\nUser ka Telegram ID bhejo.\nEXAMPLE: 123456789\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

async def process_unban_user(chat_id, user_id, target_id_str):
    target_id_str = target_id_str.strip()
    if not target_id_str.isdigit():
        await send_msg(chat_id, "<blockquote>❌ Invalid ID!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    tid = target_id_str
    if tid not in users_db:
        await send_msg(chat_id, "<blockquote>❌ User Not Found!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    users_db[tid]["banned"] = False
    save_users_json(users_db)
    uname = users_db[tid].get("name", "N/A")
    user_state[user_id] = None
    await send_msg(chat_id,
        f"<blockquote>✅ <b>User Unbanned!</b>\n👤 Name: {uname}\n🆔 ID: {tid}\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>", admin_keyboard())
    try:
        await send_msg(int(tid),
            "<blockquote>✅ <b>You have been UNBANNED!</b>\nAb aap bot use kar sakte ho.\n\n"
            "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
    except: pass

async def handle_gen_redeem(chat_id, user_id):
    user_state[user_id] = "awaiting_redeem_gen"
    await send_msg(chat_id,
        "<blockquote>🎟️ <b>GENERATE REDEEM CODE</b>\n\n"
        "Format: <code>CREDITS:AMOUNT</code> ya sirf <code>AMOUNT</code>\n\n"
        "EXAMPLE:\n• <code>10</code> → Random code with 10 credits\n"
        "• <code>MYCODE25:25</code> → Custom code with 25 credits\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

async def process_gen_redeem(chat_id, user_id, text):
    text = text.strip().upper()
    if ":" in text:
        parts = text.split(":", 1)
        code = parts[0].strip()
        try:
            credits = int(parts[1].strip())
        except:
            await send_msg(chat_id, "<blockquote>❌ Invalid format!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
            user_state[user_id] = None; return
    else:
        try:
            credits = int(text)
        except:
            await send_msg(chat_id, "<blockquote>❌ Give Number Or CODE:CREDITS format!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
            user_state[user_id] = None; return
        code = "MJ" + ''.join(random.choices(string.ascii_uppercase + string.digits, k=6))
    settings["redeem_codes"][code] = credits
    save_settings(settings)
    user_state[user_id] = None
    await send_msg(chat_id,
        f"<blockquote>✅ <b>Redeem Code Generated!</b>\n\n"
        f"🎟️ <b>CODE:</b> <code>{code}</code>\n"
        f"💎 <b>CREDITS:</b> {credits}\n\n"
        f"👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>", admin_keyboard())

async def handle_set_search_limit(chat_id, user_id):
    user_state[user_id] = "awaiting_search_limit"
    current = settings.get("daily_free_search_limit", 5)
    await send_msg(chat_id,
        f"<blockquote>🔍 <b>FREE SEARCH LIMIT</b>\n\nCurrent: <b>{current}</b>/day\n\n"
        f"Naya number bhejo:\nEXAMPLE: <code>10</code>\n\n"
        f"👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

async def process_search_limit(chat_id, user_id, text):
    text = text.strip()
    if not text.isdigit() or int(text) < 0:
        await send_msg(chat_id, "<blockquote>❌ Enter Valid number!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    settings["daily_free_search_limit"] = int(text)
    save_settings(settings)
    user_state[user_id] = None
    await send_msg(chat_id,
        f"<blockquote>✅ <b>Search Limit Updated!</b>\n🔍 New Limit: <b>{text}</b>/day\n\n"
        f"👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>", admin_keyboard())

async def handle_set_daily_claim(chat_id, user_id):
    user_state[user_id] = "awaiting_daily_claim_limit"
    current = settings.get("daily_claim_credits", 2)
    await send_msg(chat_id,
        f"<blockquote>🎁 <b>DAILY CLAIM LIMIT</b>\n\nCurrent: <b>+{current}</b> credits\n\n"
        f"Naya amount bhejo:\nEXAMPLE: <code>5</code>\n\n"
        f"👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

async def process_daily_claim_limit(chat_id, user_id, text):
    text = text.strip()
    if not text.isdigit() or int(text) < 0:
        await send_msg(chat_id, "<blockquote>❌ Enter Valid number!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    settings["daily_claim_credits"] = int(text)
    save_settings(settings)
    user_state[user_id] = None
    await send_msg(chat_id,
        f"<blockquote>✅ <b>Daily Claim Updated!</b>\n🎁 New Claim: <b>+{text}</b> credits\n\n"
        f"👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>", admin_keyboard())

# FIX: Referral credit set karne ka handler
async def handle_set_referral_credit(chat_id, user_id):
    user_state[user_id] = "awaiting_referral_credit"
    current = settings.get("referral_credits", 5)
    await send_msg(chat_id,
        f"<blockquote>👥 <b>REFERRAL CREDIT LIMIT</b>\n\nCurrent: <b>+{current}</b> credits per referral\n\n"
        f"Naya amount bhejo:\nEXAMPLE: <code>10</code>\n\n"
        f"👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

async def process_referral_credit(chat_id, user_id, text):
    text = text.strip()
    if not text.isdigit() or int(text) < 0:
        await send_msg(chat_id, "<blockquote>❌ Enter Valid number!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    settings["referral_credits"] = int(text)
    save_settings(settings)
    user_state[user_id] = None
    await send_msg(chat_id,
        f"<blockquote>✅ <b>Referral Credit Updated!</b>\n👥 Now: <b>+{text}</b> credits per referral\n\n"
        f"👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>", admin_keyboard())

async def handle_give_premium(chat_id, user_id):
    user_state[user_id] = "awaiting_give_premium_id"
    await send_msg(chat_id,
        "<blockquote>💎 <b>GIVE PREMIUM</b>\n\nFormat: <code>USER_ID:DAYS</code>\n\n"
        "EXAMPLE:\n• <code>123456789:30</code> → 30 din ka premium\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

async def process_give_premium(chat_id, user_id, text):
    text = text.strip()
    if ":" not in text:
        await send_msg(chat_id, "<blockquote>❌ Format: <code>USER_ID:DAYS</code>\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    parts = text.split(":", 1)
    tid = parts[0].strip()
    try:
        days = int(parts[1].strip())
    except:
        await send_msg(chat_id, "<blockquote>❌ Days valid number hona chahiye!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    if tid not in users_db:
        await send_msg(chat_id, "<blockquote>❌ User Not Found!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    until = (datetime.now() + timedelta(days=days)).strftime("%Y-%m-%d %H:%M")
    users_db[tid]["premium_until"] = until
    save_users_json(users_db)
    uname = users_db[tid].get("name", "N/A")
    user_state[user_id] = None
    await send_msg(chat_id,
        f"<blockquote>💎 <b>Premium Diya!</b>\n👤 Name: {uname}\n🆔 ID: {tid}\n"
        f"📅 Until: {until}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>", admin_keyboard())
    try:
        await send_msg(int(tid),
            f"<blockquote>💎 <b>PREMIUM ACTIVATED!</b>\n✨ Aapko {days} din ka premium mila!\n"
            f"📅 Valid Until: {until}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
    except: pass

async def handle_remove_premium(chat_id, user_id):
    user_state[user_id] = "awaiting_remove_premium_id"
    prem_users = [(uid, u) for uid, u in users_db.items() if is_premium(int(uid))]
    if not prem_users:
        await send_msg(chat_id,
            "<blockquote>❌ No Premium User Found!!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    lines = ["💎 <b>PREMIUM USERS</b>", "━━━━━━━━━━━━━━━━━━"]
    for uid, u in prem_users:
        lines.append(f"🆔 <code>{uid}</code> — {u.get('name','N/A')} (Until: {u.get('premium_until','N/A')})")
    lines += ["━━━━━━━━━━━━━━━━━━", "User ID bhejo premium remove karne ke liye:",
              "EXAMPLE: <code>123456789</code>", "", "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER"]
    await send_msg(chat_id, f"<blockquote>{chr(10).join(lines)}</blockquote>")

async def process_remove_premium(chat_id, user_id, target_id_str):
    target_id_str = target_id_str.strip()
    if not target_id_str.isdigit():
        await send_msg(chat_id, "<blockquote>❌ Invalid ID!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    tid = target_id_str
    if tid not in users_db:
        await send_msg(chat_id, "<blockquote>❌ User Not Found!\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = None; return
    users_db[tid]["premium_until"] = None
    save_users_json(users_db)
    uname = users_db[tid].get("name", "N/A")
    user_state[user_id] = None
    await send_msg(chat_id,
        f"<blockquote>✅ <b>Premium Removed!</b>\n👤 Name: {uname}\n🆔 ID: {tid}\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>", admin_keyboard())
    try:
        await send_msg(int(tid),
            "<blockquote>⚠️ <b>Premium Expire!</b>\nAapka premium remove ho gaya.\n"
            "Contact: @MJ_SARKAR_OWNER</blockquote>")
    except: pass

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# USER HANDLERS
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━��━━━━
async def handle_start(chat_id, user_id, user_name, username=None, ref=None):
    u = get_user_json(user_id, user_name, username)
    # FIX: Referral credit settings se lo
    ref_credits = settings.get("referral_credits", 5)
    if ref and ref != str(user_id) and u["referred_by"] is None:
        try:
            ref_id = int(ref)
            u["referred_by"] = ref_id
            users_db[str(user_id)]["referred_by"] = ref_id
            if str(ref_id) in users_db:
                users_db[str(ref_id)]["credits"] = users_db[str(ref_id)].get("credits", 0) + ref_credits
                users_db[str(ref_id)]["referrals"] = users_db[str(ref_id)].get("referrals", 0) + 1
                save_users_json(users_db)
                await send_msg(ref_id, f"🎉 <b>New Referral!</b>\n+{ref_credits} credits added!")
        except: pass
    premium_status = "UNLIMITED" if is_premium(user_id) else "FREE"
    credits = users_db[str(user_id)].get("credits", 0)
    daily_credits = settings.get("daily_claim_credits", 2)
    msg = (
        "<blockquote>"
        "⭐ <b>WELCOME TO MJ SARKAR BOT</b> ⭐\n"
        f"🚀 <b>HELLO</b> {user_name}!\n\n"
        "<b>WELCOME TO MJ SARKAR BOT!</b>\n\n"
        f"💰 <b>CREDITS :</b> {credits}\n"
        f"🎁 <b>DAILY :</b> +{daily_credits}\n"
        f"💎 <b>PREMIUM :</b> {premium_status}\n\n"
        "―――――――――――――――――\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER"
        "</blockquote>"
    )
    user_state[user_id] = None
    await send_msg(chat_id, msg, page1_keyboard(user_id))

async def prompt(chat_id, user_id, state, title, example):
    user_state[user_id] = state
    await send_msg(chat_id,
        f"<blockquote>{title}\nEXAMPLE: {example}\n\n"
        f"👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# INPUT PROCESSORS — FIX: Auto-delete searching msg + credits in result
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async def process_number(chat_id, user_id, number):
    number = number.strip().replace(" ", "").replace("-", "")
    if not number.isdigit() or len(number) != 10:
        await send_msg(chat_id,
            "<blockquote>❌ <b>Invalid Number!</b>\nSent a 10-digit mobile number.\n"
            "EXAMPLE: 9876543210\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = "awaiting_number"; return
    ok, msg = can_search(user_id)
    if not ok:
        await send_msg(chat_id, f"<blockquote>{msg}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    # FIX: Searching message bhejo aur message_id store karo
    search_resp = await send_msg(chat_id,
        "<blockquote>⏳ <b>Searching...</b>\nPlease wait...\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
    search_msg_id = search_resp.get("result", {}).get("message_id")

    try:
        data = await api_number_lookup(number)
    except Exception as e:
        # Delete searching message on error
        if search_msg_id:
            await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            f"<blockquote>❌ <b>API Error!</b>\n{e}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    records = [data[k] for k in sorted(data.keys()) if k.isdigit()]
    if not records:
        if search_msg_id:
            await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            "<blockquote>❌ <b>No Records Found!</b>\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    credits_left = consume_search(user_id)
    prem = is_premium(user_id)
    number_results_cache[user_id] = {"records": records, "page": 1, "number": number}
    user_state[user_id] = "viewing_number_results"
    text, total_pages = format_number_page(number, records, 1,
                                           credits_left=credits_left if not prem else None,
                                           is_prem=prem)
    # FIX: Searching message delete karo result aane se pehle
    if search_msg_id:
        await delete_msg(chat_id, search_msg_id)
    await send_msg(chat_id, text, number_nav_keyboard(1, total_pages))

async def process_next_page(chat_id, user_id):
    cache = number_results_cache.get(user_id)
    if not cache: return
    cache["page"] += 1
    prem = is_premium(user_id)
    credits_left = users_db.get(str(user_id), {}).get("credits", 0)
    text, total_pages = format_number_page(cache["number"], cache["records"], cache["page"],
                                           credits_left=credits_left if not prem else None,
                                           is_prem=prem)
    await send_msg(chat_id, text, number_nav_keyboard(cache["page"], total_pages))

async def process_username(chat_id, user_id, username):
    ok, msg = can_search(user_id)
    if not ok:
        await send_msg(chat_id, f"<blockquote>{msg}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return
    username = username.strip().lstrip("@")
    search_resp = await send_msg(chat_id,
        "<blockquote>⏳ <b>Searching...</b>\nResolving @" + username + "...\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
    search_msg_id = search_resp.get("result", {}).get("message_id")

    tg_id = await get_id_from_username(username)
    if not tg_id:
        if search_msg_id: await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            f"<blockquote>❌ <b>Username Not Found!</b>\n@{username} hasn't been resolved.\n\n"
            "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return
    try:
        data = await api_username_lookup(tg_id)
    except Exception as e:
        if search_msg_id: await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            f"<blockquote>❌ <b>API Error!</b>\n{e}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return
    if not data.get("status"):
        if search_msg_id: await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            f"<blockquote>❌ <b>No Records Found!</b>\nNo data for @{username}\n\n"
            "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    credits_left = consume_search(user_id)
    prem = is_premium(user_id)
    result = format_tg_result(data, "username", username,
                              credits_left=credits_left if not prem else None,
                              is_prem=prem)
    if search_msg_id: await delete_msg(chat_id, search_msg_id)
    await send_msg(chat_id, result)

async def process_tgid(chat_id, user_id, tg_id_input):
    tg_id_input = tg_id_input.strip()
    if not tg_id_input.isdigit():
        await send_msg(chat_id,
            "<blockquote>❌ <b>Invalid ID!</b>\nSend A Numeric Telegram ID.\n"
            "EXAMPLE: 6443754454\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
        user_state[user_id] = "awaiting_tgid"; return
    ok, msg = can_search(user_id)
    if not ok:
        await send_msg(chat_id, f"<blockquote>{msg}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    search_resp = await send_msg(chat_id,
        "<blockquote>⏳ <b>Searching...</b>\nPlease wait...\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
    search_msg_id = search_resp.get("result", {}).get("message_id")

    try:
        data = await api_tgid_lookup(tg_id_input)
    except Exception as e:
        if search_msg_id: await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            f"<blockquote>❌ <b>API Error!</b>\n{e}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return
    if not data.get("status"):
        if search_msg_id: await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            "<blockquote>❌ <b>No Records Found!</b>\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    credits_left = consume_search(user_id)
    prem = is_premium(user_id)
    result = format_tg_result(data, "tgid",
                              credits_left=credits_left if not prem else None,
                              is_prem=prem)
    if search_msg_id: await delete_msg(chat_id, search_msg_id)
    await send_msg(chat_id, result)

async def process_vehicle(chat_id, user_id, rc):
    rc = rc.strip().upper().replace(" ", "")
    ok, msg = can_search(user_id)
    if not ok:
        await send_msg(chat_id, f"<blockquote>{msg}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    search_resp = await send_msg(chat_id,
        "<blockquote>⏳ <b>Searching...</b>\nPlease wait...\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
    search_msg_id = search_resp.get("result", {}).get("message_id")

    try:
        data = await api_vehicle_lookup(rc)
    except Exception as e:
        if search_msg_id: await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            f"<blockquote>❌ <b>API Error!</b>\n{e}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return
    if not data.get("success"):
        if search_msg_id: await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            "<blockquote>❌ <b>No Records Found!</b>\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    credits_left = consume_search(user_id)
    prem = is_premium(user_id)
    result = format_vehicle_result(data,
                                   credits_left=credits_left if not prem else None,
                                   is_prem=prem)
    if search_msg_id: await delete_msg(chat_id, search_msg_id)
    await send_msg(chat_id, result)

async def process_gst(chat_id, user_id, gst):
    gst = gst.strip().upper()
    ok, msg = can_search(user_id)
    if not ok:
        await send_msg(chat_id, f"<blockquote>{msg}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    search_resp = await send_msg(chat_id,
        "<blockquote>⏳ <b>Searching...</b>\nPlease wait...\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
    search_msg_id = search_resp.get("result", {}).get("message_id")

    try:
        data = await api_gst_lookup(gst)
    except Exception as e:
        if search_msg_id: await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            f"<blockquote>❌ <b>API Error!</b>\n{e}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return
    if not data.get("success"):
        if search_msg_id: await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            "<blockquote>❌ <b>No Records Found!</b>\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    credits_left = consume_search(user_id)
    prem = is_premium(user_id)
    result = format_gst_result(data,
                               credits_left=credits_left if not prem else None,
                               is_prem=prem)
    if search_msg_id: await delete_msg(chat_id, search_msg_id)
    await send_msg(chat_id, result)

async def process_pan(chat_id, user_id, pan):
    pan = pan.strip().upper()
    ok, msg = can_search(user_id)
    if not ok:
        await send_msg(chat_id, f"<blockquote>{msg}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    search_resp = await send_msg(chat_id,
        "<blockquote>⏳ <b>Searching...</b>\nPlease wait...\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
    search_msg_id = search_resp.get("result", {}).get("message_id")

    try:
        data = await api_pan_lookup(pan)
    except Exception as e:
        if search_msg_id: await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            f"<blockquote>❌ <b>API Error!</b>\n{e}\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return
    if not data.get("items"):
        if search_msg_id: await delete_msg(chat_id, search_msg_id)
        await send_msg(chat_id,
            "<blockquote>❌ <b>No Records Found!</b>\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    credits_left = consume_search(user_id)
    prem = is_premium(user_id)
    result = format_pan_result(data,
                               credits_left=credits_left if not prem else None,
                               is_prem=prem)
    if search_msg_id: await delete_msg(chat_id, search_msg_id)
    await send_msg(chat_id, result)

async def process_redeem(chat_id, user_id, code):
    get_user_json(user_id)
    code = code.strip().upper()
    used = users_db[str(user_id)].get("used_codes", [])
    all_codes = settings.get("redeem_codes", {})
    if code in used:
        await send_msg(chat_id,
            "<blockquote>❌ <b>Already Used!</b>\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
    elif code in all_codes:
        credits = all_codes[code]
        users_db[str(user_id)]["credits"] = users_db[str(user_id)].get("credits", 0) + credits
        used.append(code)
        users_db[str(user_id)]["used_codes"] = used
        save_users_json(users_db)
        new_bal = users_db[str(user_id)]["credits"]
        await send_msg(chat_id,
            f"<blockquote>✅ <b>Code Redeemed!</b>\n+{credits} Credits Added!\n"
            f"💎 <b>NEW BALANCE:</b> {new_bal}\n\n"
            "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
    else:
        await send_msg(chat_id,
            "<blockquote>❌ <b>Invalid Code!</b>\n\n👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")
    user_state[user_id] = None

async def handle_balance(chat_id, user_id):
    get_user_json(user_id)
    uid = str(user_id)
    credits = users_db[uid].get("credits", 0)
    money = users_db[uid].get("money", 0)
    referrals = users_db[uid].get("referrals", 0)
    used_c = len(users_db[uid].get("used_codes", []))
    free_limit = settings.get("daily_free_search_limit", 5)
    ref_credits = settings.get("referral_credits", 5)
    await send_msg(chat_id,
        "<blockquote>💰 <b>BALANCE</b>\n"
        f"₹ <b>MONEY:</b> ₹{money}\n"
        f"💎 <b>CREDITS:</b> {credits}\n\n"
        "📊 <b>CREDIT BREAKDOWN:</b>\n"
        f"├👥 REFERRAL CREDITS: +{referrals*ref_credits} ({referrals} REFS)\n"
        f"├🎁 DAILY BONUS: +{settings.get('daily_claim_credits',2)} CREDITS\n"
        f"├🔍 FREE SEARCHES: {free_limit}/day\n"
        f"└🎟️ REDEEM CODES USED: {used_c}\n\n"
        "📣 <b>EARN MORE:</b>\n"
        f"🎁 DAILY: +{settings.get('daily_claim_credits',2)}  👥 REFER: +{ref_credits}\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

async def handle_daily_claim(chat_id, user_id, user_name):
    get_user_json(user_id, user_name)
    uid = str(user_id)
    now = datetime.now()
    last_str = users_db[uid].get("daily_last")
    claim_credits = settings.get("daily_claim_credits", 2)
    if last_str:
        try:
            last = datetime.strptime(last_str, "%Y-%m-%d %H:%M")
            if (now - last).total_seconds() < 86400:
                remaining = timedelta(seconds=86400) - (now - last)
                hrs = int(remaining.total_seconds() // 3600)
                mins = int((remaining.total_seconds() % 3600) // 60)
                await send_msg(chat_id,
                    f"<blockquote>⏳ <b>Already Claimed!</b>\n"
                    f"Come back in <b>{hrs}h {mins}m</b>\n\n"
                    "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return
        except: pass
    users_db[uid]["credits"] = users_db[uid].get("credits", 0) + claim_credits
    users_db[uid]["daily_last"] = now.strftime("%Y-%m-%d %H:%M")
    save_users_json(users_db)
    await send_msg(chat_id,
        f"<blockquote>🎁 <b>DAILY CLAIM SUCCESSFUL!</b>\n"
        f"✅ +{claim_credits} Credits Added!\n"
        f"💎 <b>NEW BALANCE:</b> {users_db[uid]['credits']} credits\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

async def handle_premium(chat_id, user_id):
    prem = is_premium(user_id)
    status = "✅ ACTIVE" if prem else "❌ NOT ACTIVE"
    until = users_db.get(str(user_id), {}).get("premium_until", "N/A")
    await send_msg(chat_id,
        "<blockquote>💎 <b>PREMIUM</b>\n"
        "―――――――――――――――――\n"
        "✨ UNLIMITED Searches\n✨ NO CREDIT COST\n✨ ALL FEATURES UNLOCKED\n\n"
        f"📋 <b>YOUR STATUS:</b> {status}\n"
        f"📅 <b>VALID UNTIL:</b> {until}\n\n"
        "💳 USE <b>Purchase Premium</b> to buy!\n"
        "📱 CONTACT: @MJ_SARKAR_OWNER\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

async def handle_purchase_premium(chat_id, user_id):
    money = users_db.get(str(user_id), {}).get("money", 0)
    plans_kb = {
        "keyboard": [
            [{"text": "📅 1 MONTH — ₹499", "style": "primary"}],
            [{"text": "📅 15 DAYS — ₹280", "style": "primary"}],
            [{"text": "📅 7 DAYS — ₹150", "style": "primary"}],
            [{"text": "📅 1 DAY — ₹40", "style": "primary"}],
            [{"text": "🏠 BACK HOME", "style": "danger"}]
        ],
        "resize_keyboard": True
    }
    await send_msg(chat_id,
        "<blockquote>💳 <b>PURCHASE PREMIUM</b>\n"
        "―――――――――――――――――\n"
        f"₹ <b>YOUR BALANCE:</b> ₹{money}\n\n"
        "🛒 <b>SELECT A PLAN:</b>\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>", plans_kb)

async def handle_referrals(chat_id, user_id):
    uid = str(user_id)
    referrals = users_db.get(uid, {}).get("referrals", 0)
    credits = users_db.get(uid, {}).get("credits", 0)
    ref_credits = settings.get("referral_credits", 5)
    link = f"https://t.me/{BOT_USERNAME}?start={user_id}"
    share_kb = {"inline_keyboard": [[
        {"text": "📤 SHARE",
         "url": f"https://t.me/share/url?url={link}&text=Join%20MJ%20SARKAR%20Bot!"}
    ]]}
    await send_msg(chat_id,
        "<blockquote>👥 <b>REFERRALS</b>\n"
        f"📊 <b>TOTAL :</b> {referrals}\n\n"
        f"🔗 <b>YOUR LINK :</b>\n<code>{link}</code>\n\n"
        f"🎁 <b>PER REFERRAL :</b> +{ref_credits} CREDITS\n"
        f"💰 <b>YOUR CREDITS :</b> {credits}\n\n"
        "―――――――――――――――――\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>", share_kb)

async def handle_channels(chat_id):
    await send_msg(chat_id,
        "<blockquote>📢 <b>OUR CHANNELS:</b>\n\n"
        "• @MJ_SARKAR_OFFICIAL\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

async def handle_help(chat_id):
    await send_msg(chat_id,
        "<blockquote>❓ <b>HELP</b>\n"
        "―――――――――――――――――\n"
        "📱 NUMBER INFO — Phone number lookup\n"
        "👤 AADHAR INFO — Aadhar lookup\n"
        "🔍 USERNAME INFO — TG username lookup\n"
        "🆔 TG ID INFO — Telegram ID lookup\n"
        "🚗 VEHICLE INFO — RC number lookup\n"
        "🧾 GST INFO — GST number lookup\n"
        "🪪 PAN INFO — PAN card lookup\n"
        "💰 BALANCE — View your credits\n"
        "🎁 DAILY CLAIM — Get daily credits\n"
        "💳 PURCHASE PREMIUM — Buy premium plan\n"
        "👥 REFERRALS — Share & earn credits\n"
        "🎟️ REDEEM CODE — Redeem gift codes\n\n"
        "📱 <b>SUPPORT:</b> @MJ_SARKAR_OWNER\n\n"
        "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# MAIN ROUTER
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async def handle_message(update):
    message = update.get("message", {})
    text = message.get("text", "").strip()
    chat_id = message.get("chat", {}).get("id")
    user_id = message.get("from", {}).get("id")
    user_name = message.get("from", {}).get("first_name", "User")
    username = message.get("from", {}).get("username", "")
    if not chat_id or not text: return

    get_user_json(user_id, user_name, username)

    if is_banned(user_id) and user_id not in ADMIN_IDS:
        await send_msg(chat_id,
            "<blockquote>🚫 <b>You are BANNED!</b>\nContact: @MJ_SARKAR_OWNER</blockquote>"); return

    # ── RATE LIMIT / ANTI-SPAM (admins exempt) ──
    # Har user ke liye 1.5s ka gap. Bulk automation/spam ko chup-chaap ignore karta hai,
    # jisse bot kabhi hang nahi hota. Pichla request abhi chal raha ho to bhi skip.
    if user_id not in ADMIN_IDS:
        now = time.monotonic()
        if now - user_last_action.get(user_id, 0.0) < RATE_LIMIT_SECONDS:
            return
        user_last_action[user_id] = now
        if user_id in user_processing:
            return
        user_processing.add(user_id)
        try:
            await _handle_message_core(update, text, chat_id, user_id, user_name, username)
        finally:
            user_processing.discard(user_id)
        return
    # Admin path -> bina rate limit
    await _handle_message_core(update, text, chat_id, user_id, user_name, username)

async def _handle_message_core(update, text, chat_id, user_id, user_name, username):
    state = user_state.get(user_id)

    # ── /start ──
    if text.startswith("/start"):
        parts = text.split()
        ref = parts[1] if len(parts) > 1 else None
        # Referral ko hamesha process karo (taaki referrer ko credit mile),
        # par menu sirf tabhi dikhe jab user ne sab channels join kar liye ho.
        if not await check_force_join(chat_id, user_id):
            # Referral relation save kar lo bina credit confusion ke
            _u = get_user_json(user_id, user_name, username)
            if ref and ref != str(user_id) and _u.get("referred_by") is None:
                try:
                    users_db[str(user_id)]["referred_by"] = int(ref)
                    save_users_json(users_db)
                except: pass
            return
        await handle_start(chat_id, user_id, user_name, username, ref); return

    # ── FORCE JOIN GATE ──
    # Admins ko chhod kar, har user ko sab channels join karna zaruri hai.
    if not await check_force_join(chat_id, user_id):
        return

    # ── ADMIN STATES ──
    if user_id in ADMIN_IDS:
        if state == "awaiting_broadcast":
            await process_broadcast(chat_id, user_id, text); return
        if state == "awaiting_ban_id":
            await process_ban_user(chat_id, user_id, text); return
        if state == "awaiting_unban_id":
            await process_unban_user(chat_id, user_id, text); return
        if state == "awaiting_redeem_gen":
            await process_gen_redeem(chat_id, user_id, text); return
        if state == "awaiting_search_limit":
            await process_search_limit(chat_id, user_id, text); return
        if state == "awaiting_daily_claim_limit":
            await process_daily_claim_limit(chat_id, user_id, text); return
        if state == "awaiting_referral_credit":
            await process_referral_credit(chat_id, user_id, text); return
        if state == "awaiting_give_premium_id":
            await process_give_premium(chat_id, user_id, text); return
        if state == "awaiting_remove_premium_id":
            await process_remove_premium(chat_id, user_id, text); return

    # ── NAVIGATION ──
    if text in ("🏠 BACK HOME",):
        user_state[user_id] = None
        await handle_start(chat_id, user_id, user_name, username); return
    if text == "➡️ NEXT PAGE":
        await send_msg(chat_id, "<blockquote>📋 <b>PAGE 2</b> — More Options</blockquote>",
                       page2_keyboard()); return
    if text == "Next ➡️" and state == "viewing_number_results":
        await process_next_page(chat_id, user_id); return

    # ── ADMIN PANEL BUTTONS ──
        # ── ADMIN PANEL BUTTONS ──
    if user_id in ADMIN_IDS:
        if text == "🛡️ ADMIN PANEL":
            await handle_admin_panel(chat_id, user_id); return
        if text == "👥 USERS LIST":
            await handle_admin_users_list(chat_id); return
        if text == "📢 BROADCAST":
            await handle_broadcast(chat_id, user_id); return
        if text == "🚫 BAN USER":
            await handle_ban_user(chat_id, user_id); return
        if text == "✅ UNBAN USER":
            await handle_unban_user(chat_id, user_id); return
        if text == "🎟️ GEN REDEEM":
            await handle_gen_redeem(chat_id, user_id); return
        if text == "🔍 SEARCH LIMIT":
            await handle_set_search_limit(chat_id, user_id); return
        if text == "🎁 DAILY LIMIT":
            await handle_set_daily_claim(chat_id, user_id); return
        if text == "👥 REFERRAL CREDIT":
            await handle_set_referral_credit(chat_id, user_id); return
        if text == "💎 GIVE PREMIUM":
            await handle_give_premium(chat_id, user_id); return
        if text == "❌ REMOVE PREMIUM":
            await handle_remove_premium(chat_id, user_id); return

    # ── USER MENU BUTTONS ──
    if text == "📱 NUMBER INFO":
        await prompt(chat_id, user_id, "awaiting_number",
            "📱 <b>SEND 10-DIGIT MOBILE NUMBER</b>", "9876543210"); return
    if text == "👤 AADHAR INFO":
        await prompt(chat_id, user_id, "awaiting_aadhar",
            "🪪 <b>SEND 12-DIGIT AADHAR NUMBER</b>", "[Aadhaar Redacted]"); return

    if text == "🔍 USERNAME INFO":
        await prompt(chat_id, user_id, "awaiting_username",
            "🔍 <b>SEND USERNAME WITH @</b>", "@username"); return
    if text == "🆔 TG ID INFO":
        await prompt(chat_id, user_id, "awaiting_tgid",
            "🆔 <b>SEND TELEGRAM USER ID</b>", "6443754454"); return
    if text == "🚗 VEHICLE INFO":
        await prompt(chat_id, user_id, "awaiting_vehicle",
            "🚗 <b>SEND VEHICLE RC NUMBER</b>", "BR06AB1234"); return
    if text == "🧾 GST INFO":
        await prompt(chat_id, user_id, "awaiting_gst",
            "🧾 <b>SEND GST NUMBER</b>", "10DJCPK4351Q1Z5"); return
    if text == "🪪 PAN INFO":
        await prompt(chat_id, user_id, "awaiting_pan",
            "🪪 <b>SEND PAN CARD NUMBER</b>", "AAMTS3432L"); return
    if text == "💰 BALANCE":
        await handle_balance(chat_id, user_id); return
    if text == "🎁 DAILY CLAIM":
        await handle_daily_claim(chat_id, user_id, user_name); return
    if text == "💎 PREMIUM":
        await handle_premium(chat_id, user_id); return
    if text == "💳 PURCHASE PREMIUM":
        await handle_purchase_premium(chat_id, user_id); return
    if text == "👥 REFERRALS":
        await handle_referrals(chat_id, user_id); return
    if text == "🎟️ REDEEM CODE":
        await prompt(chat_id, user_id, "awaiting_redeem",
            "🎟️ <b>SEND YOUR REDEEM CODE</b>", "ABC123XYZ"); return
    if text == "📢 CHANNELS":
        await handle_channels(chat_id); return
    if text == "❓ HELP":
        await handle_help(chat_id); return

    for plan in ["📅 1 MONTH — ₹499","📅 15 DAYS — ₹280","📅 7 DAYS — ₹150","📅 1 DAY — ₹40"]:
        if text == plan:
            await send_msg(chat_id,
                f"<blockquote>💳 <b>{plan}</b>\n\nContact the Admin.:\n"
                f"📱 @MJ_SARKAR_OWNER\n\n"
                "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>"); return

    # ── USER STATES ──
    if state == "awaiting_number":
        user_state[user_id] = None
        await process_number(chat_id, user_id, text)
    elif state == "awaiting_username":
        user_state[user_id] = None
        await process_username(chat_id, user_id, text)
    elif state == "awaiting_tgid":
        user_state[user_id] = None
        await process_tgid(chat_id, user_id, text)
    elif state == "awaiting_vehicle":
        user_state[user_id] = None
        await process_vehicle(chat_id, user_id, text)
    elif state == "awaiting_gst":
        user_state[user_id] = None
        await process_gst(chat_id, user_id, text)
    elif state == "awaiting_pan":
        user_state[user_id] = None
        await process_pan(chat_id, user_id, text)
    elif state == "awaiting_redeem":
        await process_redeem(chat_id, user_id, text)
    elif state == "awaiting_aadhar":
        user_state[user_id] = None
        await send_msg(chat_id,
            "<blockquote>🔍 <b>AADHAR LOOKUP</b>\n\n⚠️ API coming soon!\n\n"
            "👑 <b>BOT MADE BY :</b> @MJ_SARKAR_OWNER</blockquote>")

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# CALLBACK QUERY HANDLER (Force Join Verify button)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async def handle_callback(callback):
    data = callback.get("data", "")
    callback_id = callback.get("id")
    msg = callback.get("message", {})
    chat_id = msg.get("chat", {}).get("id")
    message_id = msg.get("message_id")
    from_user = callback.get("from", {})
    user_id = from_user.get("id")
    user_name = from_user.get("first_name", "User")
    username = from_user.get("username", "")

    if data == "check_join":
        not_joined = await get_not_joined_channels(user_id)
        if not_joined:
            await answer_callback(callback_id,
                "❌ Abhi bhi sab channels join nahi kiye! Pehle join karo.",
                show_alert=True)
            return
        # Sab join ho gaya — verify message delete karke welcome bhejo
        await answer_callback(callback_id, "✅ Verified! Welcome.", show_alert=False)
        if message_id:
            await delete_msg(chat_id, message_id)
        await handle_start(chat_id, user_id, user_name, username)

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# MAIN
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async def polling_loop():
    offset = 0
    print("✅ MJ SARKAR BOT chal raha hai (FAST MODE)...")
    while True:
        try:
            resp = await http.get(
                f"{API_URL}/getUpdates",
                params={"offset": offset, "timeout": 30},
                timeout=35
            )
            updates = resp.json().get("result", [])
            for update in updates:
                offset = update["update_id"] + 1
                # Har update ko background task me daalo -> sabhi users parallel handle honge.
                # Ek slow API call ab baaki users ko block nahi karegi.
                asyncio.create_task(dispatch_update(update))
        except Exception as e:
            print(f"Polling error: {e}")
            await asyncio.sleep(3)

async def dispatch_update(update):
    try:
        if "callback_query" in update:
            await handle_callback(update["callback_query"])
        else:
            await handle_message(update)
    except Exception as e:
        print(f"Update handle error: {e}")

async def main():
    await telethon_client.start()
    print("✅ Telethon session connected!")
    asyncio.create_task(users_flush_loop())   # background disk saver (debounced)
    try:
        await polling_loop()
    finally:
        await http.aclose()

if __name__ == "__main__":
    asyncio.run(main())
