import uuid, asyncio, secrets, string, requests
from datetime import datetime
from telethon import Button

from handlers.start import build_main_caption, build_main_keyboard, BANNER_URL
from handlers.topup import process_topup_qris, handle_cektopup
from handlers.shop import (
    handle_cat, handle_buy,
    handle_pay_qris, handle_pay_balance,
    handle_cekbayar,
    categories_keyboard
)
from utils.data_manager import (
    get_user, get_settings, update_order, get_product_by_id,
    get_category_by_id, add_order, deduct_balance, add_balance,
    get_order_by_id, get_products, save_products
)
from utils.notif import send_notif_vps_success
from config import CONTACT_ADMIN, DO_API_KEY
from api import create_qris_payment, poll_qris_status, check_qris_payment


def topup_keyboard():
    nominals = [10000, 20000, 50000, 100000, 200000, 500000]
    buttons = []
    row = []
    for nominal in nominals:
        row.append(Button.inline(f"Rp{nominal:,}", f"topup_{nominal}".encode()))
        if len(row) == 2:
            buttons.append(row)
            row = []
    if row:
        buttons.append(row)
    buttons.append([Button.inline("✏️ Nominal Lain", b"topup_custom")])
    buttons.append([Button.inline("🔙 Kembali", b"back_main")])
    return buttons


OS_VERSIONS = {
    "ubuntu": [
        ("Ubuntu 22.04 ⭐ Recommended", "ubuntu-22-04-x64"),
        ("Ubuntu 24.04", "ubuntu-24-04-x64"),
        ("Ubuntu 20.04", "ubuntu-20-04-x64"),
    ],
    "debian": [
        ("Debian 12 ⭐ Recommended", "debian-12-x64"),
        ("Debian 11", "debian-11-x64"),
    ],
    "centos": [
        ("CentOS Stream 9 ⭐ Recommended", "centos-stream-9-x64"),
        ("CentOS Stream 8", "centos-stream-8-x64"),
    ],
    "fedora": [
        ("Fedora 39 ⭐ Recommended", "fedora-39-x64"),
        ("Fedora 38", "fedora-38-x64"),
    ],
    "almalinux": [
        ("AlmaLinux 9 ⭐ Recommended", "almalinux-9-x64"),
        ("AlmaLinux 8", "almalinux-8-x64"),
    ],
    "rockylinux": [
        ("Rocky Linux 9 ⭐ Recommended", "rockylinux-9-x64"),
        ("Rocky Linux 8", "rockylinux-8-x64"),
    ],
}

REGIONS = [
    ("🇸🇬 SINGAPORE (RECOMMENDED)", "sgp1"),
    ("🇺🇸 NEW YORK", "nyc1"),
    ("🇺🇸 SAN FRANCISCO", "sfo3"),
    ("🇳🇱 AMSTERDAM", "ams3"),
    ("🇬🇧 LONDON", "lon1"),
    ("🇩🇪 FRANKFURT", "fra1"),
    ("🇮🇳 BANGALORE", "blr1"),
    ("🇦🇺 SYDNEY", "syd1"),
]

user_data_store = {}


async def handle_callback(bot, event):
    await event.answer()
    data = event.data.decode()
    user_id = event.sender_id

    if user_id not in user_data_store:
        user_data_store[user_id] = {}
    udata = user_data_store[user_id]

    if data == "check_member":
        from handlers.start import is_member, build_join_keyboard
        if await is_member(bot, user_id):
            try:
                await event.delete()
            except Exception:
                pass
            caption = build_main_caption()
            keyboard = build_main_keyboard()
            try:
                await bot.send_file(user_id, file=BANNER_URL, caption=caption, parse_mode="html", buttons=keyboard)
            except Exception:
                await bot.send_message(user_id, caption, parse_mode="html", buttons=keyboard)
        else:
            await event.answer("❌ Kamu belum gabung grup!", alert=True)
        return

    if data == "menu_produk":
        await bot.send_message(
            user_id,
            "🛍 Pilih Kategori Produk\n\nPilih kategori produk yang ingin dibeli:",
            buttons=categories_keyboard()
        )

    elif data == "menu_saldo":
        sender = await event.get_sender()
        user_db = get_user(user_id)
        balance = user_db.get("balance", 0)
        await bot.send_message(
            user_id,
            f"💰 **Saldo Kamu**\n\n"
            f"👤 Nama: {sender.first_name}\n"
            f"💵 Saldo: **Rp{balance:,}**"
        )

    elif data == "menu_topup":
        await bot.send_message(user_id, "💳 **Topup Saldo**\n\nPilih nominal topup:", buttons=topup_keyboard())

    elif data == "menu_panduan":
        settings = get_settings()
        panduan = settings.get("panduan", "Panduan belum diatur.")
        await bot.send_message(user_id, f"📖 **Panduan**\n\n{panduan}")

    elif data == "menu_kontak":
        await bot.send_message(
            user_id,
            f"📞 **Kontak Admin**\n\n"
            f"👤 Admin: {CONTACT_ADMIN}\n\n"
            f"✅ Admin Wa: wa.me/6285892673080\n\n"
            f"Jam operasional: 08.00 - 22.00 WIB"
        )

    elif data == "back_main":
        try:
            await event.delete()
        except Exception:
            pass
        caption = build_main_caption()
        keyboard = build_main_keyboard()
        try:
            await bot.send_file(user_id, file=BANNER_URL, caption=caption, parse_mode="html", buttons=keyboard)
        except Exception:
            await bot.send_message(user_id, caption, parse_mode="html", buttons=keyboard)

    elif data == "home_main":
        caption = build_main_caption()
        keyboard = build_main_keyboard()
        try:
            await bot.send_file(user_id, file=BANNER_URL, caption=caption, parse_mode="html", buttons=keyboard)
        except Exception:
            await bot.send_message(user_id, caption, parse_mode="html", buttons=keyboard)

    elif data == "back_categories":
        await event.edit("🛍 Pilih Kategori Produk\n\nPilih kategori produk yang ingin dibeli:", buttons=categories_keyboard())

    elif data.startswith("cat_"):
        await handle_cat(bot, event, data[4:])

    elif data.startswith("prod_"):
        prod_id = data[5:]
        prod = get_product_by_id(prod_id)
        if not prod:
            await event.edit("Produk tidak ditemukan.")
            return
        cat = get_category_by_id(prod.get("category_id", ""))
        is_vps = cat and cat.get("type") == "vps"

        if is_vps:
            buttons = []
            for label, family in [
                ("🖥 Ubuntu", "ubuntu"), ("🖥 Debian", "debian"),
                ("🖥 CentOS", "centos"), ("🖥 Fedora", "fedora"),
                ("🖥 AlmaLinux", "almalinux"), ("🖥 Rocky Linux", "rockylinux"),
            ]:
                buttons.append([Button.inline(label, f"vps_family_{prod_id}_{family}".encode())])
            buttons.append([Button.inline("🔙 Kembali", f"cat_{prod['category_id']}".encode())])
            await event.edit(
                f"🖥 **PILIH OS FAMILY**\n\n"
                f"💾 Spesifikasi: **{prod['description']}**\n"
                f"💰 Harga: **Rp{prod['price']:,}**\n\n"
                f"Pilih sistem operasi:",
                buttons=buttons
            )
        else:
            from handlers.shop import handle_prod
            await handle_prod(bot, event, prod_id)

    elif data.startswith("vps_family_"):
        rest = data[len("vps_family_"):]
        prod_id, family = rest.rsplit("_", 1)
        udata["vps_family"] = family
        prod = get_product_by_id(prod_id)
        if not prod:
            await event.edit("Produk tidak ditemukan.")
            return
        versions = OS_VERSIONS.get(family, [])
        buttons = []
        for name, slug in versions:
            buttons.append([Button.inline(name, f"vps_os_{prod_id}_{slug}".encode())])
        buttons.append([Button.inline("🔙 Kembali", f"prod_{prod_id}".encode())])
        await event.edit(
            f"🖥 **OS Dipilih: {family.upper()}**\n\n"
            f"💾 Spesifikasi: **{prod['description']}**\n\n"
            f"Pilih versi OS:",
            buttons=buttons
        )

    elif data.startswith("vps_os_"):
        rest = data[len("vps_os_"):]
        prod_id, os_slug = rest.rsplit("_", 1)
        udata["vps_os"] = os_slug
        prod = get_product_by_id(prod_id)
        if not prod:
            await event.edit("Produk tidak ditemukan.")
            return
        buttons = []
        for i, (name, slug) in enumerate(REGIONS, 1):
            buttons.append([Button.inline(f"{i}. {name}", f"vps_region_{prod_id}_{slug}".encode())])
        buttons.append([Button.inline("🔙 Kembali", f"vps_family_{prod_id}_{udata.get('vps_family', '')}".encode())])
        await event.edit(
            f"📍 **PILIH REGION VPS**\n\n"
            f"💾 Spesifikasi: **{prod['description']}**\n"
            f"🖥 OS: **{os_slug}**\n\n"
            f"Pilih lokasi server:",
            buttons=buttons
        )

    elif data.startswith("vps_region_"):
        rest = data[len("vps_region_"):]
        prod_id, region_slug = rest.rsplit("_", 1)
        udata["vps_region"] = region_slug
        region_name = next((n for n, s in REGIONS if s == region_slug), region_slug)
        prod = get_product_by_id(prod_id)
        if not prod:
            await event.edit("Produk tidak ditemukan.")
            return
        os_slug = udata.get("vps_os", "-")
        user_db = get_user(user_id)
        balance = user_db.get("balance", 0)
        buttons = [
            [Button.inline("💳 Bayar QRIS", f"vps_qris_{prod_id}".encode())],
            [Button.inline("💰 Bayar Saldo", f"vps_balance_{prod_id}".encode())],
            [Button.inline("❌ Batal", b"back_main")]
        ]
        await event.edit(
            f"✅ **KONFIRMASI PEMESANAN VPS**\n"
            f"━━━━━━━━━━━━━━━━━━━━━━\n"
            f"📦 Paket: **{prod['name']}**\n"
            f"💸 Harga: **Rp {prod['price']:,}**\n"
            f"🖥 Spesifikasi: **{prod['description']}**\n"
            f"🧩 OS: **{os_slug}**\n"
            f"🌍 Region: **{region_name}**\n"
            f"━━━━━━━━━━━━━━━━━━━━━━\n"
            f"💵 Saldo kamu: Rp{balance:,}\n\n"
            f"Silakan pilih metode pembayaran:",
            buttons=buttons
        )

    elif data.startswith("vps_qris_"):
        prod_id = data[9:]
        prod = get_product_by_id(prod_id)
        if not prod:
            await event.edit("Produk tidak ditemukan.")
            return

        await event.edit("⏳ Membuat QRIS, mohon tunggu...")

        sender = await event.get_sender()
        result = create_qris_payment(
            prod["price"],
            product_name=prod["name"],
            customer_name=sender.first_name,
            customer_id=sender.username or str(user_id)
        )
        if result.get("status") == "error":
            await bot.send_message(user_id, f"❌ Gagal membuat pembayaran: {result.get('message')}")
            return

        order_id = result.get("order_id")
        qris_url = result.get("qr_code_url") or result.get("qr_code_url_v2", "")

        add_order({
            "order_id": order_id,
            "user_id": user_id,
            "type": "vps",
            "prod_id": prod_id,
            "prod_name": prod["name"],
            "amount": prod["price"],
            "os": udata.get("vps_os", ""),
            "region": udata.get("vps_region", ""),
            "method": "qris",
            "status": "pending",
            "created_at": datetime.now().isoformat()
        })

        caption = (
            f"🧾 **TAGIHAN**\n\n"
            f"ID TRX : `{order_id}`\n"
            f"Item: {prod['name']} — {prod['description']}\n"
            f"Total: **Rp {prod['price']:,}**\n\n"
            f"Bayar pas sesuai nominal!\n"
            f"⏳ Status akan otomatis update setelah pembayaran."
        )
        markup = [
            [Button.inline("🔄 Cek Manual", f"vps_cekbayar_{order_id}".encode())],
            [Button.inline("❌ Batalkan", f"cancelpay_{order_id}".encode())]
        ]

        sent_msg = None
        if qris_url:
            try:
                sent_msg = await bot.send_file(user_id, file=qris_url, caption=caption, buttons=markup, force_document=False, attributes=[])
                await event.delete()
            except Exception:
                sent_msg = await bot.send_message(user_id, caption + f"\n\n{qris_url}", buttons=markup)
        else:
            sent_msg = await bot.send_message(user_id, caption, buttons=markup)

        os_slug = udata.get("vps_os", "")
        region_slug = udata.get("vps_region", "")

        async def on_payment_done(status, res):
            order_markup = [
                [Button.inline("🛒 Order Lagi", b"menu_produk")],
                [Button.inline("🏠 Kembali ke Menu", b"home_main")]
            ]

            if status == "success":
                update_order(order_id, {"status": "processing"})
                try:
                    await sent_msg.delete()
                except Exception:
                    pass
                await bot.send_message(
                    user_id,
                    f"✅ **Pembayaran Diterima!**\n\n"
                    f"🔖 Order ID: `{order_id}`\n"
                    f"📦 Paket: **{prod['name']}**\n"
                    f"🖥 OS: **{os_slug}**\n"
                    f"🌍 Region: **{region_slug}**\n\n"
                    f"VPS sedang dibuat, mohon tunggu..."
                )
                await create_vps_do(bot, user_id, order_id, prod, os_slug, region_slug)

            elif status == "failed":
                update_order(order_id, {"status": "failed"})
                try:
                    await sent_msg.delete()
                except Exception:
                    pass
                await bot.send_message(
                    user_id,
                    f"❌ **Pembayaran Gagal/Expired**\n\n"
                    f"🔖 Order ID: `{order_id}`\n"
                    f"Silakan buat order baru.",
                    buttons=order_markup
                )

            elif status == "timeout":
                try:
                    await sent_msg.delete()
                except Exception:
                    pass
                await bot.send_message(
                    user_id,
                    f"⏰ **Waktu Pembayaran Habis**\n\n"
                    f"🔖 Order ID: `{order_id}`\n"
                    f"Silakan buat order baru jika ingin melanjutkan.",
                    buttons=order_markup
                )

        asyncio.create_task(poll_qris_status(order_id, on_payment_done))

    elif data.startswith("vps_balance_"):
        prod_id = data[12:]
        prod = get_product_by_id(prod_id)
        if not prod:
            await event.edit("Produk tidak ditemukan.")
            return

        success = deduct_balance(user_id, prod["price"])
        if not success:
            await event.edit(f"❌ Saldo tidak cukup!\nHarga: Rp{prod['price']:,}\n\nSilakan topup dulu.")
            return

        order_id = "VPS-" + str(uuid.uuid4())[:8].upper()
        os_slug = udata.get("vps_os", "")
        region_slug = udata.get("vps_region", "")
        add_order({
            "order_id": order_id,
            "user_id": user_id,
            "type": "vps",
            "prod_id": prod_id,
            "prod_name": prod["name"],
            "amount": prod["price"],
            "os": os_slug,
            "region": region_slug,
            "method": "balance",
            "status": "processing",
            "created_at": datetime.now().isoformat()
        })
        await event.edit(
            f"⏳ **Pembayaran Diterima!**\n\n"
            f"🔖 Order ID: `{order_id}`\n"
            f"📦 Paket: **{prod['name']}**\n"
            f"🖥 OS: **{os_slug}**\n"
            f"🌍 Region: **{region_slug}**\n\n"
            f"VPS sedang dibuat, mohon tunggu..."
        )
        await create_vps_do(bot, user_id, order_id, prod, os_slug, region_slug)

    elif data.startswith("vps_cekbayar_"):
        order_id = data[13:]
        order = get_order_by_id(order_id)
        if not order:
            await event.answer("❌ Order tidak ditemukan.", alert=True)
            return
        if order["status"] in ("success", "processing"):
            await event.answer("✅ Pembayaran sudah dikonfirmasi.", alert=True)
            return

        result = check_qris_payment(order_id)
        payment_status = result.get("status") or result.get("data", {}).get("status", "") or result.get("order_data", {}).get("transaction_status", "")
        if payment_status in ("paid", "success", "settlement", "capture"):
            update_order(order_id, {"status": "processing"})
            prod = get_product_by_id(order["prod_id"])
            try:
                await event.delete()
            except Exception:
                pass
            await bot.send_message(
                user_id,
                f"✅ **Pembayaran Diterima!**\n\n"
                f"🔖 Order ID: `{order_id}`\n"
                f"📦 Paket: **{order['prod_name']}**\n"
                f"🖥 OS: **{order.get('os', '-')}**\n"
                f"🌍 Region: **{order.get('region', '-')}**\n\n"
                f"VPS sedang dibuat, mohon tunggu..."
            )
            await create_vps_do(bot, user_id, order_id, prod, order.get("os", ""), order.get("region", ""))
        else:
            await event.answer("⏳ Pembayaran belum diterima, coba lagi.", alert=True)

    elif data.startswith("buy_"):
        await handle_buy(bot, event, data[4:])

    elif data.startswith("pay_qris_"):
        await handle_pay_qris(bot, event, data[9:])

    elif data.startswith("pay_balance_"):
        await handle_pay_balance(bot, event, data[12:])

    elif data.startswith("cekbayar_"):
        await handle_cekbayar(bot, event, data[9:])

    elif data.startswith("cancelpay_"):
        update_order(data[10:], {"status": "cancelled"})
        try:
            await event.edit("❌ Pembayaran dibatalkan.\n\nKetik /start untuk kembali ke menu.")
        except Exception:
            await event.delete()
            await bot.send_message(user_id, "❌ Pembayaran dibatalkan.\n\nKetik /start untuk kembali ke menu.")

    elif data.startswith("topup_"):
        val = data[6:]
        if val == "custom":
            user_data_store[user_id]["awaiting_topup"] = True
            await event.edit("✏️ Ketik nominal topup (angka saja):\nContoh: 75000")
        else:
            await process_topup_qris(bot, event, int(val))

    elif data.startswith("cektopup_"):
        await handle_cektopup(bot, event, data[9:])


async def create_vps_do(bot, user_id, order_id, prod, os_slug, region_slug):
    root_password = ''.join(secrets.choice(string.ascii_letters + string.digits + "!@#$%") for _ in range(16))

    headers = {
        "Authorization": f"Bearer {DO_API_KEY}",
        "Content-Type": "application/json"
    }

    size_map = {
        "2 GB 2 CPU": "s-2vcpu-2gb",
        "4 GB 2 CPU": "s-2vcpu-4gb",
        "8 GB 4 CPU": "s-4vcpu-8gb",
        "16 GB 4 CPU": "s-4vcpu-16gb",
        "32 GB 8 CPU": "s-8vcpu-32gb-amd",
    }
    size_slug = size_map.get(prod["name"], "s-2vcpu-2gb")

    payload = {
        "name": f"{os_slug}-{region_slug}-{secrets.randbelow(900)+100}",
        "region": region_slug,
        "size": size_slug,
        "image": os_slug,
        "backups": False,
        "ipv6": False,
        "user_data": f'#!/bin/bash\necho "root:{root_password}" | chpasswd\nsed -i "s/^#*PermitRootLogin.*/PermitRootLogin yes/" /etc/ssh/sshd_config\nsed -i "s/^#*PasswordAuthentication.*/PasswordAuthentication yes/" /etc/ssh/sshd_config\nsystemctl restart sshd'
    }

    order_markup = [
        [Button.inline("🛒 Order Lagi", b"menu_produk")],
        [Button.inline("🏠 Kembali ke Menu", b"home_main")]
    ]

    try:
        loop = asyncio.get_event_loop()
        resp = await loop.run_in_executor(
            None,
            lambda: requests.post("https://api.digitalocean.com/v2/droplets", json=payload, headers=headers, timeout=30)
        )
        result = resp.json()

        if resp.status_code == 202:
            droplet = result.get("droplet", {})
            droplet_id = droplet.get("id")
            update_order(order_id, {"droplet_id": droplet_id, "status": "creating", "root_password": root_password})

            ip = None
            for _ in range(24):
                await asyncio.sleep(5)
                r = await loop.run_in_executor(
                    None,
                    lambda: requests.get(f"https://api.digitalocean.com/v2/droplets/{droplet_id}", headers=headers, timeout=10)
                )
                d = r.json().get("droplet", {})
                networks = d.get("networks", {}).get("v4", [])
                for net in networks:
                    if net.get("type") == "public":
                        ip = net.get("ip_address")
                        break
                if ip:
                    break

            if ip:
                update_order(order_id, {"status": "success", "ip": ip})
                await send_notif_vps_success(bot, user_id, order_id, prod["name"], os_slug, region_slug, ip)
                await bot.send_message(
                    user_id,
                    f"✅ **VPS Berhasil Dibuat!**\n\n"
                    f"🔖 Order ID: `{order_id}`\n"
                    f"📦 Paket: **{prod['name']}**\n"
                    f"🖥 OS: **{os_slug}**\n"
                    f"🌍 Region: **{region_slug}**\n\n"
                    f"🌐 IP Address: `{ip}`\n"
                    f"👤 Username: `root`\n"
                    f"🔑 Password: `{root_password}`\n\n"
                    f"VPS siap digunakan! Login via SSH:\n"
                    f"`ssh root@{ip}`",
                    buttons=order_markup
                )
                cat = get_category_by_id(prod.get("category_id", ""))
                if cat:
                    pdata = get_products()
                    for c in pdata["categories"]:
                        if c["id"] == cat["id"]:
                            c["stock"] = max(0, c.get("stock", 0) - 1)
                            break
                    save_products(pdata)
            else:
                update_order(order_id, {"status": "success", "ip": "pending"})
                await bot.send_message(
                    user_id,
                    f"✅ **VPS Dibuat, IP Belum Siap**\n\n"
                    f"🔖 Order ID: `{order_id}`\n"
                    f"IP sedang disiapkan"
                )
        else:
            error_msg = result.get("message", "Unknown error")
            update_order(order_id, {"status": "failed"})
            add_balance(user_id, prod["price"])
            await bot.send_message(
                user_id,
                f"❌ **Gagal Membuat VPS**\n\nError: {error_msg}\n\nSaldo Rp{prod['price']:,} telah dikembalikan."
            )
    except Exception as e:
        update_order(order_id, {"status": "failed"})
        add_balance(user_id, prod["price"])
        await bot.send_message(
            user_id,
            f"❌ **Gagal Membuat VPS**\n\nError: {str(e)}\n\nSaldo dikembalikan."
        )