import { eq } from 'drizzle-orm'
import { describe, expect, it } from 'vitest'
import {
  CommissionRateError,
  VendorNotFoundError,
  isCommissionRateError,
  isVendorAuthorizationError,
  isVendorNotFoundError,
} from './errors.js'
import { vendor } from './schema.js'
import { resolveCommissionRate, setVendorCommissionRate } from './commission.js'
import { applyAsVendor } from './vendor.js'
import { ADMIN, USER_A, freshDb } from './test-helpers.js'

describe('resolveCommissionRate', () => {
  it('resolve-rate', async () => {
    const db = await freshDb()
    const created = await db.transaction((tx) =>
      applyAsVendor(tx, { ownerUserId: USER_A, name: 'Shop A' }),
    )

    const bps = await resolveCommissionRate(db, created.id)
    expect(bps).toBe(created.commissionBps)
  })

  it('resolve-rate-missing', async () => {
    const db = await freshDb()
    const missingId = '99999999-9999-4999-8999-999999999999'

    await expect(resolveCommissionRate(db, missingId)).rejects.toSatisfy((e) =>
      isVendorNotFoundError(e),
    )
    await expect(resolveCommissionRate(db, missingId)).rejects.toBeInstanceOf(VendorNotFoundError)
  })
})

describe('setVendorCommissionRate', () => {
  it('set-rate-admin-only', async () => {
    const db = await freshDb()
    const created = await db.transaction((tx) =>
      applyAsVendor(tx, { ownerUserId: USER_A, name: 'Shop A' }),
    )
    const before = created.commissionBps

    await expect(
      db.transaction((tx) => setVendorCommissionRate(tx, created.id, { userId: USER_A }, 500)),
    ).rejects.toSatisfy((e) => isVendorAuthorizationError(e))

    const [unchanged] = await db.select().from(vendor).where(eq(vendor.id, created.id))
    expect(unchanged?.commissionBps).toBe(before)

    await db.transaction((tx) => setVendorCommissionRate(tx, created.id, ADMIN, 500))

    const [updated] = await db.select().from(vendor).where(eq(vendor.id, created.id))
    expect(updated?.commissionBps).toBe(500)
  })

  it('set-rate-range', async () => {
    const db = await freshDb()
    const created = await db.transaction((tx) =>
      applyAsVendor(tx, { ownerUserId: USER_A, name: 'Shop A' }),
    )
    const before = created.commissionBps

    // -1/10001 out of range; 250.5/NaN reject the fractional/non-int that an
    // integer() column would otherwise truncate silently.
    for (const bps of [-1, 10001, 250.5, Number.NaN]) {
      await expect(
        db.transaction((tx) => setVendorCommissionRate(tx, created.id, ADMIN, bps)),
      ).rejects.toSatisfy((e) => isCommissionRateError(e))
      await expect(
        db.transaction((tx) => setVendorCommissionRate(tx, created.id, ADMIN, bps)),
      ).rejects.toBeInstanceOf(CommissionRateError)
    }

    const [unchanged] = await db.select().from(vendor).where(eq(vendor.id, created.id))
    expect(unchanged?.commissionBps).toBe(before)
  })
})
