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

// GRN receiving flow (Backend/ERPCore/Controllers/GrnsController.cs, Frontend
// app/dashboard/receiving/grn/*). Covers direct + against-PO receipts, confirm posting to
// the stock ledger, and per-line hold-status actions.
test.describe("GRN", () => {
  let api: APIRequestContext
  let seeder: ApiSeeder
  let warehouse: Warehouse
  let vendor: Vendor
  let item: Item

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

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

  test("direct receipt creates a Draft GRN, confirm posts stock", async ({ page }) => {
    const grnNew = new GrnNewPage(page)
    await grnNew.goto()
    await grnNew.useDirectReceipt()
    await grnNew.selectVendor(vendor.name)
    await grnNew.selectWarehouse(warehouse.name)
    await grnNew.fillFirstLine({ item: item.name, qty: 10, unitCost: 50 })
    await grnNew.submit()

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

    const before = await seeder.stockOnHand(item.itemId, warehouse.warehouseId)

    await grnDetail.confirm()
    await grnDetail.expectStatus("Confirmed")

    const after = await seeder.stockOnHand(item.itemId, warehouse.warehouseId)
    expect(after.onHand).toBeCloseTo(before.onHand + 10, 4)
  })

  test("against-PO receipt pre-fills vendor/warehouse from the PO", async ({ page }) => {
    const po = await seeder.createPurchaseOrder({
      vendorId: vendor.vendorId,
      warehouseId: warehouse.warehouseId,
      itemId: item.itemId,

      qty: 5,
      unitPrice: 40,
    })

    const grnNew = new GrnNewPage(page)
    await grnNew.goto()
    await grnNew.useAgainstPo()
    await grnNew.selectPurchaseOrder(po.docNo)
    await grnNew.fillFirstLine({ item: item.name, qty: 5 })
    await grnNew.submit()

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

  test("rejecting a Draft GRN's blocked submit (missing warehouse) keeps the user on the form", async ({ page }) => {
    const grnNew = new GrnNewPage(page)
    await grnNew.goto()
    await grnNew.useDirectReceipt()
    await grnNew.selectVendor(vendor.name)
    // Warehouse intentionally left unselected.
    await grnNew.fillFirstLine({ item: item.name, qty: 1, unitCost: 10 })
    await grnNew.submit()

    await expect(page).toHaveURL(/\/dashboard\/receiving\/grn\/new/)
  })

  test("releasing an on-hold line clears the hold and makes stock available", async ({ page }) => {
    const grn = await seeder.receiveStockOnHold({
      warehouseId: warehouse.warehouseId,
      vendorId: vendor.vendorId,
      itemId: item.itemId,

      qty: 8,
      unitCost: 12,
    })

    const grnDetail = new GrnDetailPage(page)
    await grnDetail.gotoById(grn.grnId)
    await grnDetail.expectStatus("Confirmed")

    const before = await seeder.stockOnHand(item.itemId, warehouse.warehouseId)
    expect(before.available).toBeLessThan(before.onHand) // held stock is on-hand but not available

    await grnDetail.releaseFirstOnHoldLine()

    const after = await seeder.stockOnHand(item.itemId, warehouse.warehouseId)
    expect(after.available).toBeCloseTo(before.available + 8, 4)
  })

  test("rejecting an on-hold line surfaces a Create Return link", async ({ page }) => {
    const grn = await seeder.receiveStockOnHold({
      warehouseId: warehouse.warehouseId,
      vendorId: vendor.vendorId,
      itemId: item.itemId,

      qty: 3,
      unitCost: 12,
    })

    const grnDetail = new GrnDetailPage(page)
    await grnDetail.gotoById(grn.grnId)
    await grnDetail.expectStatus("Confirmed")

    await grnDetail.rejectFirstOnHoldLine()
    await grnDetail.expectCreateReturnLink()
  })
})
