'use server';

import { GpmPay } from '@gpmpay/sdk';
import { GpmPayPermissionError } from '@gpmpay/sdk';
import {
  buildPaymentInstructions,
  type PaymentInstructions as SdkPaymentInstructions,
} from '@gpmpay/sdk/vietqr';

// Module scope: constructed once per server instance. Throws at import time if
// GPMPAY_API_TOKEN is missing — which is what you want, so a misconfigured
// deploy fails immediately rather than at the first checkout.
const client = new GpmPay({ apiToken: process.env.GPMPAY_API_TOKEN! });

/**
 * Only these fields cross to the browser. Never the client, never the token.
 *
 * Derived from the SDK's own return type rather than re-declared, so a change
 * to `buildPaymentInstructions` breaks this build instead of silently drifting.
 */
export type CheckoutPayment = SdkPaymentInstructions & { code: string };

/**
 * Mint the payment code and build the QR.
 *
 * GPM Pay has no "create order" endpoint — the code is yours, derived from the
 * cart so a double-submitted form produces the *same* code rather than a second
 * pending payment. Store it against the cart before returning.
 */
export async function createPayment(
  cartId: string,
  amountVnd: number,
): Promise<CheckoutPayment> {
  const amount = Math.round(amountVnd); // must be an integer number of VND

  // Keep it A-Z0-9 and short: VietQR truncates the description to 25 chars and
  // some banks prepend their own prefix to the transfer content.
  const code = `ORD${cartId}`;

  try {
    const account = await client.bankAccounts.retrieve(
      process.env.GPMPAY_BANK_ACCOUNT_ID!,
    );

    const instructions = buildPaymentInstructions({
      bankAccount: account,
      amount,
      transferContent: code,
    });

    // await db.carts.update(cartId, { paymentCode: code, status: 'AWAITING_PAYMENT' });

    return { code, ...instructions };
  } catch (error) {
    if (error instanceof GpmPayPermissionError) {
      console.error(
        `GPM Pay token rejected (${error.reason}): ${error.missingScope ?? 'n/a'}`,
      );
      throw new Error('Payment is misconfigured — please contact support.');
    }
    throw error;
  }
}

/**
 * Let the page poll your own database while it waits.
 *
 * There is nothing to poll on the GPM Pay side: payment status lives in your
 * system, written by the webhook route. Polling GPM Pay's transaction list
 * would work but costs a round-trip per check and races with the webhook.
 */
export async function getPaymentStatus(code: string) {
  // return db.carts.findByPaymentCode(code);
  return { code, status: 'PENDING' as const, paidAt: null };
}
