import { describe, expect, it } from "vitest";
import { planAccountPayableSystemHolds } from "./holdReconciliation";

const line = {
  id: "ap-line-1",
  purchaseOrderLineId: "po-line-1",
  quantity: "3",
  unitPrice: "100",
  unitId: "unit-1",
};

const purchaseOrderLine = {
  id: "po-line-1",
  purchaseOrderId: "po-1",
  quantity: "10",
  unitPrice: "100",
  unitId: "unit-1",
  requiresPhysicalReceipt: true,
};

describe("planAccountPayableSystemHolds", () => {
  it("returns no holds when invoice price and remaining quantities match", () => {
    const holds = planAccountPayableSystemHolds({
      lines: [line],
      purchaseOrderLines: [purchaseOrderLine],
      receiptQuantities: [{ purchaseOrderLineId: "po-line-1", receivedQuantity: "6" }],
      alreadyInvoicedQuantities: [{ purchaseOrderLineId: "po-line-1", quantity: "2" }],
    });

    expect(holds).toEqual([]);
  });

  it("creates a price variance hold when invoice unit price differs from the purchase order", () => {
    const holds = planAccountPayableSystemHolds({
      lines: [{ ...line, unitPrice: "105" }],
      purchaseOrderLines: [purchaseOrderLine],
      receiptQuantities: [{ purchaseOrderLineId: "po-line-1", receivedQuantity: "10" }],
      alreadyInvoicedQuantities: [],
    });

    expect(holds).toEqual([
      {
        accountPayableDocumentLineId: "ap-line-1",
        reasonCode: "INVOICE_UNIT_PRICE_DIFFERS_FROM_PURCHASE_ORDER_UNIT_PRICE",
      },
    ]);
  });

  it("does not create standard matching holds for correction lines", () => {
    const holds = planAccountPayableSystemHolds({
      lines: [{ ...line, unitPrice: "2", correctionType: "PRICE" }],
      purchaseOrderLines: [purchaseOrderLine],
      receiptQuantities: [{ purchaseOrderLineId: "po-line-1", receivedQuantity: "10" }],
      alreadyInvoicedQuantities: [],
    });

    expect(holds).toEqual([]);
  });

  it("does not create a price variance hold when unit price difference is within tolerance", () => {
    const holds = planAccountPayableSystemHolds({
      lines: [{ ...line, unitPrice: "105" }],
      purchaseOrderLines: [purchaseOrderLine],
      receiptQuantities: [{ purchaseOrderLineId: "po-line-1", receivedQuantity: "10" }],
      alreadyInvoicedQuantities: [],
      tolerance: {
        unitPrice: { percent: "0.05" },
      },
    });

    expect(holds).toEqual([]);
  });

  it("creates a unit variance hold when invoice unit differs from the purchase order", () => {
    const holds = planAccountPayableSystemHolds({
      lines: [{ ...line, unitId: "case-unit" }],
      purchaseOrderLines: [purchaseOrderLine],
      receiptQuantities: [{ purchaseOrderLineId: "po-line-1", receivedQuantity: "10" }],
      alreadyInvoicedQuantities: [],
    });

    expect(holds).toEqual([
      {
        accountPayableDocumentLineId: "ap-line-1",
        reasonCode: "INVOICE_UNIT_DIFFERS_FROM_PURCHASE_ORDER_UNIT",
      },
    ]);
  });

  it("creates an ordered quantity hold when invoice quantity exceeds remaining ordered quantity", () => {
    const holds = planAccountPayableSystemHolds({
      lines: [{ ...line, quantity: "3" }],
      purchaseOrderLines: [{ ...purchaseOrderLine, quantity: "10" }],
      receiptQuantities: [{ purchaseOrderLineId: "po-line-1", receivedQuantity: "10" }],
      alreadyInvoicedQuantities: [{ purchaseOrderLineId: "po-line-1", quantity: "8" }],
    });

    expect(holds).toEqual([
      {
        accountPayableDocumentLineId: "ap-line-1",
        reasonCode: "INVOICE_QUANTITY_EXCEEDS_ORDERED_QUANTITY",
      },
      {
        accountPayableDocumentLineId: "ap-line-1",
        reasonCode: "INVOICE_QUANTITY_EXCEEDS_RECEIVED_QUANTITY",
      },
    ]);
  });

  it("does not create an ordered quantity hold when overage is within quantity tolerance", () => {
    const holds = planAccountPayableSystemHolds({
      lines: [{ ...line, quantity: "3" }],
      purchaseOrderLines: [{ ...purchaseOrderLine, quantity: "10" }],
      receiptQuantities: [{ purchaseOrderLineId: "po-line-1", receivedQuantity: "10" }],
      alreadyInvoicedQuantities: [{ purchaseOrderLineId: "po-line-1", quantity: "8" }],
      tolerance: {
        quantity: { absolute: "1" },
      },
    });

    expect(holds).toEqual([]);
  });

  it("creates ordered quantity holds when combined invoice lines exceed remaining ordered quantity", () => {
    const holds = planAccountPayableSystemHolds({
      lines: [
        { ...line, id: "ap-line-1", quantity: "6" },
        { ...line, id: "ap-line-2", quantity: "6" },
      ],
      purchaseOrderLines: [{ ...purchaseOrderLine, quantity: "10" }],
      receiptQuantities: [{ purchaseOrderLineId: "po-line-1", receivedQuantity: "12" }],
      alreadyInvoicedQuantities: [],
    });

    expect(holds).toEqual([
      {
        accountPayableDocumentLineId: "ap-line-1",
        reasonCode: "INVOICE_QUANTITY_EXCEEDS_ORDERED_QUANTITY",
      },
      {
        accountPayableDocumentLineId: "ap-line-2",
        reasonCode: "INVOICE_QUANTITY_EXCEEDS_ORDERED_QUANTITY",
      },
    ]);
  });

  it("creates a received quantity hold when invoice quantity exceeds remaining received quantity", () => {
    const holds = planAccountPayableSystemHolds({
      lines: [{ ...line, quantity: "3" }],
      purchaseOrderLines: [{ ...purchaseOrderLine, quantity: "10" }],
      receiptQuantities: [{ purchaseOrderLineId: "po-line-1", receivedQuantity: "6" }],
      alreadyInvoicedQuantities: [{ purchaseOrderLineId: "po-line-1", quantity: "4" }],
    });

    expect(holds).toEqual([
      {
        accountPayableDocumentLineId: "ap-line-1",
        reasonCode: "INVOICE_QUANTITY_EXCEEDS_RECEIVED_QUANTITY",
      },
    ]);
  });

  it("does not create a received quantity hold when overage is within received quantity tolerance", () => {
    const holds = planAccountPayableSystemHolds({
      lines: [{ ...line, quantity: "3" }],
      purchaseOrderLines: [{ ...purchaseOrderLine, quantity: "10" }],
      receiptQuantities: [{ purchaseOrderLineId: "po-line-1", receivedQuantity: "6" }],
      alreadyInvoicedQuantities: [{ purchaseOrderLineId: "po-line-1", quantity: "4" }],
      tolerance: {
        quantity: { absolute: "1" },
      },
    });

    expect(holds).toEqual([]);
  });

  it("creates received quantity holds when combined invoice lines exceed remaining received quantity", () => {
    const holds = planAccountPayableSystemHolds({
      lines: [
        { ...line, id: "ap-line-1", quantity: "5" },
        { ...line, id: "ap-line-2", quantity: "5" },
      ],
      purchaseOrderLines: [{ ...purchaseOrderLine, quantity: "10" }],
      receiptQuantities: [{ purchaseOrderLineId: "po-line-1", receivedQuantity: "8" }],
      alreadyInvoicedQuantities: [],
    });

    expect(holds).toEqual([
      {
        accountPayableDocumentLineId: "ap-line-1",
        reasonCode: "INVOICE_QUANTITY_EXCEEDS_RECEIVED_QUANTITY",
      },
      {
        accountPayableDocumentLineId: "ap-line-2",
        reasonCode: "INVOICE_QUANTITY_EXCEEDS_RECEIVED_QUANTITY",
      },
    ]);
  });

  it("does not create a received quantity hold when physical receipt is not required", () => {
    const holds = planAccountPayableSystemHolds({
      lines: [{ ...line, quantity: "3" }],
      purchaseOrderLines: [{ ...purchaseOrderLine, requiresPhysicalReceipt: false }],
      receiptQuantities: [],
      alreadyInvoicedQuantities: [],
    });

    expect(holds).toEqual([]);
  });
});
