import { sql } from 'drizzle-orm'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import { isOversoldError } from './errors.js'
import { startPg } from './pg-harness.js'
import { reserve } from './reserve.js'
import { setInventory } from './set-inventory.js'
import type { TransactionalDatabase } from '@platform-modules/db'
import type { InventorySchema } from './schema.js'

const INTERLEAVE_SKU = '33333333-3333-4333-8333-333333333333'
const STRESS_SKU = '44444444-4444-4444-8444-444444444444'
const NOW = new Date('2026-06-19T12:00:00.000Z')

function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

describe('reserve concurrency (real Postgres)', () => {
  let db: TransactionalDatabase<InventorySchema>
  let stop: (() => Promise<void>) | undefined

  beforeAll(async () => {
    const pg = await startPg()
    db = pg.db
    stop = pg.stop
  }, 120_000)

  afterAll(async () => {
    await stop?.()
  }, 30_000)

  it('deterministic interleave: one winner, loser → OversoldError, exactly one row', async () => {
    await db.transaction((tx) => setInventory(tx, { skuId: INTERLEAVE_SKU, quantityTotal: 1 }))

    let resolveHold!: () => void
    const hold = new Promise<void>((resolve) => {
      resolveHold = resolve
    })

    let txALocked!: () => void
    const txAHasLock = new Promise<void>((resolve) => {
      txALocked = resolve
    })

    const txA = db.transaction(async (txA) => {
      await reserve(txA, { skuId: INTERLEAVE_SKU, qty: 1, holderRef: 'A', now: NOW })
      txALocked()
      await hold
    })

    await txAHasLock

    const txB = db.transaction(async (txB) => {
      await reserve(txB, { skuId: INTERLEAVE_SKU, qty: 1, holderRef: 'B', now: NOW })
    })

    await sleep(400)
    resolveHold()

    const results = await Promise.allSettled([txA, txB])
    const fulfilled = results.filter((r) => r.status === 'fulfilled')
    const rejected = results.filter((r) => r.status === 'rejected')

    expect(fulfilled).toHaveLength(1)
    expect(rejected).toHaveLength(1)
    expect(isOversoldError((rejected[0] as PromiseRejectedResult).reason)).toBe(true)

    const countRes = (await db.execute(sql`
      SELECT COUNT(*)::int AS count FROM stock_reservation WHERE sku_id = ${INTERLEAVE_SKU}::uuid
    `)) as unknown as { rows?: Array<{ count: number }> } | Array<{ count: number }>
    const rows = (Array.isArray(countRes) ? countRes : countRes.rows) ?? []
    expect(Number(rows[0]?.count)).toBe(1)
  })

  it('stress fan-out N=30 on stock=1 → 1 success, 29 OversoldError', async () => {
    await db.transaction((tx) => setInventory(tx, { skuId: STRESS_SKU, quantityTotal: 1 }))

    const results = await Promise.allSettled(
      Array.from({ length: 30 }, (_, i) =>
        db.transaction((tx) =>
          reserve(tx, { skuId: STRESS_SKU, qty: 1, holderRef: `h${i}`, now: NOW }),
        ),
      ),
    )

    const fulfilled = results.filter((r) => r.status === 'fulfilled')
    const oversold = results.filter(
      (r) => r.status === 'rejected' && isOversoldError((r as PromiseRejectedResult).reason),
    )

    expect(fulfilled).toHaveLength(1)
    expect(oversold).toHaveLength(29)

    const countRes = (await db.execute(sql`
      SELECT COUNT(*)::int AS count FROM stock_reservation WHERE sku_id = ${STRESS_SKU}::uuid
    `)) as unknown as { rows?: Array<{ count: number }> } | Array<{ count: number }>
    const rows = (Array.isArray(countRes) ? countRes : countRes.rows) ?? []
    expect(Number(rows[0]?.count)).toBe(1)
  })
})
