import { describe, expect, it } from 'vitest'
import {
  VendorNotFoundError,
  VendorStateError,
  isVendorNotFoundError,
  isVendorStateError,
} from './errors.js'
import {
  assertVendorCanSell,
  assertVendorOwnership,
  requireVendorForActor,
} from './authz.js'
import { applyAsVendor, approveVendor, suspendVendor } from './vendor.js'
import { ADMIN, USER_A, USER_B, freshDb } from './test-helpers.js'

describe('requireVendorForActor', () => {
  it('require-vendor-for-actor', async () => {
    const db = await freshDb()
    const created = await db.transaction((tx) =>
      applyAsVendor(tx, { ownerUserId: USER_A, name: 'Shop A' }),
    )

    const vendor = await requireVendorForActor(db, { userId: USER_A })
    expect(vendor.id).toBe(created.id)
    expect(vendor.ownerUserId).toBe(USER_A)

    await expect(requireVendorForActor(db, { userId: USER_B })).rejects.toSatisfy((e) =>
      isVendorNotFoundError(e),
    )
    await expect(requireVendorForActor(db, {})).rejects.toSatisfy((e) =>
      isVendorNotFoundError(e),
    )
  })
})

describe('assertVendorOwnership', () => {
  it('assert-ownership-owner', async () => {
    const db = await freshDb()
    const created = await db.transaction((tx) =>
      applyAsVendor(tx, { ownerUserId: USER_A, name: 'Shop A' }),
    )

    await expect(
      assertVendorOwnership(db, { userId: USER_A }, created.id),
    ).resolves.toBeUndefined()
  })

  it('assert-ownership-cross', async () => {
    const db = await freshDb()
    const created = await db.transaction((tx) =>
      applyAsVendor(tx, { ownerUserId: USER_A, name: 'Shop A' }),
    )

    await expect(
      assertVendorOwnership(db, { userId: USER_B }, created.id),
    ).rejects.toSatisfy((e) => isVendorNotFoundError(e))
    await expect(
      assertVendorOwnership(db, { userId: USER_B }, created.id),
    ).rejects.toBeInstanceOf(VendorNotFoundError)
    await expect(
      assertVendorOwnership(db, { userId: USER_B }, created.id),
    ).rejects.toMatchObject({ httpStatus: 404 })
  })

  it('assert-ownership-admin', async () => {
    const db = await freshDb()
    const created = await db.transaction((tx) =>
      applyAsVendor(tx, { ownerUserId: USER_A, name: 'Shop A' }),
    )

    await expect(assertVendorOwnership(db, ADMIN, created.id)).resolves.toBeUndefined()
  })
})

describe('assertVendorCanSell', () => {
  it('can-sell-approved', async () => {
    const db = await freshDb()
    const created = await db.transaction((tx) =>
      applyAsVendor(tx, { ownerUserId: USER_A, name: 'Shop A' }),
    )
    await db.transaction((tx) => approveVendor(tx, created.id, ADMIN))

    await expect(assertVendorCanSell(db, created.id)).resolves.toBeUndefined()
  })

  it('can-sell-pending', async () => {
    const db = await freshDb()
    const created = await db.transaction((tx) =>
      applyAsVendor(tx, { ownerUserId: USER_A, name: 'Shop A' }),
    )

    await expect(assertVendorCanSell(db, created.id)).rejects.toSatisfy((e) =>
      isVendorStateError(e),
    )
    await expect(assertVendorCanSell(db, created.id)).rejects.toBeInstanceOf(VendorStateError)
  })

  it('can-sell-suspended', async () => {
    const db = await freshDb()
    const created = await db.transaction((tx) =>
      applyAsVendor(tx, { ownerUserId: USER_A, name: 'Shop A' }),
    )
    await db.transaction((tx) => suspendVendor(tx, created.id, ADMIN))

    await expect(assertVendorCanSell(db, created.id)).rejects.toSatisfy((e) =>
      isVendorStateError(e),
    )
  })
})
