"""
BizNode License Purchase Service
==================================
Handles the complete license purchase flow for both Stripe and crypto payments.

Stripe flow:
  1. Customer clicks payment link → Stripe checkout
  2. Webhook confirms payment → generate BZN key → email customer + owner

Crypto flow:
  1. Customer initiates purchase via bot → OTP sent to email (15-min window)
  2. Customer submits OTP + Polygon tx hash (BZeUSD token payment)
  3. System verifies OTP validity + tx hash on Polygonscan
  4. If valid → generate BZN key → email customer + owner

Pro license:
  - Payment confirmed → owner notified to dispatch USB
  - Owner provides USB serial number via dashboard
"""

import hashlib
import importlib.util
import json
import logging
import os
import random
import re
import string
import time
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Optional

log = logging.getLogger("biznode.license_purchase")
_PROJECT_ROOT = Path(__file__).resolve().parent.parent

# Pricing
BASIC_PRICE_USD = float(os.getenv("BASIC_LICENSE_PRICE", "200"))
PRO_PRICE_USD = float(os.getenv("PRO_LICENSE_PRICE", "499"))
BASIC_STRIPE_PLINK = os.getenv(
    "BASIC_STRIPE_PLINK",
    "https://buy.stripe.com/6oU3cvcoA6GN4697sJ7ss0j",
)
BZEUSD_CONTRACT = os.getenv("BZEUSD_CONTRACT", "")
BIZNODE_WALLET = os.getenv("BIZNODE_WALLET_ADDRESS", "0xb96e2C9f4b05042eb6D39DA4cd9c6B1b4ab9afe3")
POLYGONSCAN_API_KEY = os.getenv("POLYGONSCAN_API_KEY", "")
POLYGON_RPC = os.getenv("POLYGON_RPC_URL", "https://polygon-rpc.com")

# OTP config
CRYPTO_OTP_EXPIRY_MINUTES = 15


def _load_db():
    spec = importlib.util.spec_from_file_location("_db", str(_PROJECT_ROOT / "memory" / "database.py"))
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod


# ---------------------------------------------------------------------------
# License key generation
# ---------------------------------------------------------------------------

def generate_license_key() -> str:
    """Generate a BZN-XXXXX-XXXXX-XXXXX license key."""
    chars = string.ascii_uppercase + string.digits
    parts = ["".join(random.choices(chars, k=5)) for _ in range(3)]
    return f"BZN-{parts[0]}-{parts[1]}-{parts[2]}"


# ---------------------------------------------------------------------------
# Stripe purchase flow
# ---------------------------------------------------------------------------

def create_stripe_license_purchase(
    email: str,
    customer_name: str = "",
    telegram_id: str = "",
    license_type: str = "basic",
) -> dict:
    """
    Create a license purchase record and return the Stripe payment link.
    For Basic: uses the pre-configured Stripe payment link.
    For Pro: creates a custom checkout session.
    """
    db = _load_db()
    ref = db.generate_reference_no()

    price = BASIC_PRICE_USD if license_type == "basic" else PRO_PRICE_USD

    db.create_license_purchase(
        reference_no=ref,
        email=email,
        license_type=license_type,
        telegram_id=telegram_id,
        customer_name=customer_name,
        payment_method="stripe",
        amount=price,
        currency="USD",
    )

    if license_type == "basic":
        # Use pre-configured payment link with reference
        payment_url = f"{BASIC_STRIPE_PLINK}?client_reference_id={ref}"
        return {
            "ok": True,
            "reference_no": ref,
            "payment_url": payment_url,
            "amount": price,
            "license_type": "basic",
        }
    else:
        # Pro — create custom Stripe session
        try:
            from services.stripe_service import create_checkout_session
            result = create_checkout_session(
                telegram_id=telegram_id,
                service_name=f"BizNode Pro License",
                amount=price,
                currency="usd",
                customer_email=email,
                reference_no=ref,
            )
            if result.get("ok"):
                db.update_license_purchase(ref, stripe_session_id=result.get("session_id", ""))
                return {
                    "ok": True,
                    "reference_no": ref,
                    "payment_url": result["url"],
                    "amount": price,
                    "license_type": "pro",
                }
            return {"ok": False, "error": result.get("error", "Stripe session creation failed")}
        except Exception as exc:
            return {"ok": False, "error": str(exc)}


def handle_stripe_license_payment(
    reference_no: str = "",
    payment_intent: str = "",
    customer_email: str = "",
    amount: float = 0,
    client_reference_id: str = "",
) -> dict:
    """
    Called from Stripe webhook when a license payment is confirmed.
    Generates license key, updates DB, sends emails.
    """
    db = _load_db()

    # Find the purchase record
    ref = reference_no or client_reference_id
    if not ref:
        log.warning("No reference found in Stripe webhook for license payment")
        return {"ok": False, "error": "No reference found"}

    purchase = db.get_license_purchase(ref)
    if not purchase:
        log.warning("License purchase not found for ref=%s", ref)
        return {"ok": False, "error": "Purchase not found"}

    if purchase["status"] == "paid":
        log.info("License purchase already processed: ref=%s", ref)
        return {"ok": True, "already_processed": True}

    license_type = purchase["license_type"]
    email = customer_email or purchase["email"]

    if license_type == "basic":
        # Generate license key
        license_key = generate_license_key()
        db.update_license_purchase(
            ref,
            status="paid",
            license_key=license_key,
            stripe_payment_intent=payment_intent,
        )

        # Send license key to customer
        _send_license_email(email, license_key, ref, purchase.get("customer_name", ""))

        # Notify owner
        _notify_owner_basic_purchase(email, license_key, ref, amount)

        log.info("Basic license generated: ref=%s key=%s email=%s", ref, license_key, email)
        return {
            "ok": True,
            "license_type": "basic",
            "license_key": license_key,
            "reference_no": ref,
        }

    elif license_type == "pro":
        # Pro: mark as paid, notify owner to dispatch USB
        db.update_license_purchase(
            ref,
            status="paid",
            stripe_payment_intent=payment_intent,
        )

        _notify_owner_pro_purchase(email, ref, amount, purchase.get("customer_name", ""))

        log.info("Pro license payment confirmed: ref=%s email=%s — awaiting USB dispatch", ref, email)
        return {
            "ok": True,
            "license_type": "pro",
            "reference_no": ref,
            "awaiting_usb_dispatch": True,
        }

    return {"ok": False, "error": "Unknown license type"}


# ---------------------------------------------------------------------------
# Crypto purchase flow
# ---------------------------------------------------------------------------

def initiate_crypto_purchase(
    email: str,
    telegram_id: str = "",
    customer_name: str = "",
    license_type: str = "basic",
) -> dict:
    """
    Start the crypto payment flow:
    1. Create purchase record
    2. Generate OTP (15-min window)
    3. Send OTP to customer email
    4. Return payment instructions
    """
    import hashlib as _hashlib

    db = _load_db()
    ref = db.generate_reference_no()
    price = BASIC_PRICE_USD if license_type == "basic" else PRO_PRICE_USD

    # Create purchase record
    db.create_license_purchase(
        reference_no=ref,
        email=email,
        license_type=license_type,
        telegram_id=telegram_id,
        customer_name=customer_name,
        payment_method="crypto",
        amount=price,
        currency="USD",
    )

    # Generate 6-digit OTP
    otp_code = "".join(random.choices(string.digits, k=6))
    otp_hash = _hashlib.sha256(otp_code.encode()).hexdigest()
    expires_at = (datetime.now(timezone.utc) + timedelta(minutes=CRYPTO_OTP_EXPIRY_MINUTES)).isoformat()

    db.create_crypto_payment_otp(
        reference_no=ref,
        email=email,
        otp_hash=otp_hash,
        expires_at=expires_at,
        telegram_id=telegram_id,
        amount=price,
        currency="USD",
        license_type=license_type,
    )

    # Send OTP email
    _send_crypto_otp_email(email, otp_code, ref, price, license_type)

    token_name = "BZeUSD" if BZEUSD_CONTRACT else "MATIC"

    return {
        "ok": True,
        "reference_no": ref,
        "amount": price,
        "license_type": license_type,
        "wallet_address": BIZNODE_WALLET,
        "token": token_name,
        "otp_sent_to": _mask_email(email),
        "otp_expires_minutes": CRYPTO_OTP_EXPIRY_MINUTES,
        "message": (
            f"OTP sent to {_mask_email(email)}. Valid for {CRYPTO_OTP_EXPIRY_MINUTES} minutes.\n\n"
            f"Send ${price:.2f} in {token_name} to:\n"
            f"`{BIZNODE_WALLET}`\n\n"
            f"Then submit your OTP and transaction hash."
        ),
    }


def verify_crypto_purchase(
    reference_no: str,
    otp_code: str,
    transaction_hash: str,
) -> dict:
    """
    Verify a crypto license purchase:
    1. Check OTP is valid and not expired
    2. Verify transaction hash on Polygonscan
    3. If both pass → generate license key → email customer + owner
    """
    db = _load_db()

    # Get the OTP record
    otp_record = db.get_active_crypto_otp(reference_no)
    if not otp_record:
        return {"ok": False, "error": "No active payment session found for this reference. It may have expired."}

    # Check expiry
    expires_at = datetime.fromisoformat(otp_record["expires_at"].replace("Z", "+00:00"))
    now = datetime.now(timezone.utc)
    if now > expires_at:
        db.update_crypto_otp(otp_record["id"], status="expired")
        return {"ok": False, "error": "OTP has expired. Please start a new purchase."}

    # Check attempts
    if otp_record["attempts"] >= 5:
        db.update_crypto_otp(otp_record["id"], status="blocked")
        return {"ok": False, "error": "Too many attempts. Please start a new purchase."}

    # Verify OTP
    import hashlib as _hashlib
    otp_hash = _hashlib.sha256(otp_code.strip().encode()).hexdigest()
    db.update_crypto_otp(otp_record["id"], attempts=otp_record["attempts"] + 1)

    if otp_hash != otp_record["otp_hash"]:
        remaining = 5 - (otp_record["attempts"] + 1)
        return {"ok": False, "error": f"Invalid OTP. {remaining} attempts remaining."}

    # Verify transaction hash format
    tx_hash = transaction_hash.strip()
    if not re.match(r'^0x[a-fA-F0-9]{64}$', tx_hash):
        return {"ok": False, "error": "Invalid transaction hash format. Must be 0x followed by 64 hex characters."}

    # Verify on Polygonscan
    tx_verified, tx_info = verify_polygon_transaction(
        tx_hash,
        expected_to=BIZNODE_WALLET,
        expected_amount=otp_record["amount"],
    )

    if not tx_verified:
        return {
            "ok": False,
            "error": f"Transaction verification failed: {tx_info}. "
                     "Check that you sent the correct amount to the correct wallet.",
        }

    # Both OTP and tx verified — process the purchase
    db.update_crypto_otp(
        otp_record["id"],
        status="verified",
        transaction_hash=tx_hash,
        verified_at=now.isoformat(),
    )

    purchase = db.get_license_purchase(reference_no)
    if not purchase:
        return {"ok": False, "error": "Purchase record not found"}

    license_type = purchase["license_type"]
    email = purchase["email"]

    if license_type == "basic":
        license_key = generate_license_key()
        db.update_license_purchase(
            reference_no,
            status="paid",
            license_key=license_key,
            transaction_hash=tx_hash,
        )
        _send_license_email(email, license_key, reference_no, purchase.get("customer_name", ""))
        _notify_owner_basic_purchase(email, license_key, reference_no, purchase["amount"], payment_method="crypto")

        return {
            "ok": True,
            "license_type": "basic",
            "license_key": license_key,
            "reference_no": reference_no,
            "message": f"Payment verified! Your license key has been sent to {_mask_email(email)}.",
        }

    elif license_type == "pro":
        db.update_license_purchase(
            reference_no,
            status="paid",
            transaction_hash=tx_hash,
        )
        _notify_owner_pro_purchase(email, reference_no, purchase["amount"],
                                    purchase.get("customer_name", ""), payment_method="crypto")
        return {
            "ok": True,
            "license_type": "pro",
            "reference_no": reference_no,
            "message": "Payment verified! The owner has been notified to prepare your Pro USB license.",
        }

    return {"ok": False, "error": "Unknown license type"}


# ---------------------------------------------------------------------------
# Polygonscan transaction verification
# ---------------------------------------------------------------------------

def verify_polygon_transaction(
    tx_hash: str,
    expected_to: str = "",
    expected_amount: float = 0,
) -> tuple:
    """
    Verify a Polygon transaction using Polygonscan API or RPC.
    Returns (verified: bool, info: str).
    """
    try:
        import requests

        # Method 1: Polygonscan API (preferred)
        if POLYGONSCAN_API_KEY:
            url = (
                f"https://api.polygonscan.com/api"
                f"?module=proxy&action=eth_getTransactionByHash"
                f"&txhash={tx_hash}"
                f"&apikey={POLYGONSCAN_API_KEY}"
            )
            r = requests.get(url, timeout=15)
            if r.ok:
                data = r.json()
                result = data.get("result")
                if not result or result == "null":
                    return False, "Transaction not found on Polygon network"

                to_addr = (result.get("to") or "").lower()
                if expected_to and to_addr != expected_to.lower():
                    return False, f"Transaction recipient does not match BizNode wallet"

                # Check if tx is confirmed (has blockNumber)
                if not result.get("blockNumber"):
                    return False, "Transaction is still pending (not yet confirmed)"

                # For ERC-20 (BZeUSD), check the input data
                # For native MATIC, check the value
                value_hex = result.get("value", "0x0")
                value_wei = int(value_hex, 16)

                if BZEUSD_CONTRACT:
                    # ERC-20 transfer — check input data
                    input_data = result.get("input", "")
                    if input_data.startswith("0xa9059cbb"):
                        # transfer(address,uint256) — standard ERC-20
                        # to_addr in input is at bytes 4-36, amount at 36-68
                        log.info("BZeUSD transfer detected in tx %s", tx_hash)
                        return True, "BZeUSD transfer verified"
                    elif value_wei > 0:
                        return True, f"MATIC transfer verified ({value_wei / 1e18:.4f} MATIC)"
                    else:
                        return False, "No BZeUSD or MATIC transfer found in transaction"
                else:
                    if value_wei > 0:
                        return True, f"MATIC transfer verified ({value_wei / 1e18:.4f} MATIC)"
                    return False, "No value transferred in transaction"

        # Method 2: Direct RPC (fallback)
        payload = {
            "jsonrpc": "2.0",
            "method": "eth_getTransactionByHash",
            "params": [tx_hash],
            "id": 1,
        }
        r = requests.post(POLYGON_RPC, json=payload, timeout=15)
        if r.ok:
            result = r.json().get("result")
            if not result:
                return False, "Transaction not found"

            to_addr = (result.get("to") or "").lower()
            if expected_to and to_addr != expected_to.lower():
                return False, "Recipient does not match BizNode wallet"

            if not result.get("blockNumber"):
                return False, "Transaction still pending"

            value_hex = result.get("value", "0x0")
            value_wei = int(value_hex, 16)
            if value_wei > 0 or (BZEUSD_CONTRACT and result.get("input", "").startswith("0xa9059cbb")):
                return True, "Transaction verified via RPC"
            return False, "No value transferred"

        return False, "Could not reach Polygon network"

    except Exception as exc:
        log.error("Polygon tx verification failed: %s", exc)
        return False, f"Verification error: {exc}"


# ---------------------------------------------------------------------------
# Pro USB dispatch
# ---------------------------------------------------------------------------

def assign_usb_serial(reference_no: str, usb_serial: str) -> dict:
    """Owner assigns a USB serial number for Pro license dispatch."""
    db = _load_db()
    purchase = db.get_license_purchase(reference_no)
    if not purchase:
        return {"ok": False, "error": "Purchase not found"}
    if purchase["license_type"] != "pro":
        return {"ok": False, "error": "USB serial only applies to Pro licenses"}
    if purchase["status"] not in ("paid",):
        return {"ok": False, "error": f"Cannot assign USB to purchase with status: {purchase['status']}"}

    db.update_license_purchase(
        reference_no,
        usb_serial=usb_serial,
        status="dispatching",
    )

    # Notify customer
    _send_pro_dispatch_email(purchase["email"], reference_no, purchase.get("customer_name", ""))

    log.info("USB serial assigned: ref=%s serial=%s", reference_no, usb_serial)
    return {"ok": True, "message": f"USB serial {usb_serial} assigned. Customer notified."}


def activate_pro_license(reference_no: str) -> dict:
    """Mark a Pro license as activated (USB delivered and working)."""
    db = _load_db()
    purchase = db.get_license_purchase(reference_no)
    if not purchase:
        return {"ok": False, "error": "Purchase not found"}

    db.update_license_purchase(
        reference_no,
        status="activated",
        activated_at=datetime.now(timezone.utc).isoformat(),
    )
    return {"ok": True, "message": "Pro license activated."}


# ---------------------------------------------------------------------------
# Email helpers
# ---------------------------------------------------------------------------

def _mask_email(email: str) -> str:
    if "@" not in email:
        return "***"
    local, domain = email.split("@", 1)
    if len(local) <= 1:
        return f"*@{domain}"
    return f"{local[0]}***@{domain}"


def _send_license_email(email: str, license_key: str, reference_no: str, customer_name: str = ""):
    """Send the generated Basic license key to the customer."""
    try:
        from services.email_service import EmailService
        es = EmailService()
        name = customer_name or "Customer"
        body = f"""
<html><body>
<h2>Your BizNode Basic License</h2>
<p>Hello {name},</p>
<p>Thank you for purchasing BizNode Basic! Your license key is:</p>
<div style="background: #f4f4f4; padding: 20px; font-size: 24px; font-family: monospace; text-align: center; margin: 20px 0; border-radius: 8px;">
    <strong>{license_key}</strong>
</div>
<p><strong>How to activate:</strong></p>
<ol>
    <li>Save the key to a file called <code>.license_key</code> in your BizNode folder:
        <br><code>echo {license_key} &gt; .license_key</code></li>
    <li>Restart BizNode: <code>python launcher.py</code></li>
</ol>
<p>Reference: {reference_no}</p>
<p>If you need help, contact us at <a href="mailto:biznode@1bz.biz">biznode@1bz.biz</a></p>
<p>— BizNode Team</p>
</body></html>
"""
        es.send_html_email(email, "Your BizNode License Key", body)
        log.info("License key email sent to %s", _mask_email(email))
    except Exception as exc:
        log.error("Failed to send license email: %s", exc)


def _notify_owner_basic_purchase(email: str, license_key: str, reference_no: str,
                                  amount: float, payment_method: str = "stripe"):
    """Notify owner that a Basic license was purchased."""
    try:
        from services.email_service import EmailService
        es = EmailService()
        owner_email = os.getenv("OWNER_EMAIL", "")
        if not owner_email:
            return
        body = f"""
<html><body>
<h2>New Basic License Purchase</h2>
<table style="border-collapse: collapse;">
    <tr><td style="padding: 5px 15px;"><strong>Reference:</strong></td><td>{reference_no}</td></tr>
    <tr><td style="padding: 5px 15px;"><strong>Customer Email:</strong></td><td>{email}</td></tr>
    <tr><td style="padding: 5px 15px;"><strong>Amount:</strong></td><td>${amount:.2f} USD</td></tr>
    <tr><td style="padding: 5px 15px;"><strong>Payment:</strong></td><td>{payment_method.upper()}</td></tr>
    <tr><td style="padding: 5px 15px;"><strong>License Key:</strong></td><td><code>{license_key}</code></td></tr>
    <tr><td style="padding: 5px 15px;"><strong>Status:</strong></td><td>AUTO-REGISTERED</td></tr>
</table>
<p>The license key has been automatically sent to the customer.</p>
<p>— BizNode System</p>
</body></html>
"""
        es.send_html_email(owner_email, f"New License Sale: {reference_no}", body)
    except Exception as exc:
        log.error("Failed to notify owner: %s", exc)


def _notify_owner_pro_purchase(email: str, reference_no: str, amount: float,
                                customer_name: str = "", payment_method: str = "stripe"):
    """Notify owner that a Pro license was purchased — USB dispatch needed."""
    try:
        from services.email_service import EmailService
        es = EmailService()
        owner_email = os.getenv("OWNER_EMAIL", "")
        if not owner_email:
            return
        body = f"""
<html><body>
<h2>New Pro License Purchase — USB Dispatch Required</h2>
<table style="border-collapse: collapse;">
    <tr><td style="padding: 5px 15px;"><strong>Reference:</strong></td><td>{reference_no}</td></tr>
    <tr><td style="padding: 5px 15px;"><strong>Customer:</strong></td><td>{customer_name or 'N/A'}</td></tr>
    <tr><td style="padding: 5px 15px;"><strong>Email:</strong></td><td>{email}</td></tr>
    <tr><td style="padding: 5px 15px;"><strong>Amount:</strong></td><td>${amount:.2f} USD</td></tr>
    <tr><td style="padding: 5px 15px;"><strong>Payment:</strong></td><td>{payment_method.upper()}</td></tr>
</table>
<h3>ACTION REQUIRED:</h3>
<ol>
    <li>Prepare a USB drive with Pro license files</li>
    <li>Go to Dashboard → License Purchases</li>
    <li>Enter the USB serial number for reference {reference_no}</li>
    <li>Ship the USB to the customer</li>
</ol>
<p>— BizNode System</p>
</body></html>
"""
        es.send_html_email(owner_email, f"PRO LICENSE SALE — USB Dispatch: {reference_no}", body)
    except Exception as exc:
        log.error("Failed to notify owner of pro purchase: %s", exc)


def _send_pro_dispatch_email(email: str, reference_no: str, customer_name: str = ""):
    """Notify customer that their Pro USB is being dispatched."""
    try:
        from services.email_service import EmailService
        es = EmailService()
        name = customer_name or "Customer"
        body = f"""
<html><body>
<h2>Your BizNode Pro License is Being Prepared</h2>
<p>Hello {name},</p>
<p>Great news! Your BizNode Pro USB license is being prepared for dispatch.</p>
<p>Reference: <strong>{reference_no}</strong></p>
<p>You will receive tracking information once the USB has been shipped.</p>
<p>If you have questions, contact us at <a href="mailto:biznode@1bz.biz">biznode@1bz.biz</a></p>
<p>— BizNode Team</p>
</body></html>
"""
        es.send_html_email(email, "Your BizNode Pro License — Dispatch Update", body)
    except Exception as exc:
        log.error("Failed to send pro dispatch email: %s", exc)


def _send_crypto_otp_email(email: str, otp_code: str, reference_no: str,
                            amount: float, license_type: str = "basic"):
    """Send OTP for crypto payment verification."""
    try:
        from services.email_service import EmailService
        es = EmailService()
        tier_label = "Basic" if license_type == "basic" else "Pro"
        token_name = "BZeUSD" if BZEUSD_CONTRACT else "MATIC"
        body = f"""
<html><body>
<h2>BizNode {tier_label} License — Payment Verification</h2>
<p>Your one-time verification code is:</p>
<div style="background: #f4f4f4; padding: 20px; font-size: 32px; font-family: monospace; text-align: center; margin: 20px 0; border-radius: 8px;">
    <strong>{otp_code}</strong>
</div>
<p>This code expires in <strong>{CRYPTO_OTP_EXPIRY_MINUTES} minutes</strong>.</p>
<p><strong>Payment details:</strong></p>
<ul>
    <li>Amount: <strong>${amount:.2f} USD</strong> in {token_name}</li>
    <li>Send to wallet: <code>{BIZNODE_WALLET}</code></li>
    <li>Network: <strong>Polygon</strong></li>
    <li>Reference: <strong>{reference_no}</strong></li>
</ul>
<p>After sending payment, enter this OTP code and your transaction hash in the bot to complete the purchase.</p>
<p>If you did not request this, please ignore this email.</p>
<p>— BizNode Team</p>
</body></html>
"""
        es.send_html_email(email, f"BizNode Payment OTP: {otp_code}", body)
        log.info("Crypto OTP sent to %s for ref=%s", _mask_email(email), reference_no)
    except Exception as exc:
        log.error("Failed to send crypto OTP email: %s", exc)


# ---------------------------------------------------------------------------
# Query helpers
# ---------------------------------------------------------------------------

def get_purchase_status(reference_no: str) -> dict:
    """Get the status of a license purchase."""
    db = _load_db()
    purchase = db.get_license_purchase(reference_no)
    if not purchase:
        return {"ok": False, "error": "Purchase not found"}
    return {
        "ok": True,
        "reference_no": reference_no,
        "license_type": purchase["license_type"],
        "status": purchase["status"],
        "payment_method": purchase["payment_method"],
        "email": _mask_email(purchase["email"]),
        "created_at": purchase["created_at"],
    }


def get_all_purchases(status: str = None, limit: int = 50) -> list:
    """Get all license purchases."""
    db = _load_db()
    return db.get_license_purchases(status=status, limit=limit)
