import { and, eq } from 'drizzle-orm'
import type { PostgresTransaction } from '@platform-modules/db'
import { OrderChargeConflictError, OrderNotChargeableError } from './errors.js'
import { order, type OrdersSchema } from './schema.js'
import { assertUuid } from './types.js'

export async function markPaid(
  tx: PostgresTransaction<OrdersSchema>,
  orderId: string,
  chargeRef: string,
): Promise<void> {
  assertUuid(orderId, 'orderId')

  const now = new Date()
  const [updated] = await tx
    .update(order)
    .set({ status: 'paid', chargeRef, updatedAt: now })
    .where(and(eq(order.id, orderId), eq(order.status, 'charging')))
    .returning({ id: order.id })

  if (updated) {
    return
  }

  const [existing] = await tx.select().from(order).where(eq(order.id, orderId))

  if (!existing) {
    throw new OrderNotChargeableError(orderId)
  }

  // A chargeRef is written exactly once (by the UPDATE above), so a non-null
  // ref disambiguates regardless of how far the order has since progressed
  // (div 8): matching ref ⇒ this settlement already won — idempotent even on
  // refunded/fulfilled/completed (providers redeliver settlement events for
  // days; throwing here turns a post-refund redelivery into a retry loop);
  // different ref ⇒ two charges hit one order — a money anomaly.
  if (existing.chargeRef !== null && existing.chargeRef !== '') {
    if (existing.chargeRef === chargeRef) {
      return
    }
    throw new OrderChargeConflictError({
      orderId,
      existingChargeRef: existing.chargeRef,
      attemptedChargeRef: chargeRef,
    })
  }

  throw new OrderNotChargeableError(orderId)
}
