import { test, expect, APIRequestContext } from "@playwright/test"
import { ApiSeeder, newApiContext, Warehouse, Item, Vendor } from "../support/api"
import { StockTransferNewPage, StockTransferDetailPage } from "../pages/StockPages"

// Stock transfer flow (Backend/ERPCore/Controllers/StockTransfersController.cs, Frontend
// app/dashboard/stock/transfers/*): Draft -> Dispatch -> Receive, moving FIFO layers
// between warehouses.
test.describe("Stock transfers", () => {
  let api: APIRequestContext
  let seeder: ApiSeeder
  let srcWarehouse: Warehouse
  let destWarehouse: Warehouse
  let vendor: Vendor
  let item: Item

  test.beforeAll(async () => {
    api = await newApiContext()
    seeder = new ApiSeeder(api)
    srcWarehouse = await seeder.firstWarehouse()
    destWarehouse = await seeder.secondWarehouse()
    vendor = await seeder.createVendor()
    item = await seeder.createItem({ namePrefix: "Transfer Test Item" })

    await seeder.receiveStock({
      warehouseId: srcWarehouse.warehouseId,
      vendorId: vendor.vendorId,
      itemId: item.itemId,

      qty: 50,
      unitCost: 15,
    })
  })

  test.afterAll(async () => {
    await api.dispose()
  })

  test("create -> dispatch -> receive moves stock between warehouses", async ({ page }) => {
    const before = await seeder.stockOnHand(item.itemId, srcWarehouse.warehouseId)

    const newPage = new StockTransferNewPage(page)
    await newPage.goto()
    await newPage.fill({ fromWarehouse: srcWarehouse.name, toWarehouse: destWarehouse.name, item: item.name, qty: 10 })
    await newPage.submit()

    await expect(page).toHaveURL(/\/dashboard\/stock\/transfers\/\d+/)
    const detail = new StockTransferDetailPage(page)
    await detail.expectStatus("Draft")

    await detail.dispatch()
    await detail.expectStatus("InTransit")

    const afterDispatch = await seeder.stockOnHand(item.itemId, srcWarehouse.warehouseId)
    // Dispatch consumes the source FIFO layers immediately (Backend/ERPCore/Services/Stock/
    // StockService.cs: "Dispatch already consumed the source layers, so this stock has left
    // onHand") - inTransit is reported for visibility only, not held back from onHand.
    expect(afterDispatch.onHand).toBeCloseTo(before.onHand - 10, 4)

    await detail.receive()
    await detail.expectStatus("Received")

    const destAfter = await seeder.stockOnHand(item.itemId, destWarehouse.warehouseId)
    expect(destAfter.onHand).toBeGreaterThanOrEqual(10)
  })

  test("dispatch fails with insufficient stock and the transfer stays Draft", async ({ page }) => {
    const newPage = new StockTransferNewPage(page)
    await newPage.goto()
    await newPage.fill({
      fromWarehouse: srcWarehouse.name,
      toWarehouse: destWarehouse.name,
      item: item.name,
      qty: 999_999,
    })
    await newPage.submit()

    await expect(page).toHaveURL(/\/dashboard\/stock\/transfers\/\d+/)
    const detail = new StockTransferDetailPage(page)
    await detail.expectStatus("Draft")

    await detail.dispatch()

    // FifoCostingService rejects with 409 STOCK_NEGATIVE_BLOCKED - the frontend surfaces the
    // error and leaves the transfer in Draft rather than advancing it.
    await detail.expectStatus("Draft")
    await expect(page.getByRole("button", { name: /^dispatch$/i })).toBeVisible()
  })
})
