import os, json, threading, http.server, time, requests, urllib.parse, asyncio, hmac, hashlib
from datetime import datetime, timedelta
from pyrogram import Client, filters, idle
from pyrogram.enums import ParseMode
from pyrogram.errors import FloodWait
from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, ReplyKeyboardMarkup, KeyboardButton, WebAppInfo
import firebase_admin
from firebase_admin import credentials, firestore_async, firestore
from dotenv import load_dotenv
# --- [ Configuration ] ---

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
load_dotenv(os.getenv("ENV_FILE", os.path.join(BASE_DIR, ".env")))

API_ID = int(os.getenv("API_ID", "0"))
API_HASH = os.getenv("API_HASH")
BOT_TOKEN = os.getenv("TELEGRAM_TOKEN")

WEB_URL = "https://yttott-28862.web.app/"

RENDER_URL = os.getenv(
    "RENDER_EXTERNAL_URL",
    ""
)

LOG_CHANNEL_RAW = os.getenv("LOG_CHANNEL_ID", "mvsspliter").strip()
LOG_CHANNEL_ID = int(LOG_CHANNEL_RAW) if LOG_CHANNEL_RAW.lstrip("-").isdigit() else LOG_CHANNEL_RAW.lstrip("@")
LOG_CHANNEL_USERNAME = os.getenv("LOG_CHANNEL_USERNAME", "mvsspliter").strip().lstrip("@")
ADMIN_ID = 1715890141

KPAY = "09695616691"
AYAPAY = "09695616691"
BEP20 = "0x56824c51be35937da7E60a6223E82cD1795984cC"

# Firebase Init For VPS

if not firebase_admin._apps:

    firebase_credentials = os.getenv(
        "GOOGLE_APPLICATION_CREDENTIALS",
        os.path.join(BASE_DIR, "firebase.json")
    )

    cred = credentials.Certificate(firebase_credentials)

    firebase_admin.initialize_app(cred)

db = firestore_async.client()
admin_db = firestore.client()

app = Client(
    "luxury_spliter_bot",
    api_id=API_ID,
    api_hash=API_HASH,
    bot_token=BOT_TOKEN
)

# --- [ UI & Messages ] ---

TEXTS = {

    'my': {

        'intro': (
            "👑 **Luxury Movie Spliter Pro မှ ကြိုဆိုပါတယ်** 👑\n\n"
            "မြန်မာနိုင်ငံ၏ အဆင့်မြင့်ဆုံးနှင့် အမြန်ဆုံး "
            "ဗီဒီယိုဖြတ်စက်စနစ်ကို အသုံးပြုလိုက်ပါ။\n\n"

            "🚀 **အဓိက လုပ်ဆောင်ချက်များ:**\n"

            "• **Smart Splitting:** "
            "အပိုင်းတိုလေးများ မကျန်စေဘဲ "
            "စနစ်တကျ ဖြတ်ပေးခြင်း\n"

            "• **Dual Watermark:** "
            "လှုပ်ရှားနေသော စာသားများနှင့် "
            "ကိုယ်ပိုင် Logo များ\n"

            "• **Universal Download:** "
            "Telegram, Tiktok, FB နှင့် "
            "အခြားလင့်ခ်ပေါင်းစုံ "
            "(Stream Link များနှင့် "
            "Youtube Link အသုံးပြု၍မရပါ။)\n\n"

            "👇 စတင်ရန် ဗီဒီယိုတစ်ခုကို "
            "Forward လုပ်ပေးပါ "
            "သို့မဟုတ် လင့်ခ်တစ်ခု ပို့ပေးပါ။"
        ),

        'buy_msg': (
            "💎 **Luxury Premium Upgrade** 💎\n\n"

            "ပရီမီယံ အဖွဲ့ဝင်ဖြစ်ခြင်းဖြင့် "
            "ပိုမိုကောင်းမွန်သော "
            "Luxury Experience ကို "
            "ခံစားလိုက်ပါ။\n\n"

            "✨ **Premium အကျိုးကျေးဇူးများ**\n"
            "• **High Quality Output:** "
            "ဗီဒီယိုအရည်အသွေးကို ပိုကောင်းအောင် ထိန်းပေးမည်\n"
            "• **No Bot Watermark:** "
            "`https://t.me/tt_uploader_bot` watermark မပါတော့ပါ\n"
            "• **Cleaner Video:** "
            "ကိုယ်ပိုင် watermark/logo ကိုသာ သန့်သန့်ရှင်းရှင်း ထည့်နိုင်မည်\n"
            "• **Premium Priority:** "
            "Queue ထဲတွင် ပရီမီယံ task များကို အရင်စီပေးမည်\n\n"

            "💰 **ဈေးနှုန်း:** "
            "`3000 Ks` "
            "(သို့မဟုတ်) "
            "`1.0 USDT` "
            "(တစ်လစာ)\n"

            "💳 **KPay/AYAPay:** `{kpay}`\n"
            "💳 **BEP20:** `{BEP20}`\n"
            "🆔 **သင့်အိုင်ဒီ:** `{uid}`\n\n"

            "⚠️ **အရေးကြီး:** "
            "ငွေလွှဲပြီးပါက "
            "**ပြေစာ (Screenshot)** "
            "ကို ဤနေရာသို့ ပို့ပေးပါ။"
        ),

        'open': "🚀 Mini App ဖွင့်ရန်",
        'profile': "👤 My Profile",
        'buy': "💎 Premium ဝယ်ရန်",
        'refer': "👥 Refer Link",

        'ack': (
            "✅ ဗီဒီယို လက်ခံရရှိပါသည်။ "
            "ခဏစောင့်ပေးပါ။"
        ),

        'v_ready': (
            "✅ **ဗီဒီယိုကို မှတ်မိပါသည်။**\n"
            "🔗 လင့်ခ်: `{v_link}`"
        ),

        'refer_msg': (
            "👥 **Referral Program**\n\n"

            "🔗 Link: `{ref_link}`\n"

            "👥 ဖိတ်ကြားထားသူ: "
            "`{count}` ယောက်\n\n"

            "🎁 Refer ၅ ယောက်ပြည့်တိုင်း "
            "Premium ၁၀ ရက် "
            "အလိုအလျောက် ရရှိပါမည်။"
        ),

        'reward_msg': (
            "🎉 **ဂုဏ်ယူပါတယ်!**\n\n"

            "👑 Refer ၅ ယောက်ပြည့်သွားသဖြင့်\n"

            "Premium ၁၀ ရက် "
            "အလိုအလျောက် ရရှိပါပြီ။"
        ),

        'expired_msg': (
            "⚠️ **Premium သက်တမ်းကုန်သွားပါပြီ။**\n\n"
            "သင့်အကောင့်သည် Free Member "
            "အဖြစ် ပြန်လည်ပြောင်းလဲသွားပါပြီ။"
        ),

        'pay_done': (
            "✅ **ပြေစာ ပို့ပြီးပါပြီ။**\n"
            "Admin မှ မကြာမီ "
            "စစ်ဆေးပေးပါမည်။ "
            "ကျေးဇူးတင်ပါသည်။"
        ),

        'blocked_msg': (
            "⛔ **သင့်အကောင့်သည် Block ခံထားရပါပြီ။**\n\n"
            "အသုံးပြုခွင့် ယာယီပိတ်ထားပါသည်။ "
            "လိုအပ်ပါက Admin ကိုဆက်သွယ်ပါ။"
        )
    },

    'en': {

        'intro': (
            "👑 **Welcome to Luxury Movie Spliter Pro** 👑\n\n"

            "The most advanced and fastest "
            "video splitting system in Myanmar.\n\n"

            "🚀 **Key Features:**\n"

            "• **Smart Splitting:** "
            "Seamlessly splits videos "
            "without leaving tiny leftover segments\n"

            "• **Dual Watermark:** "
            "Animated text watermarks "
            "with customizable personal logos\n"

            "• **Universal Download:** "
            "Supports Telegram, TikTok, "
            "Facebook, and many other links "
            "(Stream links and YouTube links "
            "are not supported.)\n\n"

            "👇 Forward a video or send a link to start."
        ),

        'buy_msg': (
            "💎 **Luxury Premium Upgrade** 💎\n\n"

            "✨ **Premium Benefits**\n"
            "• **High Quality Output:** keeps the video quality much better\n"
            "• **No Bot Watermark:** removes the `https://t.me/tt_uploader_bot` watermark\n"
            "• **Cleaner Video:** only your own watermark/logo is applied\n"
            "• **Premium Priority:** premium tasks are prioritized in the queue\n\n"

            "💰 Price: 3000 Ks / 1.0 USDT\n"

            "💳 KPay/AYAPay: `{kpay}`\n"
            "💳 BEP20: `{BEP20}`\n"
            "🆔 ID: `{uid}`\n\n"

            "⚠️ Send Screenshot here after payment."
        ),

        'open': "🚀 Open Mini App",
        'profile': "👤 My Profile",
        'buy': "💎 Buy Premium",
        'refer': "👥 Refer Link",

        'ack': (
            "✅ Video received! Please wait."
        ),

        'v_ready': (
            "✅ **Video recognized!**\n"
            "🔗 Link: `{v_link}`"
        ),

        'refer_msg': (
            "👥 **Referral Program**\n\n"

            "🔗 Link: `{ref_link}`\n"

            "👥 Referrals: `{count}` people\n\n"

            "🎁 Earn 10 Days Premium "
            "automatically for every "
            "5 referrals."
        ),

        'reward_msg': (
            "🎉 **Congratulations!**\n\n"

            "👑 You received "
            "10 Days Premium\n"

            "for successfully "
            "referring 5 users."
        ),

        'expired_msg': (
            "⚠️ **Your Premium has expired.**\n\n"
            "Your account has been reverted "
            "to Free Member."
        ),

        'pay_done': (
            "✅ **Receipt sent!**\n"
            "Admin will verify it soon. "
            "Thank you."
        ),

        'blocked_msg': (
            "⛔ **Your account has been blocked.**\n\n"
            "Your access is temporarily disabled. "
            "Please contact admin if needed."
        )
    }
}

def make_web_app_url(uid=None, link=None):

    params = {}

    if uid:
        params['uid'] = str(uid)

    if link:
        params['link'] = link

    if not params:
        return WEB_URL

    separator = '&' if '?' in WEB_URL else '?'

    return f"{WEB_URL}{separator}{urllib.parse.urlencode(params)}"

def make_admin_url():

    params = {}

    if RENDER_URL:
        params["api"] = RENDER_URL.rstrip("/")

    url = urllib.parse.urljoin(WEB_URL, "admin.html")

    return f"{url}?{urllib.parse.urlencode(params)}" if params else url

def get_main_kb(lang, uid=None):

    l = lang if lang in TEXTS else 'my'

    return ReplyKeyboardMarkup([

        [
            KeyboardButton(
                TEXTS[l]['open'],
                web_app=WebAppInfo(url=make_web_app_url(uid=uid))
            )
        ],

        [
            KeyboardButton(TEXTS[l]['profile']),
            KeyboardButton(TEXTS[l]['refer'])
        ],

        [
            KeyboardButton(TEXTS[l]['buy'])
        ]

    ], resize_keyboard=True)

# --- [ Helper Functions ] ---

def self_ping():

    if not RENDER_URL:
        return

    while True:

        try:

            time.sleep(300)

            requests.get(RENDER_URL)

        except:
            pass

def build_log_message_link(message_id):

    if LOG_CHANNEL_USERNAME:
        return f"https://t.me/{LOG_CHANNEL_USERNAME}/{message_id}"

    if isinstance(LOG_CHANNEL_ID, str):
        return f"https://t.me/{LOG_CHANNEL_ID}/{message_id}"

    return (
        f"https://t.me/c/"
        f"{str(LOG_CHANNEL_ID).replace('-100', '')}/"
        f"{message_id}"
    )

def normalize_chat_id(value):

    value = str(value).strip()

    if value.startswith("@"):
        value = value[1:]

    return int(value) if value.lstrip("-").isdigit() else value

async def get_log_channel_config():

    channel_id = LOG_CHANNEL_USERNAME or LOG_CHANNEL_ID
    username = LOG_CHANNEL_USERNAME

    try:
        conf = await db.collection('settings').document('config').get()

        if conf.exists:
            data = conf.to_dict() or {}
            saved_channel = data.get('log_channel_id')
            saved_username = data.get('log_channel_username')

            if saved_channel:
                channel_id = normalize_chat_id(saved_channel)

            if saved_username:
                username = str(saved_username).strip().lstrip("@")

    except Exception as e:
        print(f"⚠️ Failed to load log channel config: {e}", flush=True)

    return channel_id, username

def build_message_link(channel_id, username, message_id):

    if username:
        return f"https://t.me/{username}/{message_id}"

    if isinstance(channel_id, str):
        return f"https://t.me/{channel_id}/{message_id}"

    return (
        f"https://t.me/c/"
        f"{str(channel_id).replace('-100', '')}/"
        f"{message_id}"
    )

async def send_admin_log(text):

    try:
        await app.send_message(ADMIN_ID, text)
    except:
        pass

async def store_media_in_log_channel(c, m):

    channel_id, _ = await get_log_channel_config()

    try:
        return await m.copy(channel_id)
    except Exception as copy_error:
        print(f"⚠️ Log channel copy failed: {copy_error}", flush=True)

        caption = m.caption or ""

        try:
            if m.video:
                return await c.send_video(
                    channel_id,
                    m.video.file_id,
                    caption=caption
                )

            if m.document:
                return await c.send_document(
                    channel_id,
                    m.document.file_id,
                    caption=caption
                )

            raise ValueError("No video/document media found")

        except Exception as fallback_error:
            raise RuntimeError(
                f"copy failed: {copy_error}; file_id fallback failed: {fallback_error}"
            ) from fallback_error

async def check_premium(uid):

    user_ref = db.collection('users').document(str(uid))

    user_doc = await user_ref.get()

    if not user_doc.exists:
        return False

    data = user_doc.to_dict() or {}

    expiry = data.get('expiry_date')

    if isinstance(expiry, datetime):

        now = (
            datetime.now(expiry.tzinfo)
            if getattr(expiry, "tzinfo", None)
            else datetime.utcnow()
        )

        if now > expiry:

            lang = data.get('lang', 'my')

            await user_ref.update({
                'is_premium': False,
                'expiry_date': 'N/A'
            })

            try:

                await app.send_message(
                    int(uid),
                    TEXTS[lang]['expired_msg']
                )

            except:
                pass

            return False

    return data.get('is_premium', False)

async def premium_expiry_watcher():

    print("⏰ Premium expiry watcher online...", flush=True)

    while True:

        try:

            premium_users = db.collection('users') \
                .where("is_premium", "==", True) \
                .stream()

            async for user_doc in premium_users:

                await check_premium(user_doc.id)

            await asyncio.sleep(3600)

        except Exception as e:

            print(f"⚠️ Premium expiry watcher error: {e}", flush=True)
            await asyncio.sleep(300)

async def is_user_blocked(uid):

    user_doc = await db.collection('users').document(str(uid)).get()

    if not user_doc.exists:
        return False, 'my'

    data = user_doc.to_dict() or {}

    return data.get('is_blocked', False) is True, data.get('lang', 'my')

async def stop_if_blocked(message, uid):

    blocked, lang = await is_user_blocked(uid)

    if not blocked:
        return False

    await message.reply_text(
        TEXTS.get(lang, TEXTS['my'])['blocked_msg']
    )

    return True

async def ack_listener():

    print("📡 Task Listener Online...", flush=True)

    while True:

        try:

            pendings = db.collection('tasks') \
                .where("status", "==", "pending") \
                .stream()

            async for p in pendings:

                data = p.to_dict()

                uid = int(data.get('user_id', 0))

                lang = data.get('lang', 'my')

                if uid <= 0:

                    await p.reference.update({
                        'status': 'failed',
                        'error': 'Missing Telegram user id'
                    })

                    continue

                blocked, blocked_lang = await is_user_blocked(uid)

                if blocked:

                    await p.reference.update({
                        'status': 'failed',
                        'error': 'account_blocked_by_admin',
                        'recipient_id': str(uid)
                    })

                    try:
                        await app.send_message(
                            uid,
                            TEXTS.get(blocked_lang, TEXTS['my'])['blocked_msg']
                        )
                    except:
                        pass

                    continue

                current_is_premium = await check_premium(uid)

                await db.collection('users').document(str(uid)).set({
                    'uid': str(uid),
                    'last_active_at': firestore.SERVER_TIMESTAMP
                }, merge=True)

                update_data = {
                    'status': 'queued',
                    'recipient_id': str(uid),
                    'is_premium': current_is_premium
                }

                await p.reference.update(update_data)

                await app.send_message(
                    uid,
                    TEXTS[lang]['ack'],
                    reply_markup=get_main_kb(lang, uid)
                )

            await asyncio.sleep(4)

        except:

            await asyncio.sleep(10)

# --- [ Handlers ] ---

@app.on_message(filters.command("setstart") & filters.user(ADMIN_ID))
async def set_start_msg(c, m):

    args = m.text.split(maxsplit=2)

    if len(args) < 3:

        return await m.reply_text(
            "`/setstart [my/en] [text]`"
        )

    target = args[1].lower()

    text = args[2]

    await db.collection('settings') \
        .document('config') \
        .set({
            f'start_msg_{target}': text
        }, merge=True)

    await m.reply_text(
        f"✅ {target.upper()} စာသား ပြောင်းပြီးပါပြီ။"
    )

@app.on_message(filters.command("admin_atom") & filters.user(ADMIN_ID))
async def open_admin_panel(c, m):

    btn = InlineKeyboardMarkup([
        [
            InlineKeyboardButton(
                "Open Admin Panel",
                web_app=WebAppInfo(url=make_admin_url())
            )
        ]
    ])

    await m.reply_text(
        "Admin panel ကိုဖွင့်ပါ။",
        reply_markup=btn
    )

@app.on_message(filters.command("checklog") & filters.user(ADMIN_ID))
async def check_log_channel(c, m):

    try:
        channel_id, username = await get_log_channel_config()
        me = await c.get_me()
        member = await c.get_chat_member(channel_id, me.id)
        test_msg = await c.send_message(
            channel_id,
            "✅ Log channel test from Luxury Spliter Bot."
        )

        await m.reply_text(
            "✅ Log channel OK\n"
            f"Channel: `{channel_id}`\n"
            f"Bot status: `{member.status}`\n"
            f"Test link: {build_message_link(channel_id, username, test_msg.id)}"
        )

    except Exception as e:
        await m.reply_text(
            "⚠️ Log channel မအောင်သေးပါ။\n\n"
            f"Channel: `{(await get_log_channel_config())[0]}`\n"
            f"Error: `{type(e).__name__}: {e}`\n\n"
            "Bot ကို channel ထဲ add လုပ်ပြီး Post Messages permission ပေးထားရပါမယ်။"
        )

@app.on_message(filters.command("setlog") & filters.user(ADMIN_ID))
async def set_log_channel(c, m):

    args = m.text.split(maxsplit=1)
    channel_value = args[1].strip() if len(args) > 1 else ""

    if not channel_value:
        return await m.reply_text(
            "Usage:\n"
            "`/setlog -1001234567890`\n"
            "သို့မဟုတ် public channel ဆို `/setlog @channelusername`"
        )

    channel_id = normalize_chat_id(channel_value)
    username = str(channel_id).strip().lstrip("@") if isinstance(channel_id, str) else ""

    try:
        me = await c.get_me()
        member = await c.get_chat_member(channel_id, me.id)
        test_msg = await c.send_message(
            channel_id,
            "✅ Log channel connected."
        )

        await db.collection('settings').document('config').set({
            'log_channel_id': str(channel_id),
            'log_channel_username': username
        }, merge=True)

        await m.reply_text(
            "✅ Log channel set ပြီးပါပြီ။\n"
            f"Channel: `{channel_id}`\n"
            f"Bot status: `{member.status}`\n"
            f"Test link: {build_message_link(channel_id, username, test_msg.id)}"
        )

    except Exception as e:
        await m.reply_text(
            "❌ Log channel set မအောင်ပါ။\n\n"
            f"Channel: `{channel_id}`\n"
            f"Error: `{type(e).__name__}: {e}`\n\n"
            "Channel ID မှန်လား၊ bot ကို channel ထဲ admin/post permission ပေးထားလား စစ်ပါ။"
        )

@app.on_message(filters.command("weburl") & filters.user(ADMIN_ID))
async def check_web_url(c, m):

    try:
        resp = requests.get(WEB_URL, timeout=15)
        status = resp.status_code
        ok = "Luxury Spliter Pro" in resp.text
    except Exception as e:
        status = f"{type(e).__name__}: {e}"
        ok = False

    await m.reply_text(
        "🌐 Current Mini App URL\n"
        f"`{WEB_URL}`\n\n"
        f"HTTP: `{status}`\n"
        f"Page OK: `{ok}`\n\n"
        f"Sample: `{make_web_app_url(uid=m.from_user.id)}`"
    )

@app.on_message(filters.command("broadcast") & filters.user(ADMIN_ID))
async def broadcast_to_users(c, m):

    text = m.text.split(maxsplit=1)[1] if m.text and len(m.text.split(maxsplit=1)) > 1 else ""
    source = m.reply_to_message

    if not text and not source:
        return await m.reply_text(
            "Usage:\n"
            "`/broadcast စာသား`\n\n"
            "သို့မဟုတ် ပို့ချင်တဲ့ message ကို reply လုပ်ပြီး `/broadcast` ရိုက်ပါ။"
        )

    status_msg = await m.reply_text("📣 Broadcast စနေပါပြီ...")

    sent = 0
    failed = 0
    total = 0

    users = db.collection('users').stream()

    async for user_doc in users:
        uid = user_doc.id
        total += 1

        try:
            if source:
                await source.copy(int(uid))
            else:
                await c.send_message(
                    int(uid),
                    text,
                    parse_mode=ParseMode.MARKDOWN
                )

            sent += 1

        except FloodWait as e:
            await asyncio.sleep(e.value)

            try:
                if source:
                    await source.copy(int(uid))
                else:
                    await c.send_message(
                        int(uid),
                        text,
                        parse_mode=ParseMode.MARKDOWN
                    )

                sent += 1

            except Exception as retry_error:
                failed += 1
                print(f"Broadcast failed for {uid}: {retry_error}", flush=True)

        except Exception as e:
            failed += 1
            print(f"Broadcast failed for {uid}: {e}", flush=True)

        if total % 25 == 0:
            try:
                await status_msg.edit_text(
                    f"📣 Broadcast လုပ်နေပါတယ်...\n"
                    f"Total: `{total}`\n"
                    f"Sent: `{sent}`\n"
                    f"Failed: `{failed}`"
                )
            except:
                pass

        await asyncio.sleep(0.05)

    await status_msg.edit_text(
        f"✅ Broadcast ပြီးပါပြီ။\n"
        f"Total: `{total}`\n"
        f"Sent: `{sent}`\n"
        f"Failed: `{failed}`"
    )

@app.on_message(filters.command("start") & filters.private)
async def start(c, m):

    uid = str(m.from_user.id)

    user_ref = db.collection('users').document(uid)

    if (await user_ref.get()).exists and await stop_if_blocked(m, uid):
        return

    # Referral System
    if len(m.text.split()) > 1:

        ref_by = m.text.split()[1]

        if ref_by != uid:

            ref_user_ref = db.collection('users').document(ref_by)

            await ref_user_ref.update({
                'referral_count': firestore_async.Increment(1)
            })

            ref_user = await ref_user_ref.get()

            ref_data = ref_user.to_dict() or {}

            ref_count = ref_data.get(
                'referral_count',
                0
            )

            # Every 5 referrals => 10 days premium
            if ref_count % 5 == 0:

                current_expiry = ref_data.get(
                    'expiry_date'
                )

                if isinstance(current_expiry, datetime):

                    expiry_date = current_expiry + timedelta(days=10)

                else:

                    expiry_date = datetime.utcnow() + timedelta(days=10)

                ref_lang = ref_data.get('lang', 'my')

                await ref_user_ref.update({

                    'is_premium': True,
                    'expiry_date': expiry_date

                })

                await app.send_message(

                    int(ref_by),

                    TEXTS[ref_lang]['reward_msg']
                )

    # Create User
    if not (await user_ref.get()).exists:

        await user_ref.set({

            'lang': 'my',
            'uid': uid,
            'is_premium': False,
            'expiry_date': 'N/A',
            'referral_count': 0

        })

    kb = InlineKeyboardMarkup([

        [

            InlineKeyboardButton(
                "🇲🇲 မြန်မာစာ",
                callback_data="lang_my"
            ),

            InlineKeyboardButton(
                "🇺🇸 English",
                callback_data="lang_en"
            )

        ]

    ])

    await m.reply_text(

        "Choose Language / "
        "ဘာသာစကားရွေးချယ်ပါ -",

        reply_markup=kb
    )

@app.on_callback_query(filters.regex("^lang_"))
async def set_lang(c, q):

    lang = q.data.split("_")[1]

    uid = str(q.from_user.id)

    blocked, blocked_lang = await is_user_blocked(uid)

    if blocked:
        await q.answer(
            TEXTS.get(blocked_lang, TEXTS['my'])['blocked_msg'],
            show_alert=True
        )
        return

    await db.collection('users') \
        .document(uid) \
        .update({
            'lang': lang
        })

    await q.message.delete()

    conf = await db.collection('settings') \
        .document('config').get()

    if conf.exists:

        intro = conf.to_dict().get(
            f'start_msg_{lang}',
            TEXTS[lang]['intro']
        )

    else:

        intro = TEXTS[lang]['intro']

    await c.send_message(

        uid,
        intro,
        reply_markup=get_main_kb(lang, uid)
    )

@app.on_message(
    (filters.video | filters.document)
    & filters.private
)
async def handle_video_upload(c, m):

    uid = str(m.from_user.id)

    if await stop_if_blocked(m, uid):
        return

    await check_premium(uid)

    lang = (
        await db.collection('users')
        .document(uid).get()
    ).to_dict().get('lang', 'my')

    try:

        log_msg = await store_media_in_log_channel(c, m)

        channel_id, username = await get_log_channel_config()
        v_link = build_message_link(channel_id, username, log_msg.id)

        btn = InlineKeyboardMarkup([

            [
                InlineKeyboardButton(

                    TEXTS[lang]['open'],

                    web_app=WebAppInfo(
                        url=make_web_app_url(uid=uid, link=v_link)
                    )
                )
            ]

        ])

        await m.reply_text(

            TEXTS[lang]['v_ready'].format(
                v_link=v_link
            ),

            reply_markup=btn
        )

    except Exception as e:

        err = f"{type(e).__name__}: {e}"
        print(f"❌ Log channel upload failed for user {uid}: {err}", flush=True)

        await send_admin_log(
            "❌ Log channel upload failed\n"
            f"User: `{uid}`\n"
            f"Channel: `{(await get_log_channel_config())[0]}`\n"
            f"Error: `{err}`"
        )

        await m.reply_text(
            "⚠️ ဗီဒီယိုကို log channel ထဲ မတင်နိုင်သေးပါ။\n"
            "Admin ကိုအသိပေးပြီးပါပြီ။ ခဏနေပြန်စမ်းပေးပါ။\n\n"
            f"`{err}`"
        )

@app.on_message(filters.photo & filters.private)
async def handle_receipt(c, m):

    uid = str(m.from_user.id)

    if await stop_if_blocked(m, uid):
        return

    lang = (
        await db.collection('users')
        .document(uid).get()
    ).to_dict().get('lang', 'my')

    await m.copy(

        ADMIN_ID,

        caption=(
            f"💰 **New Receipt**\n"
            f"From: {m.from_user.first_name}\n"
            f"ID: `{uid}`"
        )
    )

    await m.reply_text(

        TEXTS[lang]['pay_done'],

        reply_markup=get_main_kb(lang, uid)
    )

@app.on_message(filters.text & filters.private)
async def handle_text(c, m):

    uid = str(m.from_user.id)

    if await stop_if_blocked(m, uid):
        return

    # Premium expiry check
    await check_premium(uid)

    u_doc = (
        await db.collection('users')
        .document(uid).get()
    ).to_dict() or {}

    lang = u_doc.get('lang', 'my')

    # Profile
    if m.text in [

        TEXTS['my']['profile'],
        TEXTS['en']['profile']

    ]:

        expiry = u_doc.get(
            'expiry_date',
            'N/A'
        )

        if isinstance(expiry, datetime):

            mm_time = expiry + timedelta(
                hours=6,
                minutes=30
            )

            expiry_str = mm_time.strftime(
                '%Y-%m-%d %H:%M'
            )

        else:

            expiry_str = str(expiry)

            if expiry_str == 'N/A' and lang == 'my':
                expiry_str = 'မရှိပါ'

        if lang == 'my':

            status = (
                "ပရီမီယံ အဖွဲ့ဝင် ✅"
                if u_doc.get('is_premium', False)
                else "ရိုးရိုးအဖွဲ့ဝင် (Free) ❌"
            )

            profile_text = (

                f"👤 **ကျွန်ုပ်၏ ပရိုဖိုင်**\n\n"

                f"🆔 အိုင်ဒီ: `{uid}`\n"

                f"👑 အဆင့်အတန်း: {status}\n"

                f"📅 သက်တမ်းကုန်ရက်: `{expiry_str}`\n"

                f"👥 ဖိတ်ကြားထားသူ: "
                f"`{u_doc.get('referral_count', 0)}` ယောက်"
            )

        else:

            status = (
                "Premium Member ✅"
                if u_doc.get('is_premium', False)
                else "Free Member ❌"
            )

            profile_text = (

                f"👤 **My Profile**\n\n"

                f"🆔 ID: `{uid}`\n"

                f"👑 Status: {status}\n"

                f"📅 Expiry: `{expiry_str}`\n"

                f"👥 Ref: "
                f"`{u_doc.get('referral_count', 0)}` people"
            )

        await m.reply_text(profile_text)

    # Buy Premium
    elif m.text in [

        TEXTS['my']['buy'],
        TEXTS['en']['buy']

    ]:

        await m.reply_text(

            TEXTS[lang]['buy_msg'].format(

                uid=uid,
                kpay=KPAY,
                BEP20=BEP20

            )
        )

    # Refer
    elif m.text in [

        TEXTS['my']['refer'],
        TEXTS['en']['refer']

    ]:

        bot_u = (await c.get_me()).username

        await m.reply_text(

            TEXTS[lang]['refer_msg'].format(

                ref_link=f"https://t.me/{bot_u}?start={uid}",

                count=u_doc.get(
                    'referral_count',
                    0
                )
            )
        )

    # Link
    elif m.text.startswith("http"):

        btn = InlineKeyboardMarkup([

            [
                InlineKeyboardButton(

                    TEXTS[lang]['open'],

                    web_app=WebAppInfo(
                        url=make_web_app_url(uid=uid, link=m.text.strip())
                    )
                )
            ]

        ])

        await m.reply_text(

            TEXTS[lang]['v_ready'].format(
                v_link=m.text.strip()
            ),

            reply_markup=btn
        )

# --- [ HTTP Server ] ---

def json_safe(value):

    if isinstance(value, datetime):
        return value.isoformat()

    if hasattr(value, "isoformat"):
        return value.isoformat()

    if isinstance(value, dict):
        return {k: json_safe(v) for k, v in value.items()}

    if isinstance(value, list):
        return [json_safe(v) for v in value]

    return value

def verify_admin_init_data(init_data):

    if not BOT_TOKEN or not init_data:
        return False

    parsed = dict(urllib.parse.parse_qsl(init_data, keep_blank_values=True))
    received_hash = parsed.pop("hash", "")

    if not received_hash:
        return False

    data_check = "\n".join(
        f"{key}={value}" for key, value in sorted(parsed.items())
    )

    secret = hmac.new(
        b"WebAppData",
        BOT_TOKEN.encode(),
        hashlib.sha256
    ).digest()

    expected_hash = hmac.new(
        secret,
        data_check.encode(),
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(expected_hash, received_hash):
        return False

    try:
        auth_date = int(parsed.get("auth_date", "0"))
        if auth_date and time.time() - auth_date > 86400 * 2:
            return False

        user = json.loads(parsed.get("user", "{}"))
        return int(user.get("id", 0)) == ADMIN_ID

    except Exception:
        return False

def task_user_id(task):

    return str(
        task.get("recipient_id")
        or task.get("chat_id")
        or task.get("user_id")
        or ""
    )

def is_blocked_task(task):

    error_text = (
        f"{task.get('error', '')} "
        f"{task.get('error_detail', '')}"
    ).lower()

    return task.get("status") == "failed" and (
        "recipient_unreachable" in error_text
        or "blocked" in error_text
        or "forbidden" in error_text
    )

def admin_dashboard_payload():

    users = []
    for doc in admin_db.collection("users").stream():
        data = doc.to_dict() or {}
        data["id"] = doc.id
        users.append(json_safe(data))

    task_query = (
        admin_db.collection("tasks")
        .order_by("createdAt", direction=firestore.Query.DESCENDING)
        .limit(120)
    )

    tasks = []
    for doc in task_query.stream():
        data = doc.to_dict() or {}
        data["id"] = doc.id
        tasks.append(json_safe(data))

    blocked_users = sorted({
        task_user_id(task)
        for task in tasks
        if is_blocked_task(task) and task_user_id(task)
    })

    return {
        "users": users,
        "tasks": tasks,
        "blocked_users": blocked_users,
        "server_time": datetime.utcnow().isoformat()
    }

class AdminHTTPHandler(http.server.SimpleHTTPRequestHandler):

    def end_headers(self):

        self.send_header("Access-Control-Allow-Origin", "*")
        self.send_header(
            "Access-Control-Allow-Headers",
            "Content-Type"
        )
        self.send_header(
            "Access-Control-Allow-Methods",
            "GET, POST, OPTIONS"
        )
        super().end_headers()

    def do_OPTIONS(self):

        self.send_response(204)
        self.end_headers()

    def read_json_body(self):

        length = int(self.headers.get("Content-Length", "0"))

        if length <= 0:
            return {}

        raw = self.rfile.read(length).decode("utf-8")
        return json.loads(raw or "{}")

    def send_json(self, status, payload):

        encoded = json.dumps(payload, ensure_ascii=False).encode("utf-8")
        self.send_response(status)
        self.send_header("Content-Type", "application/json; charset=utf-8")
        self.send_header("Content-Length", str(len(encoded)))
        self.end_headers()
        self.wfile.write(encoded)

    def require_admin(self, body=None):

        init_data = ""

        if body:
            init_data = body.get("initData", "")

        if not init_data:
            query = urllib.parse.urlparse(self.path).query
            init_data = urllib.parse.parse_qs(query).get("initData", [""])[0]

        return verify_admin_init_data(init_data)

    def do_GET(self):

        parsed = urllib.parse.urlparse(self.path)

        if parsed.path == "/api/admin/data":
            if not self.require_admin():
                return self.send_json(403, {"error": "Forbidden"})

            try:
                return self.send_json(200, admin_dashboard_payload())
            except Exception as e:
                return self.send_json(
                    500,
                    {"error": f"{type(e).__name__}: {e}"}
                )

        return super().do_GET()

    def do_POST(self):

        parsed = urllib.parse.urlparse(self.path)

        if not parsed.path.startswith("/api/admin/"):
            return self.send_json(404, {"error": "Not found"})

        try:
            body = self.read_json_body()

            if not self.require_admin(body):
                return self.send_json(403, {"error": "Forbidden"})

            if parsed.path == "/api/admin/premium":
                uid = str(body.get("uid", "")).strip()
                action = str(body.get("action", "")).strip()

                if not uid.isdigit():
                    return self.send_json(400, {"error": "Invalid user id"})

                user_ref = admin_db.collection("users").document(uid)

                if action == "grant":
                    expiry_date = str(body.get("expiryDate", "")).strip()

                    if not expiry_date:
                        return self.send_json(
                            400,
                            {"error": "Missing expiry date"}
                        )

                    expiry = datetime.fromisoformat(
                        f"{expiry_date}T23:59:59+06:30"
                    )

                    user_ref.set({
                        "uid": uid,
                        "is_premium": True,
                        "expiry_date": expiry,
                        "premium_updated_at": firestore.SERVER_TIMESTAMP,
                        "premium_updated_by": str(ADMIN_ID)
                    }, merge=True)

                    return self.send_json(
                        200,
                        {"ok": True, "message": "Premium granted"}
                    )

                if action == "revoke":
                    user_ref.set({
                        "uid": uid,
                        "is_premium": False,
                        "expiry_date": "N/A",
                        "premium_updated_at": firestore.SERVER_TIMESTAMP,
                        "premium_updated_by": str(ADMIN_ID)
                    }, merge=True)

                    return self.send_json(
                        200,
                        {"ok": True, "message": "Premium revoked"}
                    )

                return self.send_json(400, {"error": "Invalid action"})

            if parsed.path == "/api/admin/user":
                uid = str(body.get("uid", "")).strip()
                action = str(body.get("action", "")).strip()

                if not uid.isdigit():
                    return self.send_json(400, {"error": "Invalid user id"})

                user_ref = admin_db.collection("users").document(uid)

                if action == "block":
                    user_ref.set({
                        "uid": uid,
                        "is_blocked": True,
                        "blocked_at": firestore.SERVER_TIMESTAMP,
                        "blocked_by": str(ADMIN_ID)
                    }, merge=True)

                    return self.send_json(
                        200,
                        {"ok": True, "message": "User blocked"}
                    )

                if action == "unblock":
                    user_ref.set({
                        "uid": uid,
                        "is_blocked": False,
                        "unblocked_at": firestore.SERVER_TIMESTAMP,
                        "unblocked_by": str(ADMIN_ID)
                    }, merge=True)

                    return self.send_json(
                        200,
                        {"ok": True, "message": "User unblocked"}
                    )

                return self.send_json(400, {"error": "Invalid action"})

            if parsed.path == "/api/admin/task":
                task_id = str(body.get("taskId", "")).strip()
                action = str(body.get("action", "")).strip()

                if not task_id:
                    return self.send_json(400, {"error": "Missing task id"})

                task_ref = admin_db.collection("tasks").document(task_id)

                if action == "retry":
                    task_ref.set({
                        "status": "queued",
                        "last_sent_index": -1,
                        "error": firestore.DELETE_FIELD,
                        "error_detail": firestore.DELETE_FIELD,
                        "failedAt": firestore.DELETE_FIELD,
                        "retriedAt": firestore.SERVER_TIMESTAMP,
                        "retried_by": str(ADMIN_ID)
                    }, merge=True)

                    return self.send_json(
                        200,
                        {"ok": True, "message": "Task queued again"}
                    )

                if action == "delete":
                    task_ref.delete()

                    return self.send_json(
                        200,
                        {"ok": True, "message": "Task deleted"}
                    )

                return self.send_json(400, {"error": "Invalid action"})

            return self.send_json(404, {"error": "Not found"})

        except Exception as e:
            return self.send_json(
                500,
                {"error": f"{type(e).__name__}: {e}"}
            )

def run_h():

    p = int(
        os.getenv("PORT", 8080)
    )

    http.server.HTTPServer(
        ('', p),
        AdminHTTPHandler
    ).serve_forever()

def start_bot_with_retry():

    while True:

        try:

            app.start()

            return

        except FloodWait as e:

            wait_time = int(e.value) + 5

            print(
                f"⚠️ Telegram FloodWait on bot start. Waiting {wait_time}s...",
                flush=True
            )

            time.sleep(wait_time)

# --- [ Main ] ---

if __name__ == "__main__":

    threading.Thread(

        target=run_h,
        daemon=True

    ).start()

    threading.Thread(

        target=self_ping,
        daemon=True

    ).start()

    start_bot_with_retry()

    app.loop.create_task(
        ack_listener()
    )

    app.loop.create_task(
        premium_expiry_watcher()
    )

    idle()
