import { DataAccessError } from "@isa/common/data-access";
import { Receipt, ReceiptItem } from "../../models";
import {
  CreateReturnProcessError,
  CreateReturnProcessErrorReason,
  CreateReturnProcessErrorMessages,
} from "./create-return-process.error";
import { ProductCategory } from "../../questions";

describe("CreateReturnProcessError", () => {
  const params = {
    processId: 123,
    returns: [
      {
        receipt: { id: 321 } as Receipt,
        items: [
          // Provide at least one valid item object, or an empty array if testing "no items"
          // For NO_RETURNABLE_ITEMS, an empty array is valid, but must match the expected shape
          // So, keep as [], but type is now correct
        ],
      },
    ],
  };

  // For tests that require items, use the correct shape:
  const validParams = {
    processId: 123,
    returns: [
      {
        receipt: { id: 321 } as Receipt,
        items: [
          {
            receiptItem: { id: 111 } as ReceiptItem,
            quantity: 1,
            category: "A" as ProductCategory,
          },
        ],
      },
    ],
  };

  it("should create an error instance with NO_RETURNABLE_ITEMS reason", () => {
    // Arrange, Act
    const error = new CreateReturnProcessError(
      CreateReturnProcessErrorReason.NO_RETURNABLE_ITEMS,
      params,
    );
    // Assert
    expect(error).toBeInstanceOf(CreateReturnProcessError);
    expect(error).toBeInstanceOf(DataAccessError);
    expect(error.reason).toBe(
      CreateReturnProcessErrorReason.NO_RETURNABLE_ITEMS,
    );
    expect(error.params).toEqual(params);
    expect(error.message).toBe(
      CreateReturnProcessErrorMessages[
        CreateReturnProcessErrorReason.NO_RETURNABLE_ITEMS
      ],
    );
    expect(error.code).toBe("CREATE_RETURN_PROCESS");
  });

  it("should create an error instance with MISMATCH_RETURNABLE_ITEMS reason", () => {
    // Arrange, Act
    const error = new CreateReturnProcessError(
      CreateReturnProcessErrorReason.MISMATCH_RETURNABLE_ITEMS,
      validParams,
    );
    // Assert
    expect(error).toBeInstanceOf(CreateReturnProcessError);
    expect(error).toBeInstanceOf(DataAccessError);
    expect(error.reason).toBe(
      CreateReturnProcessErrorReason.MISMATCH_RETURNABLE_ITEMS,
    );
    expect(error.params).toEqual(validParams);
    expect(error.message).toBe(
      CreateReturnProcessErrorMessages[
        CreateReturnProcessErrorReason.MISMATCH_RETURNABLE_ITEMS
      ],
    );
    expect(error.code).toBe("CREATE_RETURN_PROCESS");
  });

  it("should expose the correct params structure", () => {
    const error = new CreateReturnProcessError(
      CreateReturnProcessErrorReason.NO_RETURNABLE_ITEMS,
      params,
    );
    expect(error.params).toHaveProperty("processId", 123);
    expect(error.params).toHaveProperty("returns");
    expect(Array.isArray(error.params.returns)).toBe(true);
    expect(error.params.returns[0]).toHaveProperty("receipt");
    expect(error.params.returns[0]).toHaveProperty("items");
  });

  it("should throw and be catchable as CreateReturnProcessError", () => {
    try {
      throw new CreateReturnProcessError(
        CreateReturnProcessErrorReason.NO_RETURNABLE_ITEMS,
        params,
      );
    } catch (err) {
      expect(err).toBeInstanceOf(CreateReturnProcessError);
      expect((err as CreateReturnProcessError).reason).toBe(
        CreateReturnProcessErrorReason.NO_RETURNABLE_ITEMS,
      );
    }
  });

  it("should use the correct message for each reason", () => {
    Object.values(CreateReturnProcessErrorReason).forEach((reason) => {
      const error = new CreateReturnProcessError(reason, params);
      expect(error.message).toBe(CreateReturnProcessErrorMessages[reason]);
    });
  });

  it('should have code "CREATE_RETURN_PROCESS" for all reasons', () => {
    Object.values(CreateReturnProcessErrorReason).forEach((reason) => {
      const error = new CreateReturnProcessError(reason, params);
      expect(error.code).toBe("CREATE_RETURN_PROCESS");
    });
  });

  it("should support params with multiple returns and items", () => {
    const extendedParams = {
      processId: 999,
      returns: [
        {
          receipt: { id: 1 } as Receipt,
          items: [
            {
              receiptItem: { id: 10 } as ReceiptItem,
              quantity: 2,
              category: "A" as ProductCategory,
            },
          ],
        },
        {
          receipt: { id: 2 } as Receipt,
          items: [
            {
              receiptItem: { id: 20 } as ReceiptItem,
              quantity: 1,
              category: "B" as ProductCategory,
            },
          ],
        },
      ],
    };
    const error = new CreateReturnProcessError(
      CreateReturnProcessErrorReason.MISMATCH_RETURNABLE_ITEMS,
      extendedParams,
    );
    expect(error.params.processId).toBe(999);
    expect(error.params.returns.length).toBe(2);
    expect(error.params.returns[0].items[0].quantity).toBe(2);
    expect(error.params.returns[1].items[0].category).toBe("B");
  });
});
