import sqlite3
import asyncio
import random
import aiohttp
import time
import json
from pyrogram import Client, filters
from pyrogram.types import (
    InlineKeyboardMarkup,
    InlineKeyboardButton,
    BotCommand,
    Message,
    CallbackQuery,
    InputMediaPhoto,
    ChatJoinRequest
)
from pyrogram.enums import ParseMode
from pyrogram.errors import FloodWait, InputUserDeactivated, UserIsBlocked, PeerIdInvalid

# --- 🛑 CONFIGURATION 🛑 ---

API_ID = 23231578
API_HASH = "6016ef2dc043865f26667d89719b2c7e"
BOT_TOKEN = "8366684964:AAHjEwBkMtxCyWE8e-Cp7AZlnzaHBWOwGg8"
OWNER_ID = 6742282042

# Token Cleanup
BOT_TOKEN = BOT_TOKEN.strip()

# App Definition
app = Client("auto_reaction_bot_v2", api_id=API_ID, api_hash=API_HASH, bot_token=BOT_TOKEN)

# --- 🗄 DATABASE (SQLite) ---

DB_NAME = "reaction_database.db"

def init_db():
    conn = sqlite3.connect(DB_NAME)
    c = conn.cursor()
    c.execute('CREATE TABLE IF NOT EXISTS users (user_id INTEGER PRIMARY KEY)')
    c.execute('CREATE TABLE IF NOT EXISTS chats (chat_id INTEGER PRIMARY KEY)')
    c.execute('CREATE TABLE IF NOT EXISTS broadcast_logs (user_id INTEGER PRIMARY KEY, message_id INTEGER)')
    c.execute('CREATE TABLE IF NOT EXISTS autodm_settings (id INTEGER PRIMARY KEY CHECK (id = 1), file_id TEXT, file_type TEXT, text TEXT, buttons TEXT)')
    conn.commit()
    conn.close()

def add_user(user_id):
    conn = sqlite3.connect(DB_NAME)
    c = conn.cursor()
    try:
        c.execute('INSERT INTO users (user_id) VALUES (?)', (user_id,))
        conn.commit()
    except sqlite3.IntegrityError:
        pass
    conn.close()

def get_all_users():
    conn = sqlite3.connect(DB_NAME)
    c = conn.cursor()
    c.execute('SELECT user_id FROM users')
    users = [row[0] for row in c.fetchall()]
    conn.close()
    return users

def remove_user(user_id):
    conn = sqlite3.connect(DB_NAME)
    c = conn.cursor()
    c.execute('DELETE FROM users WHERE user_id = ?', (user_id,))
    c.execute('DELETE FROM broadcast_logs WHERE user_id = ?', (user_id,))
    conn.commit()
    conn.close()

def add_chat(chat_id):
    conn = sqlite3.connect(DB_NAME)
    c = conn.cursor()
    try:
        c.execute('INSERT INTO chats (chat_id) VALUES (?)', (chat_id,))
        conn.commit()
    except sqlite3.IntegrityError:
        pass
    conn.close()

def get_stats():
    conn = sqlite3.connect(DB_NAME)
    c = conn.cursor()
    c.execute('SELECT COUNT() FROM users')
    users_count = c.fetchone()[0]
    c.execute('SELECT COUNT() FROM chats')
    chats_count = c.fetchone()[0]
    conn.close()
    return users_count, chats_count

def save_broadcast_log(user_id, message_id):
    conn = sqlite3.connect(DB_NAME)
    c = conn.cursor()
    c.execute('INSERT OR REPLACE INTO broadcast_logs (user_id, message_id) VALUES (?, ?)', (user_id, message_id))
    conn.commit()
    conn.close()

def get_broadcast_logs():
    conn = sqlite3.connect(DB_NAME)
    c = conn.cursor()
    c.execute('SELECT user_id, message_id FROM broadcast_logs')
    logs = c.fetchall()
    conn.close()
    return logs

def clear_broadcast_logs():
    conn = sqlite3.connect(DB_NAME)
    c = conn.cursor()
    c.execute('DELETE FROM broadcast_logs')
    conn.commit()
    conn.close()

def set_autodm(file_id, file_type, text, buttons):
    conn = sqlite3.connect(DB_NAME)
    c = conn.cursor()
    buttons_json = json.dumps(buttons)
    c.execute('INSERT OR REPLACE INTO autodm_settings (id, file_id, file_type, text, buttons) VALUES (1, ?, ?, ?, ?)', (file_id, file_type, text, buttons_json))
    conn.commit()
    conn.close()

def get_autodm():
    conn = sqlite3.connect(DB_NAME)
    c = conn.cursor()
    c.execute('SELECT file_id, file_type, text, buttons FROM autodm_settings WHERE id = 1')
    row = c.fetchone()
    conn.close()
    return row

init_db()

# --- CONSTANTS & TEXTS ---

REACTION_EMOJIS = ["❤️","🥰","🔥","💋","😍","😘","☺️","💯","👍","❤️‍🔥","🤗","😎","😱"]

# Photos
START_PHOTO = "https://t.me/HackWithd/67"
USAGE_PHOTO_1 = "https://t.me/HackWithd/30"
USAGE_PHOTO_2 = "https://t.me/HackWithd/32"
MORE_BOTS_PHOTO = "https://t.me/HackWithd/69"

START_TEXT = (
    "**Aᴜᴛᴏ Rᴇᴀᴄᴛɪᴏɴ Bᴏᴛ**\n\n"
    "𖣘 `I Aᴜᴛᴏᴍᴀᴛɪᴄᴀʟʟʏ Rᴇᴀᴄᴛ Tᴏ Eᴠᴇʀʏ Nᴇᴡ Pᴏꜱᴛ Iɴ Yᴏᴜʀ Cʜᴀɴɴᴇʟ Wɪᴛʜ Eᴍᴏᴊɪꜱ.`\n\n"
    "**Hᴏᴡ Tᴏ Usᴇ:**\n"
    "➜ **1.** `Mᴀᴋᴇ Mᴇ Aᴅᴍɪɴ Iɴ Yᴏᴜʀ Cʜᴀɴɴᴇʟ`\n"
    "➜ **2.** `Pᴏsᴛ A Mᴇssᴀɢᴇ Iɴ Yᴏᴜʀ Cʜᴀɴɴᴇʟ`"
)

# Usage Texts
USAGE_WIZARD_TEXT_1 = "**Firstly Give The Bot Admin In Your Channel/ Group By Tapping ''✚ Aᴅᴅ Tᴏ Cʜᴀɴɴᴇʟ'' Button ✅**"
USAGE_WIZARD_TEXT_2 = "**Tʜᴇ Bᴏᴛ🎉 Yᴏᴜʀ Cʜᴀɴɴᴇʟ / Gʀᴏᴜᴘ 24/7 Rᴇᴀᴄᴛ Eᴠᴇʀʏ Nᴇᴡ Pᴏsᴛ Dɪғғᴇʀᴇɴᴛ✚Rᴇᴀᴄᴛɪᴏɴ✅**"

# --- 📡 BROADCAST & AUTODM GLOBAL VARS ---

BROADCAST_STATE = {} 
AUTODM_STATE = {}
IS_BROADCASTING = False
STOP_BROADCAST = False

# --- HELPER FUNCTIONS ---

def get_start_buttons(bot_username):
    return InlineKeyboardMarkup([
        [
            InlineKeyboardButton(
                "✚ 𝗔𝗱𝗱 𝗧𝗼 𝗖𝗵𝗮𝗻𝗻𝗲𝗹",
                url=f"https://t.me/{bot_username}?startchannel=true&admin=post_messages+edit_messages+delete_messages+invite_users+manage_chat+change_info"
            ),
            InlineKeyboardButton(
                "✚ 𝗔𝗱𝗱 𝗧𝗼 𝗚𝗿𝗼𝘂𝗽",
                url=f"https://t.me/{bot_username}?startgroup=true&admin=post_messages+edit_messages+delete_messages+invite_users+manage_chat+change_info"
            )
        ],
        [
            InlineKeyboardButton("📝 𝗨𝘀𝗮𝗴𝗲", callback_data="usage_callback")
        ],
        [
            InlineKeyboardButton("🚀 𝗠𝗼𝗿𝗲 𝗕𝗼𝘁𝘀", callback_data="show_more_bots")
        ]
    ])

async def send_reaction_via_http(chat_id, message_id, emoji):
    url = f"https://api.telegram.org/bot{BOT_TOKEN}/setMessageReaction"
    payload = {
        "chat_id": chat_id,
        "message_id": message_id,
        "reaction": [{"type": "emoji", "emoji": emoji}]
    }
    async with aiohttp.ClientSession() as session:
        try:
            async with session.post(url, json=payload) as response:
                return response.status == 200
        except Exception:
            return False

# --- 🚀 BASIC COMMANDS ---

@app.on_message(filters.command("start") & filters.private)
async def start_command(client, message):
    add_user(message.from_user.id)
    if message.from_user.id in BROADCAST_STATE:
        del BROADCAST_STATE[message.from_user.id]
    if message.from_user.id in AUTODM_STATE:
        del AUTODM_STATE[message.from_user.id]

    bot_info = await client.get_me()
    try:
        await client.set_bot_commands([
            BotCommand("start", "🟢 Restart Bot"),
            BotCommand("reaction", "🎭 Emoji Info"),
            BotCommand("stats", "📊 Bot Statistics"),
            BotCommand("use", "📝 How to Use")
        ])
    except:
        pass

    await client.send_photo(
        chat_id=message.chat.id,
        photo=START_PHOTO,
        caption=START_TEXT,
        reply_markup=get_start_buttons(bot_info.username)
    )

# --- 🤝 AUTO DM ON JOIN REQUEST ---

@app.on_chat_join_request()
async def auto_dm_on_join(client, request):
    user = request.from_user
    try:
        # Add user to database
        add_user(user.id)
        
        # Check Custom AutoDM
        autodm_data = get_autodm()
        
        if autodm_data:
            file_id, msg_type, caption, buttons_json = autodm_data
            buttons_list = json.loads(buttons_json)
            
            markup = None
            if buttons_list:
                pyrogram_buttons = []
                for row in buttons_list:
                    current_row = [InlineKeyboardButton(btn['text'], url=btn['url']) for btn in row]
                    pyrogram_buttons.append(current_row)
                markup = InlineKeyboardMarkup(pyrogram_buttons)
            
            if msg_type == "photo":
                await client.send_photo(user.id, file_id, caption=caption, reply_markup=markup, parse_mode=ParseMode.DEFAULT)
            elif msg_type == "video":
                await client.send_video(user.id, file_id, caption=caption, reply_markup=markup, parse_mode=ParseMode.DEFAULT)
            elif msg_type == "document":
                await client.send_document(user.id, file_id, caption=caption, reply_markup=markup, parse_mode=ParseMode.DEFAULT)
            elif msg_type == "text":
                await client.send_message(user.id, caption, reply_markup=markup, parse_mode=ParseMode.DEFAULT)
            elif msg_type == "audio":
                await client.send_audio(user.id, file_id, caption=caption, reply_markup=markup, parse_mode=ParseMode.DEFAULT)
            elif msg_type == "sticker":
                await client.send_sticker(user.id, file_id, reply_markup=markup)
            elif msg_type == "voice":
                await client.send_voice(user.id, file_id, caption=caption, reply_markup=markup, parse_mode=ParseMode.DEFAULT)
            elif msg_type == "animation":
                await client.send_animation(user.id, file_id, caption=caption, reply_markup=markup, parse_mode=ParseMode.DEFAULT)
        else:
            # Fallback to default START message
            bot_info = await client.get_me()
            await client.send_photo(
                chat_id=user.id,
                photo=START_PHOTO,
                caption=START_TEXT,
                reply_markup=get_start_buttons(bot_info.username)
            )
    except Exception as e:
        print(f"❌ Failed to Auto DM {user.id}: {e}")

@app.on_message(filters.command("reaction"))
async def reaction_info_command(client, message):
    bot_info = await client.get_me()
    username = bot_info.username
    
    text = (
        "┏━━━━━𝗥𝗘𝗔𝗖𝗧𝗜𝗢𝗡━━━━━┓\n"
        "┃**Reaction=**\n"
        "┃\"❤️\"🥰\"🔥\"💋\"😍\"😘\"☺️\n"
        "┃\"💯\"👍\"❤️\"🔥\"🤗\"😎\"😱\"\n"
        "┃ ➤ `𝟸𝟺 ʜᴏᴜʀs ᴡᴏʀᴋɪɴɢ✓`\n"
        "┃ ➤ `ᴇᴍᴏᴊɪ ᴅɪғғᴇʀᴇɴᴛ✓`\n"
        "┃ ➤ `ᴘᴀʀ ᴘᴏsᴛ ᴇᴍᴏᴊɪ✓`\n"
        "┃ ➤ `ᴄʜᴀɴɴᴇʟ / ɢʀᴏᴜᴘ ᴡᴏʀᴋ✓`\n"
        "┗━━━━━━━━━━━━━━━━━━\n\n"
        "⚙️ **Hᴏᴡ Tᴏ Usᴇ:**\n"
        "1.➜ `Usᴇ Aᴅᴅ Mᴇ Aꜱ Aᴅᴍɪɴ Iɴ Yᴏᴜʀ Cʜᴀɴɴᴇʟ`"
    )

    buttons = InlineKeyboardMarkup([
        [
            InlineKeyboardButton("✚ Cʜᴀɴɴᴇʟ", url=f"https://t.me/{username}?startchannel=true&admin=post_messages+edit_messages+delete_messages+invite_users+manage_chat+change_info"),
            InlineKeyboardButton("✚ Gʀᴏᴜᴘ", url=f"https://t.me/{username}?startgroup=true&admin=post_messages+edit_messages+delete_messages+invite_users+manage_chat+change_info")
        ],
        [
            InlineKeyboardButton("📝 How To Use", callback_data="usage_callback")
        ],
        [
            InlineKeyboardButton("🚀 More Bots", callback_data="show_more_bots")
        ]
    ])
    await message.reply_text(text, reply_markup=buttons)

@app.on_message(filters.command("stats"))
async def stats_command(client, message):
    users, chats = get_stats()
    stats_text = (
        "📊 **𝗕𝗢𝗧 𝗦𝗧𝗔𝗧𝗜𝗦𝗧𝗜𝗖𝗦** 📊\n\n"
        f"👤 **Total Users:** `{users}`\n"
        f"📢 **Connected Channels/Groups:** `{chats}`\n"
    )
    await message.reply_text(stats_text, quote=True)

# --- 📝 USAGE WIZARD (/use) ---

@app.on_message(filters.command("use"))
async def use_command(client, message):
    buttons = InlineKeyboardMarkup([
        [InlineKeyboardButton("Next ▶️ 0/1", callback_data="usage_next")],
        [InlineKeyboardButton("Back ↩️", callback_data="start_back_delete")]
    ])
    await client.send_photo(
        chat_id=message.chat.id,
        photo=USAGE_PHOTO_1,
        caption=USAGE_WIZARD_TEXT_1,
        reply_markup=buttons
    )

# --- 🎙️ BROADCAST SYSTEM ---

@app.on_message(filters.command("broadcastinfo") & filters.user(OWNER_ID))
async def broadcast_info_command(client, message):
    info_text = (
        "🎙️ **Broadcast All Info Command**\n\n"
        "To : /broadcast - **Start New Broadcast**\n"
        "To : /stopBroadcast - **Stop Running Broadcast**\n"
        "To : /BroadMessageDelete - **Delete Last Broadcast Message**\n"
        "To : /autodm - **Setup Join Request Auto DM**\n"
        "To : /stats - **Check Users Count**\n"
    )
    await message.reply_text(info_text)

@app.on_message(filters.command("autodm") & filters.user(OWNER_ID))
async def autodm_init(client, message):
    AUTODM_STATE[message.from_user.id] = {"step": "WAIT_MSG"}
    await message.reply_text(
        "✨ **Auto DM Setup (For Channel Join Requests)**\n\n"
        "Please send the message (Photo, Video, Text, etc.) you want to automatically send to users.\n"
        "*(Tip: You can use `**bold**` and `` `mono` `` formatting!)*\n\n"
        "👇 **Drop it below:**"
    )

@app.on_message(filters.command("broadcast") & filters.user(OWNER_ID))
async def broadcast_init(client, message):
    if IS_BROADCASTING:
        return await message.reply_text("⚠️ A broadcast is already running! Use /stopBroadcast to stop it.")
    
    BROADCAST_STATE[message.from_user.id] = {"step": "WAIT_MSG"}
    await message.reply_text(
        "📢 **Broadcast Setup**\n\n"
        "Please send the message (Photo, Video, Text, etc.) you want to broadcast.\n"
        "👇 **Drop it below:**"
    )

@app.on_message(filters.command("stopBroadcast") & filters.user(OWNER_ID))
async def stop_broadcast_command(client, message):
    global STOP_BROADCAST, IS_BROADCASTING
    if not IS_BROADCASTING:
        return await message.reply_text("❌ No broadcast is currently running.")
    
    STOP_BROADCAST = True
    await message.reply_text("🛑 **Stopping Broadcast...** It will stop shortly.")

@app.on_message(filters.command("BroadMessageDelete") & filters.user(OWNER_ID))
async def delete_broadcast_msg(client, message):
    status_msg = await message.reply_text("♻️ **Deleting last broadcast from all users...**\nThis might take time.")
    
    logs = get_broadcast_logs()
    if not logs:
        return await status_msg.edit("❌ No broadcast logs found to delete.")

    deleted_count = 0
    for user_id, msg_id in logs:
        try:
            await client.delete_messages(chat_id=user_id, message_ids=msg_id)
            deleted_count += 1
            await asyncio.sleep(0.05)
        except FloodWait as e:
            await asyncio.sleep(e.value)
        except Exception:
            pass
    
    clear_broadcast_logs()
    await status_msg.edit(f"✅ **Successfully Deleted Messages!**\n🗑 Count: `{deleted_count}`")

# --- 🔄 COMBINED WIZARD (BROADCAST & AUTODM) ---

@app.on_message(filters.private & filters.user(OWNER_ID) & ~filters.command(["start", "broadcast", "stopBroadcast", "use", "reaction", "stats", "broadcastinfo", "autodm", "BroadMessageDelete"]))
async def wizards_handler(client, message):
    user_id = message.from_user.id
    
    # ---------------- AUTODM LOGIC (UPGRADED) ----------------
    if user_id in AUTODM_STATE:
        state = AUTODM_STATE[user_id]
        step = state["step"]

        if step == "WAIT_MSG":
            file_id = None
            file_type = "text"
            caption = message.caption or message.text or ""

            if message.photo:
                file_id = message.photo.file_id
                file_type = "photo"
            elif message.video:
                file_id = message.video.file_id
                file_type = "video"
            elif message.audio:
                file_id = message.audio.file_id
                file_type = "audio"
            elif message.document:
                file_id = message.document.file_id
                file_type = "document"
            elif message.animation:
                file_id = message.animation.file_id
                file_type = "animation"
            elif message.voice:
                file_id = message.voice.file_id
                file_type = "voice"
            elif message.sticker:
                file_id = message.sticker.file_id
                file_type = "sticker"
            
            AUTODM_STATE[user_id].update({
                "msg_file_id": file_id,
                "msg_type": file_type,
                "caption": caption,
                "step": "WAIT_BTN_FORMAT"
            })
            
            prompt = (
                "✅ **Message Received!**\n\n"
                "⌨️ **Now send me the Buttons Layout.**\n"
                "You can arrange buttons side-by-side using the `|` symbol.\n\n"
                "**Format Example:**\n"
                "`Button 1 - https://link1.com | Button 2 - https://link2.com`\n"
                "`Button 3 - https://link3.com`\n\n"
                "*(Send `done` if you don't want any buttons)*"
            )
            await message.reply_text(prompt)

        elif step == "WAIT_BTN_FORMAT":
            input_text = message.text.strip()
            buttons_list = []
            
            if input_text.lower() != "done":
                lines = input_text.split('\n')
                for line in lines:
                    row_buttons = []
                    parts = line.split('|')
                    for part in parts:
                        if ' - ' in part:
                            name, url = part.split(' - ', 1)
                            url = url.strip()
                            if not url.startswith("http"):
                                url = "https://" + url
                            row_buttons.append({"text": name.strip(), "url": url})
                    if row_buttons:
                        buttons_list.append(row_buttons)
                
                if not buttons_list:
                    await message.reply_text("⚠️ **Invalid format!**\nPlease use `Button Name - Link` format.\nTry again or send `done`.")
                    return
            
            # Save to DB
            data = AUTODM_STATE[user_id]
            set_autodm(data["msg_file_id"], data["msg_type"], data["caption"], buttons_list)
            del AUTODM_STATE[user_id]
            
            await message.reply_text("🎉 **Custom Auto DM Successfully Saved!**\nNew joiners will now receive this message with your Custom Text Formatting & Buttons Layout.")
        return

    # ---------------- BROADCAST LOGIC (UNTOUCHED) ----------------
    if user_id not in BROADCAST_STATE:
        return

    state = BROADCAST_STATE[user_id]
    step = state["step"]

    if step == "WAIT_MSG":
        file_id = None
        file_type = "text"
        caption = message.caption or message.text or ""

        if message.photo:
            file_id = message.photo.file_id
            file_type = "photo"
        elif message.video:
            file_id = message.video.file_id
            file_type = "video"
        elif message.audio:
            file_id = message.audio.file_id
            file_type = "audio"
        elif message.document:
            file_id = message.document.file_id
            file_type = "document"
        elif message.animation:
            file_id = message.animation.file_id
            file_type = "animation"
        elif message.voice:
            file_id = message.voice.file_id
            file_type = "voice"
        elif message.sticker:
            file_id = message.sticker.file_id
            file_type = "sticker"
        
        BROADCAST_STATE[user_id].update({
            "msg_file_id": file_id,
            "msg_type": file_type,
            "caption": caption,
            "step": "WAIT_BTN_NAME"
        })
        
        await message.reply_text(
            "✅ Message Received!\n\n"
            "⌨️ **Enter Button Name** (e.g., 'Join Channel')\n"
            "*(Send 'skip' if you don't want a button)*"
        )

    elif step == "WAIT_BTN_NAME":
        btn_name = message.text
        if btn_name.lower() == "skip":
            BROADCAST_STATE[user_id]["btn_name"] = None
            BROADCAST_STATE[user_id]["step"] = "CONFIRM"
            await show_broadcast_preview(client, user_id)
        else:
            BROADCAST_STATE[user_id]["btn_name"] = btn_name
            BROADCAST_STATE[user_id]["step"] = "WAIT_BTN_URL"
            await message.reply_text("🔗 **Now Enter Button Link** (URL):")

    elif step == "WAIT_BTN_URL":
        BROADCAST_STATE[user_id]["btn_url"] = message.text
        BROADCAST_STATE[user_id]["step"] = "CONFIRM"
        await show_broadcast_preview(client, user_id)


async def show_broadcast_preview(client, user_id):
    data = BROADCAST_STATE[user_id]
    markup = None
    if data.get("btn_name") and data.get("btn_url"):
        markup = InlineKeyboardMarkup([[InlineKeyboardButton(data["btn_name"], url=data["btn_url"])]])
    
    preview_text = "👁‍🗨 **PREVIEW OF BROADCAST**\n\nCheck above. If correct, click SEND."
    
    try:
        if data["msg_type"] == "photo":
            await client.send_photo(user_id, data["msg_file_id"], caption=data["caption"], reply_markup=markup)
        elif data["msg_type"] == "video":
            await client.send_video(user_id, data["msg_file_id"], caption=data["caption"], reply_markup=markup)
        elif data["msg_type"] == "document":
            await client.send_document(user_id, data["msg_file_id"], caption=data["caption"], reply_markup=markup)
        elif data["msg_type"] == "text":
            await client.send_message(user_id, data["caption"], reply_markup=markup)
        
        await client.send_message(
            user_id, 
            preview_text,
            reply_markup=InlineKeyboardMarkup([
                [InlineKeyboardButton("✅ SEND BROADCAST", callback_data="broadcast_confirm")],
                [InlineKeyboardButton("❌ CANCEL", callback_data="broadcast_cancel")]
            ])
        )
    except Exception as e:
        await client.send_message(user_id, f"❌ Error creating preview: {e}\nTry /broadcast again.")
        del BROADCAST_STATE[user_id]

@app.on_callback_query(filters.regex("broadcast_confirm"))
async def start_broadcasting(client, callback_query):
    global IS_BROADCASTING, STOP_BROADCAST
    user_id = callback_query.from_user.id
    if user_id not in BROADCAST_STATE:
        return await callback_query.answer("Session expired.", show_alert=True)
    
    data = BROADCAST_STATE[user_id]
    del BROADCAST_STATE[user_id]
    
    await callback_query.message.edit_text("🚀 **Broadcast Started!**\nUse /stopBroadcast to stop.")
    
    IS_BROADCASTING = True
    STOP_BROADCAST = False
    
    file_id = data.get("msg_file_id")
    msg_type = data.get("msg_type")
    caption = data.get("caption")
    markup = None
    if data.get("btn_name"):
        markup = InlineKeyboardMarkup([[InlineKeyboardButton(data["btn_name"], url=data["btn_url"])]])
        
    clear_broadcast_logs()
    users = get_all_users()
    sent = 0
    failed = 0
    start_time = time.time()
    
    for uid in users:
        if STOP_BROADCAST:
            break
        try:
            msg = None
            if msg_type == "photo":
                msg = await client.send_photo(uid, file_id, caption=caption, reply_markup=markup)
            elif msg_type == "video":
                msg = await client.send_video(uid, file_id, caption=caption, reply_markup=markup)
            elif msg_type == "document":
                msg = await client.send_document(uid, file_id, caption=caption, reply_markup=markup)
            elif msg_type == "text":
                msg = await client.send_message(uid, caption, reply_markup=markup)
            elif msg_type == "audio":
                msg = await client.send_audio(uid, file_id, caption=caption, reply_markup=markup)
            elif msg_type == "sticker":
                msg = await client.send_sticker(uid, file_id, reply_markup=markup)
            elif msg_type == "voice":
                msg = await client.send_voice(uid, file_id, caption=caption, reply_markup=markup)
            elif msg_type == "animation":
                msg = await client.send_animation(uid, file_id, caption=caption, reply_markup=markup)
            
            if msg:
                save_broadcast_log(uid, msg.id)
                sent += 1
            await asyncio.sleep(0.05)
        except FloodWait as e:
            await asyncio.sleep(e.value)
            try:
                if msg_type == "text": await client.send_message(uid, caption, reply_markup=markup)
                sent += 1
            except: pass
        except Exception:
            failed += 1
            
    IS_BROADCASTING = False
    STOP_BROADCAST = False
    elapsed = round(time.time() - start_time, 2)
    await client.send_message(OWNER_ID, f"📣 **Broadcast Completed!**\n\n✅ Sent: `{sent}`\n❌ Failed: `{failed}`\n⏱ Time: `{elapsed}s`")

@app.on_callback_query(filters.regex("broadcast_cancel"))
async def cancel_broadcasting(client, callback_query):
    user_id = callback_query.from_user.id
    if user_id in BROADCAST_STATE:
        del BROADCAST_STATE[user_id]
    await callback_query.message.edit_text("❌ **Broadcast Cancelled.**")

# --- CALLBACK HANDLERS ---

@app.on_callback_query(filters.regex("usage_callback"))
async def usage_handler(client, callback_query):
    await callback_query.answer()
    
    USAGE_TEXT_DISPLAY = (
        "🛠 𝗛𝗼𝘄 𝘁𝗼 𝗨𝘀𝗲 𝗔𝘂𝘁𝗼 𝗥𝗲𝗮𝗰𝘁 𝗕𝗼𝘁:\n\n"
        "1. ➕ Add me as **admin** in your channel or group\n"
        "2. 🔐 Grant me **Message Management + Reaction** permission\n"
        "3. 🌀 I’ll automatically react to every post with emojis.\n\n"
        "✨ Use /start to return to main menu."
    )
    
    buttons = InlineKeyboardMarkup([
        [InlineKeyboardButton("🔙 Back", callback_data="start_back")]
    ])
    
    try:
        await callback_query.message.edit_caption(
            caption=USAGE_TEXT_DISPLAY,
            reply_markup=buttons
        )
    except:
        await callback_query.message.edit_text(
            text=USAGE_TEXT_DISPLAY,
            reply_markup=buttons
        )

@app.on_callback_query(filters.regex("show_more_bots"))
async def more_bots_handler(client, callback_query):
    await callback_query.answer()
    
    MORE_BOTS_TEXT = (
        "🤖 Hᴇʀᴇ Oᴜʀ Mᴏʀᴇ Bᴏᴛs Lɪsᴛ!\n\n"
        "✅ Cʟɪᴄᴋ Oɴ Aɴʏ Bᴜᴛᴛᴏɴ Tᴏ Sᴛᴀʀᴛ Tʜᴇ Bᴏᴛ"
    )
    
    buttons = InlineKeyboardMarkup([
        [InlineKeyboardButton("🤖 𝗥𝗲𝗮𝗰𝘁𝗶𝗼𝗻 𝗕𝗼𝘁 ①", url="http://t.me/PhxAutoReactionBot?start=start")],
        [InlineKeyboardButton("🤖 𝗥𝗲𝗮𝗰𝘁𝗶𝗼𝗻 𝗕𝗼𝘁 ②", url="http://t.me/AutoReactions1Bot?start=start")],
        [InlineKeyboardButton("🤖 𝗥𝗲𝗮𝗰𝘁𝗶𝗼𝗻 𝗕𝗼𝘁 ③", url="http://t.me/auto_reactionx_bot?start=start")],
        [InlineKeyboardButton("🔙 Back", callback_data="start_back")]
    ])
    
    await callback_query.message.edit_media(
        media=InputMediaPhoto(MORE_BOTS_PHOTO, caption=MORE_BOTS_TEXT),
        reply_markup=buttons
    )

@app.on_callback_query(filters.regex("usage_next"))
async def usage_next_handler(client, callback_query):
    await callback_query.answer()
    buttons = InlineKeyboardMarkup([
        [InlineKeyboardButton("Back ↩️", callback_data="usage_back_to_1")]
    ])
    await callback_query.message.edit_media(
        media=InputMediaPhoto(USAGE_PHOTO_2, caption=USAGE_WIZARD_TEXT_2),
        reply_markup=buttons
    )

@app.on_callback_query(filters.regex("usage_back_to_1"))
async def usage_back_handler(client, callback_query):
    await callback_query.answer()
    buttons = InlineKeyboardMarkup([
        [InlineKeyboardButton("Next ▶️ 0/1", callback_data="usage_next")],
        [InlineKeyboardButton("Back ↩️", callback_data="start_back_delete")]
    ])
    await callback_query.message.edit_media(
        media=InputMediaPhoto(USAGE_PHOTO_1, caption=USAGE_WIZARD_TEXT_1),
        reply_markup=buttons
    )

@app.on_callback_query(filters.regex("start_back"))
async def back_to_start_handler(client, callback_query):
    bot_info = await client.get_me()
    await callback_query.answer()
    
    if callback_query.data == "start_back_delete":
        await callback_query.message.delete()
        return

    await callback_query.message.edit_media(
        media=InputMediaPhoto(START_PHOTO, caption=START_TEXT),
        reply_markup=get_start_buttons(bot_info.username)
    )

# --- 😍 AUTO REACTION LOGIC ---

@app.on_message((filters.channel | filters.group) & ~filters.service)
async def auto_react_handler(client, message):
    try:
        add_chat(message.chat.id)
    except:
        pass

    try:
        if REACTION_EMOJIS:
            emoji = random.choice(REACTION_EMOJIS)
            success = await send_reaction_via_http(message.chat.id, message.id, emoji)
            if success:
                print(f"✅ Reacted {emoji} in {message.chat.title}")
    except FloodWait as e:
        print(f"😴 Sleeping {e.value}s (FloodWait)")
        await asyncio.sleep(e.value)
    except Exception as e:
        print(f"❌ Error: {e}")

print("🔥 Auto Reaction + Broadcast Bot is Running... ✅")
app.run()
