import { prisma } from './db.js';
import { formatFiat, paymentsProvider } from './shopCatalog.js';
import { getPurchasableOsuPack } from './shopOsu.js';

/**
 * Create a pending osu top-up order.
 * Mock provider completes client-side via /confirm.
 * Stripe provider (when configured) would return a clientSecret.
 */
export async function createOsuCheckout(userId, packId) {
  const pack = await getPurchasableOsuPack(packId);
  if (!pack) {
    const err = new Error('Unknown or disabled osu pack');
    err.status = 400;
    throw err;
  }

  const provider = paymentsProvider();

  const order = await prisma.paymentOrder.create({
    data: {
      userId: Number(userId),
      packId: pack.id,
      osuAmount: pack.osu,
      priceCents: pack.priceCents,
      currency: pack.currency,
      status: 'pending',
      provider,
      meta: JSON.stringify({
        packName: pack.name,
        displayPrice: formatFiat(pack.priceCents, pack.currency),
      }),
    },
  });

  if (provider === 'stripe') {
    // Placeholder for Stripe PaymentIntent wiring.
    // Set PAYMENTS_PROVIDER=stripe + STRIPE_SECRET_KEY when ready.
    const err = new Error(
      'Stripe checkout is configured but not wired yet — set PAYMENTS_PROVIDER=mock for local buys'
    );
    err.status = 501;
    throw err;
  }

  return {
    order: serializeOrder(order),
    pack: {
      id: pack.id,
      name: pack.name,
      osu: pack.osu,
      priceCents: pack.priceCents,
      currency: pack.currency,
      displayPrice: formatFiat(pack.priceCents, pack.currency),
    },
    mode: 'mock',
    /** Client calls POST /api/shop/osu/confirm with this id in mock mode */
    confirmable: true,
  };
}

/**
 * Complete a mock checkout and credit osu (idempotent).
 */
export async function confirmMockOsuPayment(userId, orderId) {
  const id = String(orderId || '');
  if (!id) {
    const err = new Error('Missing order id');
    err.status = 400;
    throw err;
  }

  return prisma.$transaction(async (tx) => {
    const order = await tx.paymentOrder.findUnique({ where: { id } });
    if (!order || order.userId !== Number(userId)) {
      const err = new Error('Order not found');
      err.status = 404;
      throw err;
    }
    if (order.status === 'paid') {
      const user = await tx.user.findUnique({ where: { id: userId } });
      return { order: serializeOrder(order), user, alreadyPaid: true };
    }
    if (order.status !== 'pending') {
      const err = new Error(`Order is ${order.status}`);
      err.status = 400;
      throw err;
    }
    if (order.provider !== 'mock') {
      const err = new Error('This order must be completed by the payment provider');
      err.status = 400;
      throw err;
    }

    const now = new Date();
    const updatedOrder = await tx.paymentOrder.update({
      where: { id: order.id },
      data: { status: 'paid', paidAt: now },
    });

    const user = await tx.user.update({
      where: { id: userId },
      data: { osuBalance: { increment: order.osuAmount } },
    });

    await tx.transaction.create({
      data: {
        userId,
        type: 'osu_purchase',
        amount: String(order.osuAmount),
        meta: JSON.stringify({
          orderId: order.id,
          packId: order.packId,
          priceCents: order.priceCents,
          currency: order.currency,
          provider: order.provider,
        }),
      },
    });

    return { order: serializeOrder(updatedOrder), user, alreadyPaid: false };
  });
}

export function serializeOrder(order) {
  return {
    id: order.id,
    packId: order.packId,
    osuAmount: order.osuAmount,
    priceCents: order.priceCents,
    currency: order.currency,
    status: order.status,
    provider: order.provider,
    displayPrice: formatFiat(order.priceCents, order.currency),
    createdAt: order.createdAt,
    paidAt: order.paidAt || null,
  };
}
