import { sql } from 'drizzle-orm'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import { isInventoryValidationError } 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 = '55555555-5555-4555-8555-555555555555'
const NOW = new Date('2026-06-19T12:00:00.000Z')

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

function firstRows(res: unknown): Array<Record<string, unknown>> {
  return (Array.isArray(res) ? res : (res as { rows?: Array<Record<string, unknown>> }).rows) ?? []
}

describe('setInventory 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: reserve wins, setInventory → InventoryValidationError, total preserved', async () => {
    await db.transaction((tx) =>
      setInventory(tx, { skuId: INTERLEAVE_SKU, quantityTotal: 10 }),
    )

    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: 5, holderRef: 'A', now: NOW })
      txALocked()
      await hold
    })

    await txAHasLock

    const txB = db.transaction(async (txB) => {
      await setInventory(txB, { skuId: INTERLEAVE_SKU, quantityTotal: 4 })
    })

    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(isInventoryValidationError((rejected[0] as PromiseRejectedResult).reason)).toBe(true)

    const itemRes = await db.execute(sql`
      SELECT quantity_total, quantity_sold
      FROM inventory_item
      WHERE sku_id = ${INTERLEAVE_SKU}::uuid
    `)
    const item = firstRows(itemRes)[0]
    const total = Number(item?.quantity_total ?? 0)
    const sold = Number(item?.quantity_sold ?? 0)

    const activeRes = await db.execute(sql`
      SELECT COALESCE(SUM(qty), 0)::int AS active
      FROM stock_reservation
      WHERE sku_id = ${INTERLEAVE_SKU}::uuid
        AND consumed_at IS NULL
        AND released_at IS NULL
    `)
    const active = Number(firstRows(activeRes)[0]?.active ?? 0)

    expect(sold + active).toBeLessThanOrEqual(total)
    expect(total).toBe(10)
    expect(sold).toBe(0)
    expect(active).toBe(5)
  })
})
