import { sql } from 'drizzle-orm'
import { describe, expect, it } from 'vitest'
import { isMovementNotFoundError } from './errors.js'
import { postReceipt } from './post-receipt.js'
import { reverseMovement } from './reverse-movement.js'
import {
  FIFO_ITEM_ID,
  LOCATION_A,
  NOW,
  TENANT_ID,
  firstRows,
  freshDb,
  seedItem,
  seedLocation,
} from './test-helpers.js'

describe('reverseMovement', () => {
  it('throws when no movements exist for holderRef', async () => {
    const db = await freshDb()
    await expect(
      reverseMovement(db, { tenantId: TENANT_ID, holderRef: 'missing' }),
    ).rejects.toSatisfy((error) => isMovementNotFoundError(error))
  })

  it('reverses existing holderRef movements and is idempotent after reversal exists', async () => {
    const db = await freshDb()
    await seedLocation(db, LOCATION_A)
    await seedItem(db, FIFO_ITEM_ID, 'fifo')

    await postReceipt(db, {
      tenantId: TENANT_ID,
      itemId: FIFO_ITEM_ID,
      locationId: LOCATION_A,
      qty: 2,
      unitCost: 4,
      holderRef: 'receipt-reverse',
      occurredAt: NOW,
    })

    const first = await reverseMovement(db, {
      tenantId: TENANT_ID,
      holderRef: 'receipt-reverse',
    })
    const second = await reverseMovement(db, {
      tenantId: TENANT_ID,
      holderRef: 'receipt-reverse',
    })

    expect(first).toHaveLength(1)
    expect(second[0]?.movement.id).toBe(first[0]?.movement.id)

    const qty = firstRows(await db.execute(sql`
      SELECT COALESCE(SUM(qty_delta), 0)::numeric AS qty
      FROM stock_movement
      WHERE tenant_id = ${TENANT_ID}::uuid
        AND item_id = ${FIFO_ITEM_ID}::uuid
        AND location_id = ${LOCATION_A}::uuid
    `))
    expect(Number(qty[0]?.qty ?? 0)).toBe(0)
  })
})
