import { beforeEach, describe, expect, it, vi } from 'vitest'

const selectOrderBy = vi.fn()
const insertValues = vi.fn()
const insertReturning = vi.fn()
const updateWhere = vi.fn()
const updateReturning = vi.fn()
const deleteWhere = vi.fn()
const deleteReturning = vi.fn()

const db = {
  select: vi.fn(() => ({
    from: vi.fn(() => ({
      where: vi.fn(() => ({
        orderBy: selectOrderBy,
      })),
    })),
  })),
  insert: vi.fn(() => ({
    values: insertValues,
  })),
  update: vi.fn(() => ({
    set: vi.fn(() => ({
      where: updateWhere,
    })),
  })),
  delete: vi.fn(() => ({
    where: deleteWhere,
  })),
}

describe('inventory location settings queries', () => {
  beforeEach(() => {
    vi.clearAllMocks()

    insertValues.mockReturnValue({
      returning: insertReturning,
    })
    updateWhere.mockReturnValue({
      returning: updateReturning,
    })
    deleteWhere.mockReturnValue({
      returning: deleteReturning,
    })
  })

  it('creates a default location by clearing sibling defaults first', async () => {
    updateReturning.mockResolvedValueOnce(undefined)
    insertReturning.mockResolvedValueOnce([
      {
        id: 'loc-2',
        name: 'Overflow',
        code: 'OVR',
        isDefault: true,
        isActive: true,
      },
    ])

    const { createInventoryLocation } = await import('../src/queries/settings-inventory')

    const created = await createInventoryLocation(db as never, 'tenant-1', {
      name: ' Overflow ',
      code: ' OVR ',
      isDefault: true,
    })

    expect(db.update).toHaveBeenCalledTimes(1)
    expect(db.insert).toHaveBeenCalledTimes(1)
    expect(insertValues).toHaveBeenCalledWith(
      expect.objectContaining({
        tenantId: 'tenant-1',
        name: 'Overflow',
        code: 'OVR',
        isDefault: true,
        isActive: true,
      }),
    )
    expect(created).toEqual({
      id: 'loc-2',
      name: 'Overflow',
      code: 'OVR',
      isDefault: true,
      isActive: true,
    })
  })

  it('updates a location and flips the default invariant', async () => {
    selectOrderBy.mockResolvedValueOnce([
      {
        id: 'loc-2',
        name: 'Overflow',
        code: 'OVR',
        isDefault: false,
        isActive: true,
      },
    ])
    selectOrderBy.mockResolvedValueOnce([
      {
        id: 'loc-2',
        name: 'Overflow shelf',
        code: 'OVR-2',
        isDefault: true,
        isActive: false,
      },
    ])
    updateReturning.mockResolvedValue([
      {
        id: 'loc-2',
        name: 'Overflow shelf',
        code: 'OVR-2',
        isDefault: true,
        isActive: false,
      },
    ])

    const { updateInventoryLocation } = await import('../src/queries/settings-inventory')

    const updated = await updateInventoryLocation(db as never, 'tenant-1', 'loc-2', {
      name: ' Overflow shelf ',
      code: ' OVR-2 ',
      isDefault: true,
      isActive: false,
    })

    expect(db.update).toHaveBeenCalledTimes(2)
    expect(updated).toEqual({
      id: 'loc-2',
      name: 'Overflow shelf',
      code: 'OVR-2',
      isDefault: true,
      isActive: false,
    })
  })

  it('rejects deleting the tenant default location', async () => {
    selectOrderBy.mockResolvedValueOnce([
      {
        id: 'loc-1',
        name: 'Main',
        code: 'MAIN',
        isDefault: true,
        isActive: true,
      },
    ])

    const { deleteInventoryLocation, InventoryLocationConflictError } = await import(
      '../src/queries/settings-inventory'
    )

    await expect(deleteInventoryLocation(db as never, 'tenant-1', 'loc-1')).rejects.toBeInstanceOf(
      InventoryLocationConflictError,
    )
    expect(db.delete).not.toHaveBeenCalled()
  })
})
