import uuid, asyncio, io
from datetime import datetime
from telethon import Button
import httpx

from config import SHOP_NAME, NOTIF_CHANNEL
from utils.data_manager import (
    get_user, get_product_by_id, get_category_by_id,
    get_products, get_products_by_category, pop_stock, add_order,
    get_order_by_id, update_order, add_balance, deduct_balance
)
from utils.notif import send_notif_order
from api import create_qris_payment, check_qris_payment


async def send_qris_photo(bot, user_id, qris_url, caption, buttons):
    try:
        async with httpx.AsyncClient() as client:
            r = await client.get(qris_url, timeout=15)
            buf = io.BytesIO(r.content)
            buf.name = "qris.jpg"
        return await bot.send_file(user_id, file=buf, caption=caption, buttons=buttons)
    except Exception:
        return await bot.send_message(user_id, caption + f"\n\n{qris_url}", buttons=buttons)


def categories_keyboard():
    data = get_products()
    cats = data.get("categories", [])
    buttons = []
    row = []
    for i, c in enumerate(cats):
        row.append(Button.inline(c["name"], f"cat_{c['id']}".encode()))
        if len(row) == 2:
            buttons.append(row)
            row = []
    if row:
        buttons.append(row)
    buttons.append([Button.inline("Kembali", b"back_main")])
    return buttons


def products_keyboard(cat_id):
    prods = get_products_by_category(cat_id)
    buttons = []
    for p in prods:
        stok = len(p.get("stock", []))
        buttons.append([Button.inline(
            f"{p['name']} — Rp{p['price']:,} ({stok} stok)",
            f"prod_{p['id']}".encode()
        )])
    buttons.append([Button.inline("Kembali", b"back_categories")])
    return buttons


def product_detail_keyboard(prod_id, cat_id):
    return [
        [Button.inline("Beli Sekarang", f"buy_{prod_id}".encode())],
        [Button.inline("Kembali", f"cat_{cat_id}".encode())]
    ]


def confirm_buy_keyboard(prod_id):
    return [
        [Button.inline("Bayar via QRIS", f"pay_qris_{prod_id}".encode())],
        [Button.inline("Bayar via Saldo", f"pay_balance_{prod_id}".encode())],
        [Button.inline("Batal", b"back_main")]
    ]


def payment_status_keyboard(order_id):
    return [
        [Button.inline("Cek Status Pembayaran", f"cekbayar_{order_id}".encode())],
        [Button.inline("Batalkan", f"cancelpay_{order_id}".encode())]
    ]


async def handle_cat(bot, event, cat_id: str):
    cat = get_category_by_id(cat_id)
    if not cat:
        await event.edit("Kategori tidak ditemukan.")
        return

    is_vps = cat.get("type") == "vps"
    prods = get_products_by_category(cat_id)

    if is_vps:
        stok = cat.get("stock", 0)
        lines = ["PILIH SPESIFIKASI VPS\n──────────────────────────"]
        buttons = []
        for i, p in enumerate(prods, 1):
            lines.append(f"{i}. {p['description']}\n   Rp {p['price']:,}")
            lines.append("──────────────────────────")
            buttons.append([Button.inline(
                f"{i}. {p['name']} — Rp{p['price']:,}",
                f"prod_{p['id']}".encode()
            )])
        lines.append(f"STOK TERSEDIA : {stok} VPS")
        buttons.append([Button.inline("Kembali", b"back_categories")])
        await event.edit("\n".join(lines), buttons=buttons)
    else:
        await event.edit(
            f"{cat['name']}\n\nPilih produk yang ingin dibeli:",
            buttons=products_keyboard(cat_id)
        )


async def handle_prod(bot, event, prod_id: str):
    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:
        regions = [
            ("Singapore", "sgp1"), ("New York", "nyc1"),
            ("Amsterdam", "ams3"), ("London", "lon1"),
            ("Frankfurt", "fra1"), ("San Francisco", "sfo3"),
        ]
        buttons = []
        for name, slug in regions:
            buttons.append([Button.inline(name, f"vps_region_{prod_id}_{slug}".encode())])
        buttons.append([Button.inline("Kembali", f"cat_{prod['category_id']}".encode())])
        await event.edit(
            f"PILIH REGION VPS\n\n"
            f"Spek: {prod['description']}\n"
            f"Harga: Rp{prod['price']:,}\n\n"
            f"Pilih lokasi server:",
            buttons=buttons
        )
    else:
        stock_count = len(prod.get("stock", []))
        text = (
            f"{prod['name']}\n\n"
            f"{prod['description']}\n\n"
            f"Harga: Rp{prod['price']:,}\n"
            f"Stok: {stock_count} tersedia"
        )
        await event.edit(text, buttons=product_detail_keyboard(prod_id, prod["category_id"]))


async def handle_buy(bot, event, prod_id: str):
    prod = get_product_by_id(prod_id)
    if not prod:
        await event.edit("Produk tidak ditemukan.")
        return
    if len(prod.get("stock", [])) == 0:
        await event.edit("Stok habis! Silakan coba produk lain.")
        return

    user_data = get_user(event.sender_id)
    balance = user_data.get("balance", 0)
    text = (
        f"Konfirmasi Pembelian\n\n"
        f"Produk: {prod['name']}\n"
        f"Harga: Rp{prod['price']:,}\n\n"
        f"Saldo kamu: Rp{balance:,}\n\n"
        f"Pilih metode pembayaran:"
    )
    await event.edit(text, buttons=confirm_buy_keyboard(prod_id))


async def handle_pay_qris(bot, event, prod_id: str):
    prod = get_product_by_id(prod_id)
    if not prod or len(prod.get("stock", [])) == 0:
        await event.edit("Stok habis atau produk tidak ditemukan.")
        return

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

    result = create_qris_payment(
        prod["price"],
        product_name=prod["name"],
        customer_name=(await event.get_sender()).first_name,
        customer_id=str(event.sender_id)
    )

    if result.get("status") == "error":
        await bot.send_message(event.sender_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": event.sender_id,
        "prod_id": prod_id,
        "prod_name": prod["name"],
        "amount": prod["price"],
        "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"Menunggu pembayaran..."
    )

    sender_id = event.sender_id
    sent_msg = None

    if qris_url:
        sent_msg = await send_qris_photo(bot, sender_id, qris_url, caption, payment_status_keyboard(order_id))
        await event.delete()
    else:
        sent_msg = await bot.send_message(sender_id, caption, buttons=payment_status_keyboard(order_id))

    async def on_payment_done(status, res):
        if status == "success":
            stock_item = pop_stock(prod_id)
            if not stock_item:
                update_order(order_id, {"status": "failed"})
                try:
                    await sent_msg.delete()
                except Exception:
                    pass
                await bot.send_message(sender_id, "Pembayaran diterima tapi stok habis. Hubungi admin.")
                return

            update_order(order_id, {"status": "success", "item": stock_item})
            await send_notif_order(bot, {
                "order_id": order_id,
                "user_id": sender_id,
                "prod_name": prod["name"],
                "amount": prod["price"],
                "method": "qris",
                "created_at": datetime.now().strftime("%Y-%m-%d %H:%M"),
            })
            try:
                await sent_msg.delete()
            except Exception:
                pass
            await bot.send_message(
                sender_id,
                f"Pembayaran Berhasil!\n\n"
                f"Produk: {prod['name']}\n"
                f"Total: Rp{prod['price']:,}\n\n"
                f"Detail Produk:\n"
                f"```\n{stock_item}\n```"
            )

        elif status in ("failed", "timeout"):
            update_order(order_id, {"status": "failed"})
            try:
                await sent_msg.delete()
            except Exception:
                pass
            msg = "Pembayaran Gagal/Expired" if status == "failed" else "Waktu Pembayaran Habis"
            await bot.send_message(sender_id, f"{msg}\n\nOrder ID: {order_id}\nSilakan buat order baru.")

    from api import poll_qris_status
    asyncio.create_task(poll_qris_status(order_id, on_payment_done))


async def handle_pay_balance(bot, event, prod_id: str):
    prod = get_product_by_id(prod_id)
    if not prod or len(prod.get("stock", [])) == 0:
        await event.edit("Stok habis.")
        return

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

    stock_item = pop_stock(prod_id)
    if not stock_item:
        add_balance(event.sender_id, prod["price"])
        await event.edit("Stok habis saat checkout. Saldo dikembalikan.")
        return

    order_id = str(uuid.uuid4())[:10].upper()
    add_order({
        "order_id": order_id,
        "user_id": event.sender_id,
        "prod_id": prod_id,
        "prod_name": prod["name"],
        "amount": prod["price"],
        "method": "balance",
        "status": "success",
        "item": stock_item,
        "created_at": datetime.now().isoformat()
    })

    await send_notif_order(bot, {
        "order_id": order_id,
        "user_id": event.sender_id,
        "prod_name": prod["name"],
        "amount": prod["price"],
        "method": "balance",
        "created_at": datetime.now().strftime("%Y-%m-%d %H:%M"),
    })

    await event.edit(
        f"Pembayaran Berhasil!\n\n"
        f"Produk: {prod['name']}\n"
        f"Total: Rp{prod['price']:,}\n\n"
        f"Detail Produk:\n"
        f"```\n{stock_item}\n```"
    )


async def handle_cekbayar(bot, event, order_id: str):
    order = get_order_by_id(order_id)
    if not order:
        await event.answer("Order tidak ditemukan.", alert=True)
        return
    if order["status"] == "success":
        await event.answer("Pembayaran sudah dikonfirmasi sebelumnya.", alert=True)
        return

    result = check_qris_payment(order_id)
    payment_status = (
        result.get("order_data", {}).get("transaction_status", "") or
        result.get("midtrans_status", {}).get("transaction_status", "")
    )

    SUCCESS_STATUS = ("settlement", "capture")

    if payment_status in SUCCESS_STATUS:
        stock_item = pop_stock(order["prod_id"])
        if not stock_item:
            await event.answer("Pembayaran diterima tapi stok habis. Hubungi admin.", alert=True)
            return
        update_order(order_id, {"status": "success", "item": stock_item})
        await send_notif_order(bot, {
            "order_id": order_id,
            "user_id": order["user_id"],
            "prod_name": order["prod_name"],
            "amount": order["amount"],
            "method": order.get("method", "qris"),
            "created_at": datetime.now().strftime("%Y-%m-%d %H:%M"),
        })
        try:
            await event.delete()
        except Exception:
            pass
        await bot.send_message(
            event.sender_id,
            f"Pembayaran Berhasil!\n\n"
            f"Produk: {order['prod_name']}\n"
            f"Total: Rp{order['amount']:,}\n\n"
            f"Detail Produk:\n`{stock_item}`\n\n"
            f"Terima kasih sudah belanja di {SHOP_NAME}!"
        )
    else:
        await event.answer(f"Pembayaran belum diterima. Status: {payment_status}", alert=True)