"""
routes_topup.py — Endpoint top-up saldo via Midtrans Snap.

BUG FIX:
  - Tambah endpoint GET /api/topup/check-order/{order_id} untuk polling status
    dari frontend setelah Snap onSuccess dipanggil.
  - Frontend tidak lagi langsung percaya onSuccess — ia polling backend sampai
    status order berubah jadi 'paid' (artinya webhook sudah diterima & saldo
    sudah ditambah).
"""

import logging

from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.models.topup_order import TopupOrder
from app.models.user import User
from app.services.auth_service import get_current_user
from app.services.feature_flag_service import require_feature
from app.services.midtrans_service import (
    TOPUP_AMOUNTS,
    create_snap_transaction,
    generate_order_id,
    is_payment_expired,
    is_payment_failed,
    is_payment_success,
    verify_notification,
)
from app.utils.billing import add_balance

router = APIRouter()
logger = logging.getLogger(__name__)

_topup_enabled = require_feature(
    "topup_enabled",
    "Fitur top-up sedang dinonaktifkan oleh administrator.",
)


class CreateTopupRequest(BaseModel):
    amount: int


@router.get("/topup/amounts")
def get_topup_amounts(
    _: None = Depends(_topup_enabled),
):
    return {"amounts": TOPUP_AMOUNTS}


@router.post("/topup/create")
async def create_topup(
    payload:      CreateTopupRequest,
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
    _:            None    = Depends(_topup_enabled),
):
    if payload.amount not in TOPUP_AMOUNTS:
        raise HTTPException(
            status_code=400,
            detail="Nominal tidak valid. Pilih salah satu: " + str(TOPUP_AMOUNTS),
        )

    from app.core.config import MIDTRANS_CLIENT_KEY

    order_id = generate_order_id(current_user.id)

    order = TopupOrder(
        order_id=order_id,
        user_id=current_user.id,
        amount=payload.amount,
        status="pending",
    )
    db.add(order)
    db.commit()
    db.refresh(order)

    try:
        snap_token = await create_snap_transaction(
            order_id=order_id,
            amount=payload.amount,
            user_id=current_user.id,
            username=current_user.username,
            email=current_user.email,
        )
    except Exception as exc:
        order.status = "failed"
        db.commit()
        logger.error("[Topup] Gagal membuat Snap token untuk order %s: %s", order_id, exc)
        raise HTTPException(
            status_code=502,
            detail="Gagal menghubungi Midtrans: " + str(exc)[:200],
        )

    order.snap_token = snap_token
    db.commit()

    logger.info("[Topup] Order %s dibuat: user_id=%d amount=%d", order_id, current_user.id, payload.amount)

    return {
        "success":    True,
        "order_id":   order_id,
        "snap_token": snap_token,
        "client_key": MIDTRANS_CLIENT_KEY,
        "amount":     payload.amount,
    }


@router.post("/topup/notification")
async def midtrans_notification(request: Request, db: Session = Depends(get_db)):
    """
    Webhook dari Midtrans. Dipanggil server-to-server setelah user bayar.

    PENTING untuk development lokal:
      Midtrans tidak bisa POST ke localhost. Gunakan ngrok atau layanan
      tunnel sejenis, lalu set Notification URL di dashboard Midtrans:
        https://<ngrok-url>/api/topup/notification

    NOTE: Endpoint ini sengaja TIDAK pakai _topup_enabled —
    webhook Midtrans harus tetap diterima meski fitur topup dimatikan,
    agar transaksi yang sudah terlanjur dibuat bisa diselesaikan.
    """
    try:
        payload = await request.json()
    except Exception:
        logger.warning("[Midtrans] Notifikasi bukan JSON valid.")
        return {"status": "ignored"}

    order_id = payload.get("order_id", "")
    logger.info(
        "[Midtrans] Notifikasi diterima: order_id=%s status=%s",
        order_id, payload.get("transaction_status"),
    )

    if not verify_notification(payload):
        logger.warning("[Midtrans] Signature tidak valid untuk order %s.", order_id)
        return {"status": "invalid_signature"}

    if not order_id.startswith("TOPUP-"):
        return {"status": "ignored"}

    order = db.query(TopupOrder).filter(TopupOrder.order_id == order_id).first()
    if not order:
        logger.warning("[Midtrans] Order %s tidak ditemukan di DB.", order_id)
        return {"status": "order_not_found"}

    if order.status == "paid":
        logger.info("[Midtrans] Order %s sudah diproses.", order_id)
        return {"status": "already_processed"}

    order.payment_type   = payload.get("payment_type")
    order.transaction_id = payload.get("transaction_id")
    order.fraud_status   = payload.get("fraud_status")

    if is_payment_success(payload):
        try:
            new_balance = add_balance(
                db=db,
                user_id=order.user_id,
                amount=order.amount,
                description="Top Up via Midtrans [" + order_id + "]",
            )
            order.status = "paid"
            db.commit()
            logger.info(
                "[Midtrans] TOP-UP BERHASIL: order=%s user_id=%d amount=%d saldo_baru=%d",
                order_id, order.user_id, order.amount, new_balance,
            )
        except Exception as exc:
            db.rollback()
            logger.error("[Midtrans] Gagal tambah saldo order %s: %s", order_id, exc, exc_info=True)
            raise HTTPException(status_code=500, detail="Gagal memproses pembayaran.")

    elif is_payment_failed(payload):
        order.status = "failed"
        db.commit()
        logger.info("[Midtrans] Pembayaran gagal: order=%s", order_id)

    elif is_payment_expired(payload):
        order.status = "expired"
        db.commit()
        logger.info("[Midtrans] Pembayaran expired: order=%s", order_id)

    else:
        db.commit()

    return {"status": "ok"}


@router.get("/topup/check-order/{order_id}")
def check_order_status(
    order_id:     str,
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
):
    """
    Dipakai frontend untuk polling status setelah Snap onSuccess.
    Frontend cek endpoint ini setiap 2 detik sampai status = 'paid'.

    NOTE: Sengaja TIDAK pakai _topup_enabled — user harus tetap
    bisa mengecek status transaksi yang sudah terlanjur dibuat sebelum
    fitur dimatikan.

    Keamanan: hanya bisa cek order milik user sendiri (kecuali admin).
    """
    order = db.query(TopupOrder).filter(TopupOrder.order_id == order_id).first()

    if not order:
        raise HTTPException(status_code=404, detail="Order tidak ditemukan.")

    if current_user.role != "admin" and order.user_id != current_user.id:
        raise HTTPException(status_code=403, detail="Akses ditolak.")

    return {
        "order_id": order.order_id,
        "status":   order.status,
        "amount":   order.amount,
    }


@router.get("/topup/orders")
def list_topup_orders(
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
    _:            None    = Depends(_topup_enabled),
):
    orders = (
        db.query(TopupOrder)
        .filter(TopupOrder.user_id == current_user.id)
        .order_by(TopupOrder.created_at.desc())
        .limit(50)
        .all()
    )
    return {
        "orders": [
            {
                "id":           o.id,
                "order_id":     o.order_id,
                "amount":       o.amount,
                "status":       o.status,
                "payment_type": o.payment_type,
                "created_at":   o.created_at.isoformat() if o.created_at else None,
            }
            for o in orders
        ]
    }