/**
 * QrLoader - server-side loader for the QR code screen.
 *
 * Loads a purchase and verifies ownership before rendering the QR.
 */

import type { DrizzleClient } from '@/server/db/client.js';
import * as purchaseQueries from '@/server/db/queries/purchases.js';
import type { LineVoucherSummary } from '@/server/fulfillment/voucher-line-state.js';

export interface QrPurchaseData {
  id: string;
  dealId: string;
  userId: string | null;
  qrTokenHash: string | null;
  /** Already-hosted R2 QR image URL for the primary (first still-unredeemed) unit. */
  qrPngUrl: string | null;
  expiresAt: Date | null;
  redemptionStatus: string;
  /** Still-unredeemed units, ordered by unitIndex ASC — one QR per entry (qty>1 support). */
  unredeemedVouchers: LineVoucherSummary[];
}

export class QrAccessError extends Error {
  constructor(public readonly code: 'NOT_FOUND' | 'FORBIDDEN' | 'ALREADY_REDEEMED') {
    super(code);
    this.name = 'QrAccessError';
  }
}

/**
 * Load a purchase and verify the requesting user owns it.
 *
 * @throws {QrAccessError} if not found, forbidden, or already redeemed
 */
export async function loadQrPurchase(
  db: DrizzleClient,
  purchaseId: string,
  userId: string,
): Promise<QrPurchaseData> {
  const purchase = await purchaseQueries.findById(db, purchaseId);

  if (!purchase) throw new QrAccessError('NOT_FOUND');
  if (purchase.userId !== userId) throw new QrAccessError('FORBIDDEN');

  // Block access only when every unit is terminal. A qty>1 line with one
  // REDEEMED unit and one still-UNREDEEMED unit must stay reachable so the
  // buyer can redeem the remaining unit(s).
  const unredeemedVouchers = purchase.vouchers.filter((v) => v.state === 'UNREDEEMED');
  const anyUnredeemed =
    purchase.vouchers.length > 0
      ? unredeemedVouchers.length > 0
      : purchase.redemptionStatus !== 'REDEEMED';
  if (!anyUnredeemed) throw new QrAccessError('ALREADY_REDEEMED');

  return {
    id: purchase.id,
    dealId: purchase.dealId,
    userId: purchase.userId,
    qrTokenHash: purchase.qrTokenHash,
    qrPngUrl: unredeemedVouchers[0]?.qrPngUrl ?? purchase.qrPngUrl,
    expiresAt: purchase.expiresAt,
    redemptionStatus: purchase.redemptionStatus,
    unredeemedVouchers,
  };
}
