import { and, eq, isNull, sql } from 'drizzle-orm';
import type { DrizzleClient, TxDrizzleClient } from '@/server/db/client.js';
import { stockReservations } from '@/server/db/schema.js';
import { asStockReservationId } from '@/server/platform-seams/ids.js';

export type SqlExecutor = DrizzleClient | TxDrizzleClient;

export async function releaseReservation(db: DrizzleClient, reservationId: string): Promise<void> {
  await db
    .update(stockReservations)
    .set({ releasedAt: new Date() })
    .where(
      and(
        eq(stockReservations.id, asStockReservationId(reservationId)),
        isNull(stockReservations.releasedAt),
        isNull(stockReservations.consumedAt),
      ),
    );
}

export async function insertReservation(
  tx: SqlExecutor,
  input: {
    skuId: string;
    userId: string;
    qty: number;
    paymentIntentId: string;
    expiresAt: Date;
    cartTokenHash?: string;
  },
): Promise<string> {
  const result = (await tx.execute<{ id: string }>(sql`
    INSERT INTO stock_reservations
      (sku_id, user_id, cart_token_hash, qty, payment_intent_id, expires_at)
    VALUES
      (${input.skuId}::uuid, ${input.userId}::uuid, ${input.cartTokenHash ?? null}, ${input.qty},
       ${input.paymentIntentId}, ${input.expiresAt.toISOString()}::timestamptz)
    RETURNING id
  `)) as { rows: Array<{ id: string }> };
  const row = result.rows[0];
  if (!row?.id) throw new Error(`oversold:${input.skuId}`);
  return row.id;
}
