/**
 * Copyright Super iPaaS Integration LLC, an IBM Company 2024
 */
import { getRefsFromAsset } from "./asset-handler.js";
import { BaseAsset } from "../model/assets-model.js";
import { KindEnums } from "@apic/api-model/common/StudioEnums.js";
import { getRefsFromApiAsset } from "./api-asset-handler.js";
import { getRefsFromPolicySeqAsset } from "../helpers/apim/asset-kinds/policy-seq-kind-helper.js";
import { getRefsFromRouteAsset } from "../helpers/apim/asset-kinds/route-kind-helper.js";
import { getRefsFromTestAsset } from "../helpers/apim/asset-kinds/test-kind-helper.js";
import { AssetCacheModel } from "../model/asset-cache-model.js";
import { getRefsFromMockEndpointAsset } from "../helpers/apim/asset-kinds/mockEndpoint-kind-helper.js";

jest.mock("../handlers/api-asset-handler.js", () => ({
  getRefsFromApiAsset: jest.fn(),
}));
jest.mock("../helpers/common/message-helper.js", () => ({
  showWarning: jest.fn(),
}));
jest.mock("../helpers/apim/asset-kinds/policy-seq-kind-helper.js", () => ({
  getRefsFromPolicySeqAsset: jest.fn(),
}));

jest.mock("../helpers/apim/asset-kinds/route-kind-helper.js", () => ({
  getRefsFromRouteAsset: jest.fn(),
}));

jest.mock("../helpers/apim/asset-kinds/test-kind-helper.js", () => ({
  getRefsFromTestAsset: jest.fn(),
}));

jest.mock("../helpers/apim/asset-kinds/mockEndpoint-kind-helper.js", () => ({
  getRefsFromMockEndpointAsset: jest.fn(),
}));

describe("Asset handler function test suite", () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  it("should handle API asset type", () => {
    const asset: BaseAsset = { kind: KindEnums.API } as BaseAsset;
    const expectedOutput: AssetCacheModel[] = [
      { kind: "API", ref: "someRef", isNewlyAdded: true },
    ];
    (getRefsFromApiAsset as jest.Mock).mockReturnValue(expectedOutput);

    const result = getRefsFromAsset(asset);

    expect(result).toEqual(expectedOutput);
    expect(getRefsFromApiAsset).toHaveBeenCalledWith(asset);
    expect(getRefsFromPolicySeqAsset).not.toHaveBeenCalled();
    expect(getRefsFromRouteAsset).not.toHaveBeenCalled();
    expect(getRefsFromTestAsset).not.toHaveBeenCalled();
  });

  it("should handle PolicySeq asset type", () => {
    const asset: BaseAsset = { kind: KindEnums.PolicySequence } as BaseAsset;
    const expectedOutput: AssetCacheModel[] = [
      { kind: "PolicySequence", ref: "someRef", isNewlyAdded: true },
    ];
    (getRefsFromPolicySeqAsset as jest.Mock).mockReturnValue(expectedOutput);

    const result = getRefsFromAsset(asset);

    expect(result).toEqual(expectedOutput);
    expect(getRefsFromPolicySeqAsset).toHaveBeenCalledWith(asset);
    expect(getRefsFromApiAsset).not.toHaveBeenCalled();
    expect(getRefsFromRouteAsset).not.toHaveBeenCalled();
    expect(getRefsFromTestAsset).not.toHaveBeenCalled();
  });
  it("should handle Route asset type", () => {
    const routeAsset: BaseAsset = {
      kind: KindEnums.Route,
      spec: {
        "default-endpoint": { $ref: "path/to/default-endpoint" },
      },
    } as unknown as BaseAsset;
    const expectedRefs: AssetCacheModel[] = [
      { kind: "Endpoint", ref: "path/to/default-endpoint", isNewlyAdded: true },
    ];
    (getRefsFromRouteAsset as jest.Mock).mockReturnValue(expectedRefs);
    const result = getRefsFromAsset(routeAsset);
    expect(getRefsFromRouteAsset).toHaveBeenCalledWith(routeAsset);
    expect(result).toEqual(expectedRefs);
    expect(getRefsFromApiAsset).not.toHaveBeenCalled();
    expect(getRefsFromPolicySeqAsset).not.toHaveBeenCalled();
    expect(getRefsFromTestAsset).not.toHaveBeenCalled();
  });
  it("should handle Test asset type", () => {
    const testAsset: BaseAsset = {
      kind: KindEnums.Test,
      spec: {
        environment: { $ref: "dev:env-ref:1.0" },
      },
    } as unknown as BaseAsset;
    const expectedRefs: AssetCacheModel[] = [
      { kind: "Environment", ref: "dev:env-ref:1.0", isNewlyAdded: true },
    ];
    (getRefsFromTestAsset as jest.Mock).mockReturnValue(expectedRefs);
    const result = getRefsFromAsset(testAsset);
    expect(getRefsFromTestAsset).toHaveBeenCalledWith(testAsset);
    expect(result).toEqual(expectedRefs);
  });

  it("should handle MockEndpoint asset type", () => {
    const mockEndpointAsset: BaseAsset = {
      kind: KindEnums.MockEndpoint,
      spec: {
        config: [
          {
            condition: "($request.path equals v2/pet and $request.method equals GET and $request.query.<key1> equals 'test')",
            response: { $ref: "sample:api_response:2.0" },
          },
          {
            condition: "($request.path equals v2/pet and $request.method equals POST and $request.query.<key1> equals 'test' and $request.body.<val>)",
            response: { $ref: "sample:api_response1:2.0" },
          },
          {
            condition: "default",
            response: { $ref: "sample:api_response2:2.0" },
          },
        ],
      },
    } as unknown as BaseAsset;
  
    const expectedRefs: AssetCacheModel[] = [
      { kind: "MockResponse", ref: "sample:api_response:2.0", isNewlyAdded: true },
      { kind: "MockResponse", ref: "sample:api_response1:2.0", isNewlyAdded: true },
      { kind: "MockResponse", ref: "sample:api_response2:2.0", isNewlyAdded: true },
    ];
  
    (getRefsFromMockEndpointAsset as jest.Mock).mockReturnValue(expectedRefs);
  
    const result = getRefsFromAsset(mockEndpointAsset);
  
    expect(result).toEqual(expectedRefs);
    expect(getRefsFromMockEndpointAsset).toHaveBeenCalledWith(mockEndpointAsset);
    expect(getRefsFromApiAsset).not.toHaveBeenCalled();
    expect(getRefsFromPolicySeqAsset).not.toHaveBeenCalled();
    expect(getRefsFromRouteAsset).not.toHaveBeenCalled();
    expect(getRefsFromTestAsset).not.toHaveBeenCalled();
  });
  


  it("should return an empty array for unknown asset type", () => {
    const asset: BaseAsset = { kind: "UnknownKind" } as BaseAsset;

    const result = getRefsFromAsset(asset);

    expect(result).toEqual([]);
    expect(getRefsFromApiAsset).not.toHaveBeenCalled();
    expect(getRefsFromPolicySeqAsset).not.toHaveBeenCalled();
    expect(getRefsFromRouteAsset).not.toHaveBeenCalled();
    expect(getRefsFromTestAsset).not.toHaveBeenCalled();
  });

  it("should return an empty array for undefined asset kind", () => {
    const asset: BaseAsset = { kind: undefined } as BaseAsset;

    const result = getRefsFromAsset(asset);

    expect(result).toEqual([]);
    expect(getRefsFromApiAsset).not.toHaveBeenCalled();
    expect(getRefsFromPolicySeqAsset).not.toHaveBeenCalled();
    expect(getRefsFromRouteAsset).not.toHaveBeenCalled();
    expect(getRefsFromTestAsset).not.toHaveBeenCalled();
  });

  it("should return an empty array for null asset kind", () => {
    const asset: BaseAsset = { kind: null } as unknown as BaseAsset;

    const result = getRefsFromAsset(asset);
    expect(result).toEqual([]);
    expect(getRefsFromApiAsset).not.toHaveBeenCalled();
    expect(getRefsFromPolicySeqAsset).not.toHaveBeenCalled();
    expect(getRefsFromRouteAsset).not.toHaveBeenCalled();
    expect(getRefsFromTestAsset).not.toHaveBeenCalled();
  });
});
