"""
midtrans_service.py — Integrasi Midtrans Snap untuk top-up saldo.

Dokumentasi Midtrans:
  https://docs.midtrans.com/reference/snap-api

Alur:
  1. create_snap_transaction() → dapatkan snap_token dari Midtrans
  2. Frontend buka popup Snap dengan snap_token
  3. Midtrans POST ke /api/topup/notification setelah user bayar
  4. verify_notification() → cek signature SHA-512
  5. Jika valid & settlement → add_balance()
"""

import hashlib
import logging
import uuid
import time
from typing import Optional

import httpx

from app.core.config import (
    MIDTRANS_SERVER_KEY,
    MIDTRANS_CLIENT_KEY,
    MIDTRANS_IS_PRODUCTION,
)

logger = logging.getLogger(__name__)

# URL Midtrans Snap API
_SNAP_URL = (
    "https://app.midtrans.com/snap/v1/transactions"
    if MIDTRANS_IS_PRODUCTION
    else "https://app.sandbox.midtrans.com/snap/v1/transactions"
)

# Timeout request ke Midtrans (detik)
_HTTP_TIMEOUT = 15


def generate_order_id(user_id: int) -> str:
    """
    Buat order_id unik untuk dikirim ke Midtrans.
    Format: TOPUP-{user_id}-{timestamp_ms}-{random4}
    Harus unik per transaksi — Midtrans menolak order_id yang sudah dipakai.
    """
    ts     = int(time.time() * 1000)
    suffix = uuid.uuid4().hex[:6].upper()
    return f"TOPUP-{user_id}-{ts}-{suffix}"


async def create_snap_transaction(
    order_id:   str,
    amount:     int,
    user_id:    int,
    username:   str,
    email:      Optional[str] = None,
) -> str:
    """
    Minta Snap token ke Midtrans.
    Kembalikan snap_token (string) yang dipakai frontend membuka popup.

    Raises:
        RuntimeError: jika Midtrans mengembalikan error atau MIDTRANS_SERVER_KEY kosong.
    """
    if not MIDTRANS_SERVER_KEY:
        raise RuntimeError(
            "MIDTRANS_SERVER_KEY belum diset di environment variable.\n"
            "Tambahkan ke .env: MIDTRANS_SERVER_KEY=SB-Mid-server-xxxx"
        )

    payload = {
        "transaction_details": {
            "order_id":     order_id,
            "gross_amount": amount,
        },
        "customer_details": {
            "first_name": username,
            "email":      email or f"{username}@suarakata.id",
        },
        "item_details": [
            {
                "id":       "BALANCE_TOPUP",
                "price":    amount,
                "quantity": 1,
                "name":     f"Top Up Saldo Rp {amount:,}",
            }
        ],
        # Expired 1 jam setelah dibuat (bisa diubah)
        "expiry": {
            "unit":     "hour",
            "duration": 1,
        },
    }

    import base64
    auth = base64.b64encode(f"{MIDTRANS_SERVER_KEY}:".encode()).decode()

    async with httpx.AsyncClient(timeout=_HTTP_TIMEOUT) as client:
        resp = await client.post(
            _SNAP_URL,
            json=payload,
            headers={
                "Authorization": f"Basic {auth}",
                "Content-Type":  "application/json",
                "Accept":        "application/json",
            },
        )

    if resp.status_code not in (200, 201):
        logger.error(
            "[Midtrans] Gagal membuat Snap transaction. Status=%d Body=%s",
            resp.status_code, resp.text[:500],
        )
        raise RuntimeError(
            f"Midtrans mengembalikan error {resp.status_code}: {resp.text[:200]}"
        )

    data = resp.json()
    token = data.get("token")
    if not token:
        raise RuntimeError(f"Midtrans tidak mengembalikan token. Response: {data}")

    logger.info(
        "[Midtrans] Snap token dibuat: order_id=%s amount=%d user_id=%d",
        order_id, amount, user_id,
    )
    return token


def verify_notification(payload: dict) -> bool:
    """
    Verifikasi signature notifikasi Midtrans menggunakan SHA-512.

    Formula Midtrans:
        SHA512(order_id + status_code + gross_amount + server_key)

    Kembalikan True jika tanda tangan cocok, False jika tidak.
    JANGAN proses pembayaran jika False — kemungkinan request palsu.
    """
    if not MIDTRANS_SERVER_KEY:
        logger.error("[Midtrans] MIDTRANS_SERVER_KEY kosong — tidak bisa verifikasi.")
        return False

    order_id     = payload.get("order_id", "")
    status_code  = payload.get("status_code", "")
    gross_amount = payload.get("gross_amount", "")
    sig_received = payload.get("signature_key", "")

    raw = f"{order_id}{status_code}{gross_amount}{MIDTRANS_SERVER_KEY}"
    sig_expected = hashlib.sha512(raw.encode()).hexdigest()

    if sig_received != sig_expected:
        logger.warning(
            "[Midtrans] Signature tidak cocok untuk order_id=%s. "
            "Kemungkinan request palsu.",
            order_id,
        )
        return False

    return True


def is_payment_success(payload: dict) -> bool:
    """
    Tentukan apakah pembayaran dianggap berhasil berdasarkan status Midtrans.

    transaction_status yang dianggap berhasil:
      - settlement  : pembayaran dikonfirmasi penuh
      - capture     : kartu kredit/debit (perlu cek fraud_status)

    fraud_status harus 'accept' atau tidak ada (bukan 'deny' atau 'challenge').
    """
    tx_status    = payload.get("transaction_status", "")
    fraud_status = payload.get("fraud_status", "accept")

    if tx_status == "settlement":
        return True

    if tx_status == "capture" and fraud_status == "accept":
        return True

    return False


def is_payment_failed(payload: dict) -> bool:
    """Kembalikan True jika pembayaran gagal atau ditolak."""
    tx_status = payload.get("transaction_status", "")
    return tx_status in ("deny", "cancel", "failure")


def is_payment_expired(payload: dict) -> bool:
    """Kembalikan True jika pembayaran kedaluwarsa."""
    return payload.get("transaction_status") == "expire"


# ── Pilihan nominal top-up yang tersedia ─────────────────────────────
TOPUP_AMOUNTS = [10_000, 25_000, 50_000, 100_000, 250_000, 500_000]