import { suite } from '../lib/context.js'

suite('Inventory', { tags: ['inventory'] }, (t) => {
  // ─── Categories ────────────────────────────────────────────────────────────

  t.test('creates a category', { tags: ['categories', 'create'] }, async () => {
    const res = await t.api.post('/v1/categories', { name: 'Violins', sortOrder: 1 })
    t.assert.status(res, 201)
    t.assert.equal(res.data.name, 'Violins')
    t.assert.equal(res.data.sortOrder, 1)
    t.assert.equal(res.data.isActive, true)
    t.assert.ok(res.data.id)
  })

  t.test('rejects category without name', { tags: ['categories', 'create', 'validation'] }, async () => {
    const res = await t.api.post('/v1/categories', {})
    t.assert.status(res, 400)
  })

  t.test('lists categories with pagination', { tags: ['categories', 'list'] }, async () => {
    await t.api.post('/v1/categories', { name: 'Cat List A' })
    await t.api.post('/v1/categories', { name: 'Cat List B' })
    const res = await t.api.get('/v1/categories', { page: 1, limit: 25 })
    t.assert.status(res, 200)
    t.assert.ok(res.data.data.length >= 2)
    t.assert.ok(res.data.pagination)
  })

  t.test('gets category by id', { tags: ['categories', 'read'] }, async () => {
    const created = await t.api.post('/v1/categories', { name: 'Get By ID Cat' })
    const res = await t.api.get(`/v1/categories/${created.data.id}`)
    t.assert.status(res, 200)
    t.assert.equal(res.data.name, 'Get By ID Cat')
  })

  t.test('returns 404 for missing category', { tags: ['categories', 'read'] }, async () => {
    const res = await t.api.get('/v1/categories/a0000000-0000-0000-0000-999999999999')
    t.assert.status(res, 404)
  })

  t.test('updates a category', { tags: ['categories', 'update'] }, async () => {
    const created = await t.api.post('/v1/categories', { name: 'Before Update' })
    const res = await t.api.patch(`/v1/categories/${created.data.id}`, { name: 'After Update', sortOrder: 5 })
    t.assert.status(res, 200)
    t.assert.equal(res.data.name, 'After Update')
    t.assert.equal(res.data.sortOrder, 5)
  })

  t.test('soft-deletes a category', { tags: ['categories', 'delete'] }, async () => {
    const created = await t.api.post('/v1/categories', { name: 'To Delete Cat' })
    const res = await t.api.del(`/v1/categories/${created.data.id}`)
    t.assert.status(res, 200)
    t.assert.equal(res.data.isActive, false)
  })

  // ─── Suppliers ─────────────────────────────────────────────────────────────

  t.test('creates a supplier', { tags: ['suppliers', 'create'] }, async () => {
    const res = await t.api.post('/v1/suppliers', {
      name: 'Shar Music',
      email: 'orders@sharmusic.com',
      phone: '800-248-7427',
      paymentTerms: 'Net 30',
    })
    t.assert.status(res, 201)
    t.assert.equal(res.data.name, 'Shar Music')
    t.assert.equal(res.data.paymentTerms, 'Net 30')
    t.assert.ok(res.data.id)
  })

  t.test('rejects supplier without name', { tags: ['suppliers', 'create', 'validation'] }, async () => {
    const res = await t.api.post('/v1/suppliers', { email: 'x@x.com' })
    t.assert.status(res, 400)
  })

  t.test('lists suppliers with pagination', { tags: ['suppliers', 'list'] }, async () => {
    await t.api.post('/v1/suppliers', { name: 'Sup List A' })
    await t.api.post('/v1/suppliers', { name: 'Sup List B' })
    const res = await t.api.get('/v1/suppliers', { page: 1, limit: 25 })
    t.assert.status(res, 200)
    t.assert.ok(res.data.data.length >= 2)
    t.assert.ok(res.data.pagination.total >= 2)
  })

  t.test('searches suppliers by name', { tags: ['suppliers', 'list', 'search'] }, async () => {
    await t.api.post('/v1/suppliers', { name: 'SearchableSupplierXYZ' })
    const res = await t.api.get('/v1/suppliers', { q: 'SearchableSupplierXYZ' })
    t.assert.status(res, 200)
    t.assert.equal(res.data.data.length, 1)
    t.assert.equal(res.data.data[0].name, 'SearchableSupplierXYZ')
  })

  t.test('updates a supplier', { tags: ['suppliers', 'update'] }, async () => {
    const created = await t.api.post('/v1/suppliers', { name: 'Old Supplier Name' })
    const res = await t.api.patch(`/v1/suppliers/${created.data.id}`, { name: 'New Supplier Name', accountNumber: 'ACC-001' })
    t.assert.status(res, 200)
    t.assert.equal(res.data.name, 'New Supplier Name')
    t.assert.equal(res.data.accountNumber, 'ACC-001')
  })

  t.test('soft-deletes a supplier', { tags: ['suppliers', 'delete'] }, async () => {
    const created = await t.api.post('/v1/suppliers', { name: 'To Delete Sup' })
    const res = await t.api.del(`/v1/suppliers/${created.data.id}`)
    t.assert.status(res, 200)
    t.assert.equal(res.data.isActive, false)
  })

  // ─── Products ──────────────────────────────────────────────────────────────

  t.test('creates a product', { tags: ['products', 'create'] }, async () => {
    const res = await t.api.post('/v1/products', {
      name: 'Violin 4/4 Student',
      sku: 'VLN-44-TST',
      brand: 'Eastman',
      price: 399,
      isSerialized: true,
      isRental: true,
      isActive: true,
    })
    t.assert.status(res, 201)
    t.assert.equal(res.data.name, 'Violin 4/4 Student')
    t.assert.equal(res.data.sku, 'VLN-44-TST')
    t.assert.equal(res.data.price, '399.00')
    t.assert.equal(res.data.isSerialized, true)
    t.assert.ok(res.data.id)
  })

  t.test('rejects product without name', { tags: ['products', 'create', 'validation'] }, async () => {
    const res = await t.api.post('/v1/products', { sku: 'NO-NAME' })
    t.assert.status(res, 400)
  })

  t.test('lists products with pagination', { tags: ['products', 'list'] }, async () => {
    await t.api.post('/v1/products', { name: 'Prod List A', price: 100 })
    await t.api.post('/v1/products', { name: 'Prod List B', price: 200 })
    const res = await t.api.get('/v1/products', { page: 1, limit: 25 })
    t.assert.status(res, 200)
    t.assert.ok(res.data.data.length >= 2)
    t.assert.ok(res.data.pagination)
  })

  t.test('searches products by name', { tags: ['products', 'list', 'search'] }, async () => {
    await t.api.post('/v1/products', { name: 'SearchableViolinXYZ' })
    const res = await t.api.get('/v1/products', { q: 'SearchableViolinXYZ' })
    t.assert.status(res, 200)
    t.assert.equal(res.data.data.length, 1)
    t.assert.equal(res.data.data[0].name, 'SearchableViolinXYZ')
  })

  t.test('filters products by categoryId', { tags: ['products', 'list', 'filter'] }, async () => {
    const cat = await t.api.post('/v1/categories', { name: 'FilterCat' })
    await t.api.post('/v1/products', { name: 'In Cat Prod', categoryId: cat.data.id })
    await t.api.post('/v1/products', { name: 'No Cat Prod' })
    const res = await t.api.get('/v1/products', { categoryId: cat.data.id })
    t.assert.status(res, 200)
    t.assert.ok(res.data.data.every((p: any) => p.categoryId === cat.data.id))
  })

  t.test('gets product by id', { tags: ['products', 'read'] }, async () => {
    const created = await t.api.post('/v1/products', { name: 'Get By ID Prod' })
    const res = await t.api.get(`/v1/products/${created.data.id}`)
    t.assert.status(res, 200)
    t.assert.equal(res.data.name, 'Get By ID Prod')
  })

  t.test('returns 404 for missing product', { tags: ['products', 'read'] }, async () => {
    const res = await t.api.get('/v1/products/a0000000-0000-0000-0000-999999999999')
    t.assert.status(res, 404)
  })

  t.test('updates a product and records price history', { tags: ['products', 'update', 'price-history'] }, async () => {
    const created = await t.api.post('/v1/products', { name: 'Price Test Prod', price: 100 })
    const res = await t.api.patch(`/v1/products/${created.data.id}`, { price: 150, name: 'Price Test Prod Updated' })
    t.assert.status(res, 200)
    t.assert.equal(res.data.price, '150.00')
    const history = await t.api.get(`/v1/products/${created.data.id}/price-history`)
    t.assert.status(history, 200)
    t.assert.equal(history.data.data.length, 1)
    t.assert.equal(history.data.data[0].previousPrice, '100.00')
    t.assert.equal(history.data.data[0].newPrice, '150.00')
  })

  t.test('price history is empty for new product', { tags: ['products', 'price-history'] }, async () => {
    const created = await t.api.post('/v1/products', { name: 'No History Prod', price: 50 })
    const res = await t.api.get(`/v1/products/${created.data.id}/price-history`)
    t.assert.status(res, 200)
    t.assert.equal(res.data.data.length, 0)
  })

  t.test('soft-deletes a product', { tags: ['products', 'delete'] }, async () => {
    const created = await t.api.post('/v1/products', { name: 'To Delete Prod' })
    const res = await t.api.del(`/v1/products/${created.data.id}`)
    t.assert.status(res, 200)
    t.assert.equal(res.data.isActive, false)
  })

  // ─── Inventory Units ───────────────────────────────────────────────────────

  t.test('creates a serialized unit', { tags: ['units', 'create'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Serial Prod', isSerialized: true })
    const res = await t.api.post(`/v1/products/${prod.data.id}/units`, {
      serialNumber: 'SN-001',
      condition: 'new',
      status: 'available',
      purchaseCost: 185,
    })
    t.assert.status(res, 201)
    t.assert.equal(res.data.serialNumber, 'SN-001')
    t.assert.equal(res.data.condition, 'new')
    t.assert.equal(res.data.status, 'available')
    t.assert.equal(res.data.purchaseCost, '185.00')
  })

  t.test('lists units for a product', { tags: ['units', 'list'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Multi Unit Prod', isSerialized: true })
    await t.api.post(`/v1/products/${prod.data.id}/units`, { serialNumber: 'SN-A', condition: 'new', status: 'available' })
    await t.api.post(`/v1/products/${prod.data.id}/units`, { serialNumber: 'SN-B', condition: 'good', status: 'rented' })
    const res = await t.api.get(`/v1/products/${prod.data.id}/units`)
    t.assert.status(res, 200)
    t.assert.equal(res.data.data.length, 2)
  })

  t.test('updates a unit status', { tags: ['units', 'update'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Update Unit Prod', isSerialized: true })
    const unit = await t.api.post(`/v1/products/${prod.data.id}/units`, { serialNumber: 'SN-UPD', condition: 'good', status: 'available' })
    const res = await t.api.patch(`/v1/units/${unit.data.id}`, { status: 'rented', notes: 'Rented to customer A' })
    t.assert.status(res, 200)
    t.assert.equal(res.data.status, 'rented')
    t.assert.equal(res.data.notes, 'Rented to customer A')
  })

  // ─── Product Suppliers ─────────────────────────────────────────────────────

  t.test('links a supplier to a product', { tags: ['product-suppliers', 'create'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Linkable Prod' })
    const sup = await t.api.post('/v1/suppliers', { name: 'Link Supplier' })
    const res = await t.api.post(`/v1/products/${prod.data.id}/suppliers`, {
      supplierId: sup.data.id,
      supplierSku: 'SUP-SKU-001',
      isPreferred: true,
    })
    t.assert.status(res, 201)
    t.assert.equal(res.data.supplierId, sup.data.id)
    t.assert.equal(res.data.supplierSku, 'SUP-SKU-001')
    t.assert.equal(res.data.isPreferred, true)
  })

  t.test('lists suppliers for a product with joined supplier details', { tags: ['product-suppliers', 'list'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Supplier List Prod' })
    const sup1 = await t.api.post('/v1/suppliers', { name: 'Supplier Alpha', paymentTerms: 'Net 30' })
    const sup2 = await t.api.post('/v1/suppliers', { name: 'Supplier Beta' })
    await t.api.post(`/v1/products/${prod.data.id}/suppliers`, { supplierId: sup1.data.id, isPreferred: true })
    await t.api.post(`/v1/products/${prod.data.id}/suppliers`, { supplierId: sup2.data.id, isPreferred: false })
    const res = await t.api.get(`/v1/products/${prod.data.id}/suppliers`)
    t.assert.status(res, 200)
    t.assert.equal(res.data.data.length, 2)
    // preferred comes first
    t.assert.equal(res.data.data[0].supplierName, 'Supplier Alpha')
    t.assert.equal(res.data.data[0].isPreferred, true)
    t.assert.equal(res.data.data[0].supplierPaymentTerms, 'Net 30')
    t.assert.equal(res.data.data[1].supplierName, 'Supplier Beta')
  })

  t.test('preferred flag moves to new supplier when set', { tags: ['product-suppliers', 'preferred'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Preferred Test Prod' })
    const sup1 = await t.api.post('/v1/suppliers', { name: 'Pref Sup A' })
    const sup2 = await t.api.post('/v1/suppliers', { name: 'Pref Sup B' })
    const link1 = await t.api.post(`/v1/products/${prod.data.id}/suppliers`, { supplierId: sup1.data.id, isPreferred: true })
    t.assert.equal(link1.data.isPreferred, true)
    // Link second supplier as preferred — first should lose preferred status
    await t.api.post(`/v1/products/${prod.data.id}/suppliers`, { supplierId: sup2.data.id, isPreferred: true })
    const list = await t.api.get(`/v1/products/${prod.data.id}/suppliers`)
    const a = list.data.data.find((s: any) => s.supplierId === sup1.data.id)
    const b = list.data.data.find((s: any) => s.supplierId === sup2.data.id)
    t.assert.equal(a.isPreferred, false)
    t.assert.equal(b.isPreferred, true)
  })

  t.test('updates a product-supplier link', { tags: ['product-suppliers', 'update'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Update Link Prod' })
    const sup = await t.api.post('/v1/suppliers', { name: 'Update Link Sup' })
    const link = await t.api.post(`/v1/products/${prod.data.id}/suppliers`, { supplierId: sup.data.id, supplierSku: 'OLD-SKU' })
    const res = await t.api.patch(`/v1/products/${prod.data.id}/suppliers/${link.data.id}`, { supplierSku: 'NEW-SKU' })
    t.assert.status(res, 200)
    t.assert.equal(res.data.supplierSku, 'NEW-SKU')
  })

  t.test('removes a supplier link', { tags: ['product-suppliers', 'delete'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Remove Link Prod' })
    const sup = await t.api.post('/v1/suppliers', { name: 'Remove Link Sup' })
    const link = await t.api.post(`/v1/products/${prod.data.id}/suppliers`, { supplierId: sup.data.id })
    const res = await t.api.del(`/v1/products/${prod.data.id}/suppliers/${link.data.id}`)
    t.assert.status(res, 200)
    const list = await t.api.get(`/v1/products/${prod.data.id}/suppliers`)
    t.assert.equal(list.data.data.length, 0)
  })

  t.test('returns 404 for missing product-supplier link update', { tags: ['product-suppliers', 'update'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Missing Link Prod' })
    const res = await t.api.patch(`/v1/products/${prod.data.id}/suppliers/a0000000-0000-0000-0000-999999999999`, { supplierSku: 'X' })
    t.assert.status(res, 404)
  })

  // ─── Stock Receipts ────────────────────────────────────────────────────────

  t.test('records a stock receipt and increments qty_on_hand', { tags: ['stock-receipts', 'create'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Rosin Stock', qtyOnHand: 10 })
    const res = await t.api.post(`/v1/products/${prod.data.id}/stock-receipts`, {
      qty: 5,
      costPerUnit: 6.50,
      receivedDate: '2026-03-15',
      invoiceNumber: 'INV-2026-001',
    })
    t.assert.status(res, 201)
    t.assert.equal(res.data.qty, 5)
    t.assert.equal(res.data.costPerUnit, '6.50')
    t.assert.equal(res.data.totalCost, '32.50')
    t.assert.equal(res.data.invoiceNumber, 'INV-2026-001')
    // qty_on_hand should have increased
    const updated = await t.api.get(`/v1/products/${prod.data.id}`)
    t.assert.equal(updated.data.qtyOnHand, 15)
  })

  t.test('records receipt with supplier link', { tags: ['stock-receipts', 'create'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Strings Stock' })
    const sup = await t.api.post('/v1/suppliers', { name: 'Receipt Supplier' })
    const res = await t.api.post(`/v1/products/${prod.data.id}/stock-receipts`, {
      supplierId: sup.data.id,
      qty: 12,
      costPerUnit: 19.50,
      receivedDate: '2026-03-20',
    })
    t.assert.status(res, 201)
    t.assert.equal(res.data.supplierId, sup.data.id)
  })

  t.test('does not increment qty for serialized products', { tags: ['stock-receipts', 'create'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Serial Stock', isSerialized: true, qtyOnHand: 0 })
    await t.api.post(`/v1/products/${prod.data.id}/stock-receipts`, {
      qty: 1,
      costPerUnit: 185,
      receivedDate: '2026-03-01',
    })
    const updated = await t.api.get(`/v1/products/${prod.data.id}`)
    t.assert.equal(updated.data.qtyOnHand, 0)
  })

  t.test('lists stock receipts for a product', { tags: ['stock-receipts', 'list'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'List Receipts Prod' })
    await t.api.post(`/v1/products/${prod.data.id}/stock-receipts`, { qty: 10, costPerUnit: 5, receivedDate: '2026-01-10' })
    await t.api.post(`/v1/products/${prod.data.id}/stock-receipts`, { qty: 20, costPerUnit: 4.75, receivedDate: '2026-02-15' })
    const res = await t.api.get(`/v1/products/${prod.data.id}/stock-receipts`)
    t.assert.status(res, 200)
    t.assert.equal(res.data.data.length, 2)
    // most recent date first
    t.assert.equal(res.data.data[0].receivedDate, '2026-02-15')
  })

  t.test('rejects receipt with missing required fields', { tags: ['stock-receipts', 'validation'] }, async () => {
    const prod = await t.api.post('/v1/products', { name: 'Invalid Receipt Prod' })
    const res = await t.api.post(`/v1/products/${prod.data.id}/stock-receipts`, { qty: 5 })
    t.assert.status(res, 400)
  })
})
