import html, sqlite3, secrets
from datetime import datetime, timedelta, timezone
from telegram import Update, ReplyKeyboardMarkup, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, CommandHandler, MessageHandler, CallbackQueryHandler, ContextTypes, filters

TOKEN = "8827270824:AAG1YxR4eJcXAYirr-VuIsdQY4U_-G4zUT8"
ADMINS = [8093002631]

FORCE_JOIN_CHAT_ID = "@ASxStore72"
FORCE_JOIN_LINK = "https://t.me/ASxStore72"
LOG_CHAT_ID = -1004465909003
BOT_USERNAME = "@ASxStoreBot"

REF_REWARD = 0.10
ACCOUNT_TITLE = "Asif Sakhani"
BINANCE_UID = "914581847"
BEP20_ADDRESS = "0x85b06184b69840a5c5a1b881cb723f6346e63fe9"
TRC20_ADDRESS = "THJwt87tZ5mvk8mctGgZLTWPcGxzGgtRq5"
DB_FILE = "shopbot.db"

menu = ReplyKeyboardMarkup(
    [["🛍 Shop"], ["💰 Deposit", "👤 My Profile"], ["🏆 Leaderboard", "🆘 Support"], ["⭐ Refer & Earn"]],
    resize_keyboard=True
)

def now(): return datetime.now(timezone.utc).isoformat()
def money(x): return f"${float(x):.2f}"
def parse_price(x): return float(str(x).replace("$","").replace("USDT","").strip())
def order_id(): return "Ash" + secrets.token_hex(3).upper()
def short_id(x): return f"{x[:4]}***{x[-1]}" if len(x) > 6 else x

def con():
    c = sqlite3.connect(DB_FILE)
    c.row_factory = sqlite3.Row
    return c

def init_db():
    c = con()
    c.execute("CREATE TABLE IF NOT EXISTS users(user_id INTEGER PRIMARY KEY, username TEXT, first_name TEXT, balance REAL DEFAULT 0, referrer_id INTEGER, referrals INTEGER DEFAULT 0, verified INTEGER DEFAULT 0, joined_at TEXT)")
    c.execute("CREATE TABLE IF NOT EXISTS products(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, price REAL, emoji TEXT DEFAULT '📦', description TEXT DEFAULT '', instructions TEXT DEFAULT '', discount_price REAL, discount_until TEXT, discount_text TEXT DEFAULT '', photo TEXT)")
    c.execute("CREATE TABLE IF NOT EXISTS stock(id INTEGER PRIMARY KEY AUTOINCREMENT, product_id INTEGER, item TEXT, sold INTEGER DEFAULT 0)")
    c.execute("CREATE TABLE IF NOT EXISTS orders(id INTEGER PRIMARY KEY AUTOINCREMENT, order_id TEXT, user_id INTEGER, product_id INTEGER, product_name TEXT, price REAL, item TEXT, created_at TEXT)")
    c.execute("CREATE TABLE IF NOT EXISTS deposits(id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, order_ref TEXT, photo_id TEXT, status TEXT DEFAULT 'pending', amount REAL DEFAULT 0, created_at TEXT)")
    c.commit(); c.close()

def ensure_user(user, ref=None):
    c = con()
    r = c.execute("SELECT * FROM users WHERE user_id=?", (user.id,)).fetchone()
    if ref == user.id: ref = None
    if r is None:
        c.execute("INSERT INTO users(user_id,username,first_name,referrer_id,joined_at) VALUES(?,?,?,?,?)", (user.id, user.username or "", user.first_name or "", ref, now()))
    else:
        c.execute("UPDATE users SET username=?, first_name=? WHERE user_id=?", (user.username or "", user.first_name or "", user.id))
    c.commit(); c.close()

def get_user(uid):
    c = con(); r = c.execute("SELECT * FROM users WHERE user_id=?", (uid,)).fetchone(); c.close(); return r
def add_bal(uid, amt):
    c = con(); c.execute("UPDATE users SET balance=balance+? WHERE user_id=?", (float(amt), uid)); c.commit(); c.close()
def rem_bal(uid, amt):
    c = con(); c.execute("UPDATE users SET balance=balance-? WHERE user_id=?", (float(amt), uid)); c.commit(); c.close()
def ulink(uid, username=None, first="User"):
    return f"@{html.escape(username)}" if username else f'<a href="tg://user?id={uid}">{html.escape(first or "User")}</a>'

def get_product(pid):
    c = con(); r = c.execute("SELECT * FROM products WHERE id=?", (pid,)).fetchone(); c.close(); return r
def stock_count(pid):
    c = con(); n = c.execute("SELECT COUNT(*) c FROM stock WHERE product_id=? AND sold=0", (pid,)).fetchone()["c"]; c.close(); return n
def pop_stock(pid):
    c = con(); cur = c.cursor()
    r = cur.execute("SELECT * FROM stock WHERE product_id=? AND sold=0 ORDER BY id LIMIT 1", (pid,)).fetchone()
    if not r: c.close(); return None
    cur.execute("UPDATE stock SET sold=1 WHERE id=?", (r["id"],)); c.commit(); c.close(); return r["item"]

def price_now(p):
    if p["discount_price"] is not None and p["discount_until"]:
        try:
            until = datetime.fromisoformat(p["discount_until"])
            if datetime.now(timezone.utc) < until:
                return float(p["discount_price"]), True, until
        except Exception:
            pass
    return float(p["price"]), False, None

def countdown(until):
    s = int((until - datetime.now(timezone.utc)).total_seconds())
    return "Expired" if s <= 0 else f"{s//3600}h {(s%3600)//60}m"

async def joined(ctx, uid):
    try:
        m = await ctx.bot.get_chat_member(FORCE_JOIN_CHAT_ID, uid)
        print("JOIN CHECK:", uid, m.status, flush=True)
        return m.status in ["member", "administrator", "creator"]
    except Exception as e:
        print("JOIN ERROR:", e, flush=True)
        return False

async def join_gate(msg):
    kb = InlineKeyboardMarkup([[InlineKeyboardButton("📢 Join Channel", url=FORCE_JOIN_LINK)], [InlineKeyboardButton("✅ Verify Join", callback_data="verify_join")]])
    await msg.reply_text("🔒 <b>Join Required</b>\n\nPlease join our channel first, then press <b>Verify Join</b> to start using the bot.", reply_markup=kb, parse_mode="HTML")

async def require_join(update, ctx):
    ensure_user(update.effective_user)
    if not await joined(ctx, update.effective_user.id):
        await join_gate(update.message)
        return False
    c = con(); c.execute("UPDATE users SET verified=1 WHERE user_id=?", (update.effective_user.id,)); c.commit(); c.close()
    return True

async def verify_join(update, ctx):
    q = update.callback_query; await q.answer()
    ensure_user(q.from_user)
    if not await joined(ctx, q.from_user.id):
        await q.message.reply_text("❌ You have not joined yet. Please join the channel first, then press Verify Join.")
        return
    c = con(); cur = c.cursor()
    row = cur.execute("SELECT * FROM users WHERE user_id=?", (q.from_user.id,)).fetchone()
    first = row and int(row["verified"]) == 0
    cur.execute("UPDATE users SET verified=1 WHERE user_id=?", (q.from_user.id,)); c.commit(); c.close()
    if first and row and row["referrer_id"]:
        ref = int(row["referrer_id"]); add_bal(ref, REF_REWARD)
        c = con(); c.execute("UPDATE users SET referrals=referrals+1 WHERE user_id=?", (ref,)); c.commit()
        rr = c.execute("SELECT * FROM users WHERE user_id=?", (ref,)).fetchone(); c.close()
        try: await ctx.bot.send_message(ref, f"🎉 New referral joined!\n💰 {money(REF_REWARD)} added.\n👥 Total referrals: {rr['referrals']}\n💵 Balance: {money(rr['balance'])}")
        except Exception: pass
    await q.message.reply_text("✅ Verified successfully. Welcome!", reply_markup=menu)
    await show_shop(q.message, ctx)

async def start(update, ctx):
    ref = None
    if ctx.args:
        try: ref = int(ctx.args[0])
        except Exception: pass
    ensure_user(update.effective_user, ref)
    if not await require_join(update, ctx): return
    await update.message.reply_text(f"👋 <b>Welcome, {html.escape(update.effective_user.first_name or 'User')}!</b>\n\nUse the buttons below.", reply_markup=menu, parse_mode="HTML")

async def show_shop(msg, ctx):
    c = con(); rows = c.execute("SELECT * FROM products ORDER BY id DESC").fetchall(); c.close()
    if not rows: await msg.reply_text("❌ No products available."); return
    buttons = [[InlineKeyboardButton(f"{p['emoji']} {p['name']} ({stock_count(p['id'])})", callback_data=f"product_{p['id']}")] for p in rows]
    buttons.append([InlineKeyboardButton("🔄 Refresh", callback_data="shop_refresh")])
    await msg.reply_text("🛒 <b>Choose Your Product:</b>", reply_markup=InlineKeyboardMarkup(buttons), parse_mode="HTML")

async def shop(update, ctx):
    if await require_join(update, ctx): await show_shop(update.message, ctx)

async def product_view(update, ctx):
    q = update.callback_query; await q.answer()
    if not await joined(ctx, q.from_user.id): await join_gate(q.message); return
    if q.data == "shop_refresh": await show_shop(q.message, ctx); return
    pid = int(q.data.replace("product_","")); p = get_product(pid)
    if not p: await q.message.reply_text("❌ Product not found."); return
    pr, disc, until = price_now(p)
    price_line = f"💵 Price: <b>{money(p['price'])}</b>"
    if disc: price_line = f"💵 Original Price: <s>{money(p['price'])}</s>\n✅ Discount Price: <b>{money(pr)}</b>\n⏳ Ends in: <b>{countdown(until)}</b>\n💥 {html.escape(p['discount_text'] or '')}"
    text = f"{html.escape(p['emoji'])} <b>{html.escape(p['name'])}</b>\n\n📦 Available: <b>{stock_count(pid)}</b>\n{price_line}\n\n{html.escape(p['description'] or '')}"
    kb = InlineKeyboardMarkup([[InlineKeyboardButton(f"🛒 Buy {p['name']}", callback_data=f"buy_{pid}")], [InlineKeyboardButton("⬅️ Back", callback_data="shop_refresh")]])
    if p["photo"]: await q.message.reply_photo(p["photo"], caption=text, reply_markup=kb, parse_mode="HTML")
    else: await q.message.reply_text(text, reply_markup=kb, parse_mode="HTML")

async def buy(update, ctx):
    q = update.callback_query; await q.answer()
    if not await joined(ctx, q.from_user.id): await join_gate(q.message); return
    pid = int(q.data.replace("buy_","")); p = get_product(pid)
    if not p: await q.message.reply_text("❌ Product not found."); return
    pr, _, _ = price_now(p); u = get_user(q.from_user.id)
    if not u or float(u["balance"]) < pr:
        await q.message.reply_text(f"❌ Low balance.\nPrice: {money(pr)}\nYour balance: {money(u['balance'] if u else 0)}"); return
    item = pop_stock(pid)
    if not item: await q.message.reply_text("❌ Out of stock."); return
    rem_bal(q.from_user.id, pr); oid = order_id()
    c = con(); c.execute("INSERT INTO orders(order_id,user_id,product_id,product_name,price,item,created_at) VALUES(?,?,?,?,?,?,?)", (oid,q.from_user.id,pid,p["name"],pr,item,now())); c.commit(); c.close()
    await q.message.reply_text(f"✅ <b>Order Completed</b>\n\n📦 Product: <b>{html.escape(p['name'])}</b>\n🧾 Order ID: <code>{oid}</code>\n\n🔐 <b>Your Delivery:</b>\n<code>{html.escape(item)}</code>\n\n📌 <b>Instructions:</b>\n{html.escape(p['instructions'] or 'Contact support if you need help.')}", parse_mode="HTML")
    try: await ctx.bot.send_message(LOG_CHAT_ID, f"✅ <b>New Order</b>\n\n📦 Product: <b>{html.escape(p['name'])}</b>\n👤 User: {ulink(q.from_user.id,q.from_user.username,q.from_user.first_name)}\n💵 Price: <b>{money(pr)}</b>\n🧾 Order ID: <code>{short_id(oid)}</code>", parse_mode="HTML")
    except Exception as e: print("LOG ERROR:", e, flush=True)

async def deposit(update, ctx):
    if not await require_join(update, ctx): return
    ctx.user_data["deposit_step"] = "order_id"
    await update.message.reply_text(f"💰 <b>BINANCE DEPOSIT</b>\n\n👤 <b>Account Title:</b> {ACCOUNT_TITLE}\n🆔 <b>Binance UID:</b> <code>{BINANCE_UID}</code>\n\n🔹 <b>BEP20 Address</b>\n<code>{BEP20_ADDRESS}</code>\n\n🔹 <b>TRC20 Address</b>\n<code>{TRC20_ADDRESS}</code>\n\nAfter payment, send your <b>Order ID / Transaction ID</b>.\nThen send payment screenshot.", parse_mode="HTML")

async def handle_photo(update, ctx):
    if not await require_join(update, ctx): return
    if ctx.user_data.get("deposit_step") != "screenshot":
        await update.message.reply_text("Photo received. For deposit, press 💰 Deposit first, send Order ID, then screenshot."); return
    order_ref = ctx.user_data.get("deposit_order_ref"); photo_id = update.message.photo[-1].file_id
    c = con(); cur = c.cursor(); cur.execute("INSERT INTO deposits(user_id,order_ref,photo_id,created_at) VALUES(?,?,?,?)", (update.effective_user.id, order_ref, photo_id, now())); dep = cur.lastrowid; c.commit(); c.close()
    ctx.user_data.clear()
    await update.message.reply_text("✅ Deposit request received. Admin will verify and add balance.")
    cap = f"💰 <b>New Deposit Request</b>\n\n🧾 Deposit ID: <code>{dep}</code>\n👤 User: {ulink(update.effective_user.id, update.effective_user.username, update.effective_user.first_name)}\n🆔 User ID: <code>{update.effective_user.id}</code>\n🔖 Order/Tx ID: <code>{html.escape(order_ref)}</code>\n\nApprove:\n<code>/approve {dep} AMOUNT</code>\nReject:\n<code>/reject {dep}</code>"
    for a in ADMINS:
        try: await ctx.bot.send_photo(a, photo_id, caption=cap, parse_mode="HTML")
        except Exception: pass
    try: await ctx.bot.send_photo(LOG_CHAT_ID, photo_id, caption=cap, parse_mode="HTML")
    except Exception as e: print("DEPOSIT LOG ERROR:", e, flush=True)

async def profile(update, ctx):
    if not await require_join(update, ctx): return
    u=get_user(update.effective_user.id)
    await update.message.reply_text(f"👤 <b>My Profile</b>\n\n🆔 ID: <code>{update.effective_user.id}</code>\n💵 Balance: <b>{money(u['balance'])}</b>\n👥 Referrals: <b>{u['referrals']}</b>", parse_mode="HTML")

async def refer(update, ctx):
    if not await require_join(update, ctx): return
    u=get_user(update.effective_user.id); link=f"https://t.me/{BOT_USERNAME}?start={update.effective_user.id}"
    await update.message.reply_text(f"⭐ <b>Refer & Earn</b>\n\n💰 1 verified invite = <b>{money(REF_REWARD)}</b>\n👥 Referrals: <b>{u['referrals']}</b>\n💵 Balance: <b>{money(u['balance'])}</b>\n\n🔗 Your link:\n<code>{link}</code>", parse_mode="HTML")

async def leaderboard(update, ctx):
    if not await require_join(update, ctx): return
    c=con(); rows=c.execute("SELECT * FROM users ORDER BY referrals DESC LIMIT 10").fetchall(); c.close()
    text="🏆 <b>Top Referrers</b>\n\n"
    for i,r in enumerate(rows,1): text += f"{i}. {ulink(r['user_id'],r['username'],r['first_name'])} — <b>{r['referrals']}</b>\n"
    await update.message.reply_text(text, parse_mode="HTML", disable_web_page_preview=True)

def adminok(uid): return uid in ADMINS

async def admin(update, ctx):
    if not adminok(update.effective_user.id): await update.message.reply_text("❌ Access denied."); return
    await update.message.reply_text("⚙️ <b>Admin Commands</b>\n\n/addp Name | Price | Emoji | Description\n/addstock ProductID | gmail:password\n/listp\n/delp ProductID\n/editprice ProductID | NewPrice\n/instructions ProductID | Message\n/discount ProductID | DiscountPrice | Hours | Text\n/cleardiscount ProductID\n/addpic ProductID\n/editpic ProductID\n/removepic ProductID\n/approve DepositID Amount\n/reject DepositID\n/addbal UserID Amount\n/removebal UserID Amount\n/broadcast Message\n/users", parse_mode="HTML")

async def addp(update, ctx):
    if not adminok(update.effective_user.id): return
    d=update.message.text.replace("/addp","",1).strip().split("|")
    if len(d)<4: await update.message.reply_text("Usage: /addp Name | Price | Emoji | Description"); return
    c=con(); cur=c.cursor(); cur.execute("INSERT INTO products(name,price,emoji,description) VALUES(?,?,?,?)",(d[0].strip(),parse_price(d[1]),d[2].strip(),d[3].strip())); pid=cur.lastrowid; c.commit(); c.close()
    await update.message.reply_text(f"✅ Product added. ID: {pid}")

async def addstock(update, ctx):
    if not adminok(update.effective_user.id): return
    d=update.message.text.replace("/addstock","",1).strip().split("|",1)
    if len(d)<2: await update.message.reply_text("Usage: /addstock ProductID | gmail:password"); return
    pid=int(d[0].strip()); c=con(); c.execute("INSERT INTO stock(product_id,item) VALUES(?,?)",(pid,d[1].strip())); c.commit(); c.close()
    await update.message.reply_text(f"✅ Stock added. Current: {stock_count(pid)}")

async def listp(update, ctx):
    if not adminok(update.effective_user.id): return
    c=con(); rows=c.execute("SELECT * FROM products ORDER BY id DESC").fetchall(); c.close()
    if not rows: await update.message.reply_text("No products."); return
    text="📦 Products\n\n"
    for p in rows: text += f"ID {p['id']} — {p['emoji']} {p['name']} — {money(p['price'])} — Stock: {stock_count(p['id'])}\n"
    await update.message.reply_text(text)

async def delp(update, ctx):
    if not adminok(update.effective_user.id): return
    if not ctx.args: await update.message.reply_text("Usage: /delp ProductID"); return
    pid=int(ctx.args[0]); c=con(); c.execute("DELETE FROM products WHERE id=?",(pid,)); c.execute("DELETE FROM stock WHERE product_id=?",(pid,)); c.commit(); c.close()
    await update.message.reply_text("✅ Deleted.")

async def editprice(update, ctx):
    if not adminok(update.effective_user.id): return
    d=update.message.text.replace("/editprice","",1).strip().split("|")
    if len(d)<2: await update.message.reply_text("Usage: /editprice ProductID | NewPrice"); return
    c=con(); c.execute("UPDATE products SET price=? WHERE id=?",(parse_price(d[1]),int(d[0]))); c.commit(); c.close()
    await update.message.reply_text("✅ Price updated.")

async def instructions(update, ctx):
    if not adminok(update.effective_user.id): return
    d=update.message.text.replace("/instructions","",1).strip().split("|",1)
    if len(d)<2: await update.message.reply_text("Usage: /instructions ProductID | Message"); return
    c=con(); c.execute("UPDATE products SET instructions=? WHERE id=?",(d[1].strip(),int(d[0]))); c.commit(); c.close()
    await update.message.reply_text("✅ Instructions updated.")

async def discount(update, ctx):
    if not adminok(update.effective_user.id): return
    d=update.message.text.replace("/discount","",1).strip().split("|")
    if len(d)<4: await update.message.reply_text("Usage: /discount ProductID | DiscountPrice | Hours | Text"); return
    until=datetime.now(timezone.utc)+timedelta(hours=float(d[2].strip()))
    c=con(); c.execute("UPDATE products SET discount_price=?, discount_until=?, discount_text=? WHERE id=?",(parse_price(d[1]),until.isoformat(),d[3].strip(),int(d[0]))); c.commit(); c.close()
    await update.message.reply_text("✅ Discount added.")

async def cleardiscount(update, ctx):
    if not adminok(update.effective_user.id): return
    c=con(); c.execute("UPDATE products SET discount_price=NULL, discount_until=NULL, discount_text='' WHERE id=?",(int(ctx.args[0]),)); c.commit(); c.close()
    await update.message.reply_text("✅ Discount cleared.")

async def addpic(update, ctx):
    if not adminok(update.effective_user.id): return
    if not ctx.args or not update.message.reply_to_message or not update.message.reply_to_message.photo:
        await update.message.reply_text("Reply to a photo with: /addpic ProductID"); return
    pid=int(ctx.args[0]); photo_id=update.message.reply_to_message.photo[-1].file_id
    c=con(); c.execute("UPDATE products SET photo=? WHERE id=?",(photo_id,pid)); c.commit(); c.close()
    await update.message.reply_text("✅ Product photo saved/updated.")

async def removepic(update, ctx):
    if not adminok(update.effective_user.id): return
    c=con(); c.execute("UPDATE products SET photo=NULL WHERE id=?",(int(ctx.args[0]),)); c.commit(); c.close()
    await update.message.reply_text("✅ Photo removed.")

async def approve(update, ctx):
    if not adminok(update.effective_user.id): return
    if len(ctx.args)<2: await update.message.reply_text("Usage: /approve DepositID Amount"); return
    dep=int(ctx.args[0]); amt=parse_price(ctx.args[1]); c=con(); d=c.execute("SELECT * FROM deposits WHERE id=?",(dep,)).fetchone()
    if not d: c.close(); await update.message.reply_text("❌ Deposit not found."); return
    c.execute("UPDATE deposits SET status='approved', amount=? WHERE id=?",(amt,dep)); c.execute("UPDATE users SET balance=balance+? WHERE user_id=?",(amt,d["user_id"])); c.commit(); c.close()
    await update.message.reply_text("✅ Deposit approved.")
    try: await ctx.bot.send_message(d["user_id"], f"✅ Deposit approved. Added: {money(amt)}")
    except Exception: pass

async def reject(update, ctx):
    if not adminok(update.effective_user.id): return
    dep=int(ctx.args[0]); c=con(); d=c.execute("SELECT * FROM deposits WHERE id=?",(dep,)).fetchone()
    if d:
        c.execute("UPDATE deposits SET status='rejected' WHERE id=?",(dep,)); c.commit()
        try: await ctx.bot.send_message(d["user_id"], "❌ Deposit rejected. Contact support.")
        except Exception: pass
    c.close(); await update.message.reply_text("✅ Deposit rejected.")

async def addbal(update, ctx):
    if not adminok(update.effective_user.id): return
    add_bal(int(ctx.args[0]), parse_price(ctx.args[1])); await update.message.reply_text("✅ Balance added.")

async def removebal(update, ctx):
    if not adminok(update.effective_user.id): return
    rem_bal(int(ctx.args[0]), parse_price(ctx.args[1])); await update.message.reply_text("✅ Balance removed.")

async def broadcast(update, ctx):
    if not adminok(update.effective_user.id): return
    msg=update.message.text.replace("/broadcast","",1).strip()
    if not msg: await update.message.reply_text("Usage: /broadcast Message"); return
    c=con(); users=c.execute("SELECT user_id FROM users").fetchall(); c.close()
    sent=0
    for u in users:
        try: await ctx.bot.send_message(u["user_id"], msg); sent+=1
        except Exception: pass
    await update.message.reply_text(f"✅ Broadcast sent: {sent}")

async def users_cmd(update, ctx):
    if not adminok(update.effective_user.id): return
    c=con(); total=c.execute("SELECT COUNT(*) c FROM users").fetchone()["c"]; verified=c.execute("SELECT COUNT(*) c FROM users WHERE verified=1").fetchone()["c"]; c.close()
    await update.message.reply_text(f"👥 Users: {total}\n✅ Verified: {verified}")

async def text_handler(update, ctx):
    text = update.message.text or ""
    if ctx.user_data.get("deposit_step") == "order_id" and not text.startswith("/"):
        ctx.user_data["deposit_order_ref"]=text.strip(); ctx.user_data["deposit_step"]="screenshot"
        await update.message.reply_text("✅ Order/Transaction ID received. Now send payment screenshot."); return
    if text == "🛍 Shop": await shop(update, ctx)
    elif text == "💰 Deposit": await deposit(update, ctx)
    elif text == "👤 My Profile": await profile(update, ctx)
    elif text == "⭐ Refer & Earn": await refer(update, ctx)
    elif text == "🏆 Leaderboard": await leaderboard(update, ctx)
    elif text == "🆘 Support": await update.message.reply_text("🆘 Support: @YourUsername")
    else: await update.message.reply_text("Please choose an option below 👇", reply_markup=menu)

init_db()
app = Application.builder().token(TOKEN).build()
for name, func in [
    ("start", start), ("admin", admin), ("addp", addp), ("addstock", addstock), ("listp", listp),
    ("delp", delp), ("editprice", editprice), ("instructions", instructions), ("discount", discount),
    ("cleardiscount", cleardiscount), ("addpic", addpic), ("editpic", addpic), ("removepic", removepic),
    ("approve", approve), ("reject", reject), ("addbal", addbal), ("removebal", removebal),
    ("broadcast", broadcast), ("users", users_cmd)
]:
    app.add_handler(CommandHandler(name, func))
app.add_handler(CallbackQueryHandler(verify_join, pattern="^verify_join$"))
app.add_handler(CallbackQueryHandler(product_view, pattern="^(product_|shop_refresh)"))
app.add_handler(CallbackQueryHandler(buy, pattern="^buy_"))
app.add_handler(MessageHandler(filters.PHOTO, handle_photo))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, text_handler))
print("Bot Running...", flush=True)
app.run_polling()
