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

// Full cross-module lifecycle: GRN receipt -> Production consumes the received stock and
// produces a finished good -> Stock Transfer moves the finished good to a second warehouse.
// All four modules post to the same StockLayer/StockLedger tables (docs/10 C.9), so this is
// the scenario most likely to catch a regression in one module's ledger posting breaking
// another's downstream read - the thing the per-module suites (grn.spec.ts,
// production.spec.ts, stock-transfers.spec.ts) can't see in isolation.
test.describe("Chained flow: GRN -> Production -> Stock Transfer", () => {
  let api: APIRequestContext
  let seeder: ApiSeeder
  let sourceWarehouse: Warehouse
  let destWarehouse: Warehouse
  let vendor: Vendor
  let rawItem: Item
  let finishedItem: Item
  let templateName: string

  test.beforeAll(async () => {
    api = await newApiContext()
    seeder = new ApiSeeder(api)
    sourceWarehouse = await seeder.firstWarehouse()
    destWarehouse = await seeder.secondWarehouse()
    vendor = await seeder.createVendor("Chained Flow Vendor")
    rawItem = await seeder.createItem({ namePrefix: "Chained Raw Material" })
    finishedItem = await seeder.createItem({ namePrefix: "Chained Finished Good" })

    const template = await seeder.createSingleStageTemplate({
      rawItemId: rawItem.itemId,
      finishedItemId: finishedItem.itemId,

    })
    templateName = template.name
  })

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

  test("receive raw material, run production, transfer the finished good", async ({ page }) => {
    // --- 1. GRN: receive the raw material into the source warehouse -----------------
    const grnNew = new GrnNewPage(page)
    await grnNew.goto()
    await grnNew.useDirectReceipt()
    await grnNew.selectVendor(vendor.name)
    await grnNew.selectWarehouse(sourceWarehouse.name)
    await grnNew.fillFirstLine({ item: rawItem.name, qty: 100, unitCost: 20 })
    await grnNew.submit()

    await expect(page).toHaveURL(/\/dashboard\/receiving\/grn\/\d+/)
    const grnDetail = new GrnDetailPage(page)
    await grnDetail.expectStatus("Draft")
    await grnDetail.confirm()
    await grnDetail.expectStatus("Confirmed")

    const rawAfterGrn = await seeder.stockOnHand(rawItem.itemId, sourceWarehouse.warehouseId)
    expect(rawAfterGrn.onHand).toBeCloseTo(100, 4)

    // --- 2. Production: consume the raw material, produce the finished good ---------
    const runList = new ProductionRunListPage(page)
    await runList.goto()
    await runList.startRun({ template: templateName, targetQty: 20, warehouse: sourceWarehouse.name })

    await expect(page).toHaveURL(/\/dashboard\/production\/runs\/\d+/)
    const runDetail = new ProductionRunDetailPage(page)
    await runDetail.expectStatus(/in progress/i)

    await runDetail.openStage("Assemble")
    await runDetail.saveQuantities()
    await runDetail.startStage()

    const rawAfterStart = await seeder.stockOnHand(rawItem.itemId, sourceWarehouse.warehouseId)
    expect(rawAfterStart.onHand).toBeLessThan(rawAfterGrn.onHand)

    await runDetail.completeStage({ producedQty: 20 })
    await runDetail.approveAndReceive()

    const finishedAfterRun = await seeder.stockOnHand(finishedItem.itemId, sourceWarehouse.warehouseId)
    expect(finishedAfterRun.onHand).toBeCloseTo(20, 4)

    // --- 3. Stock Transfer: move the finished good to a second warehouse ------------
    const transferNew = new StockTransferNewPage(page)
    await transferNew.goto()
    await transferNew.fill({
      fromWarehouse: sourceWarehouse.name,
      toWarehouse: destWarehouse.name,
      item: finishedItem.name,
      qty: 20,
    })
    await transferNew.submit()

    await expect(page).toHaveURL(/\/dashboard\/stock\/transfers\/\d+/)
    const transferDetail = new StockTransferDetailPage(page)
    await transferDetail.expectStatus("Draft")
    await transferDetail.dispatch()
    await transferDetail.expectStatus("InTransit")
    await transferDetail.receive()
    await transferDetail.expectStatus("Received")

    // --- 4. Final assertions across the whole chain ----------------------------------
    const finishedAtSource = await seeder.stockOnHand(finishedItem.itemId, sourceWarehouse.warehouseId)
    const finishedAtDest = await seeder.stockOnHand(finishedItem.itemId, destWarehouse.warehouseId)
    expect(finishedAtSource.onHand).toBeCloseTo(0, 4)
    expect(finishedAtDest.onHand).toBeCloseTo(20, 4)
  })
})
