import { handleError } from "Common/ErrorHandlingUtils";
import { createUri } from "Common/UrlUtility";
import Explorer from "Explorer/Explorer";
import { SubmitFeedback } from "Explorer/QueryCopilot/Shared/QueryCopilotClient";
import { userContext } from "UserContext";
import { useQueryCopilot } from "hooks/useQueryCopilot";

jest.mock("@azure/cosmos", () => ({
  Constants: {
    HttpHeaders: {},
  },
}));

jest.mock("Common/ErrorHandlingUtils", () => ({
  handleError: jest.fn(),
}));

jest.mock("Common/SampleDataClient");

jest.mock("node-fetch");

jest.mock("Explorer/Explorer", () => {
  class MockExplorer {
    allocateContainer = jest.fn().mockResolvedValueOnce({});
  }
  return MockExplorer;
});

describe("Query Copilot Client", () => {
  beforeEach(() => jest.clearAllMocks());

  describe("SubmitFeedback", () => {
    const payload = {
      like: "like",
      generatedSql: "GeneratedQuery",
      userPrompt: "UserPrompt",
      description: "Description",
      contact: "Contact",
    };

    const mockStore = useQueryCopilot.getState();
    mockStore.correlationId = "mocked-correlation-id";
    mockStore.notebookServerInfo = {
      notebookServerEndpoint: "mocked-endpoint",
      authToken: "mocked-token",
      forwardingId: "mocked-forwarding-id",
    };

    const feedbackUri = userContext.features.disableCopilotPhoenixGateaway
      ? createUri("https://copilotorchestrater.azurewebsites.net/", "feedback")
      : createUri(useQueryCopilot.getState().notebookServerInfo.notebookServerEndpoint, "public/feedback");

    it("should call fetch with the payload with like", async () => {
      const mockFetch = jest.fn().mockResolvedValueOnce({});

      globalThis.fetch = mockFetch;
      await SubmitFeedback({
        databaseId: "test",
        containerId: "test",
        mode: "User",
        params: {
          likeQuery: true,
          generatedQuery: "GeneratedQuery",
          userPrompt: "UserPrompt",
          description: "Description",
          contact: "Contact",
        },
        explorer: new Explorer(),
      });

      expect(mockFetch).toHaveBeenCalledWith(
        feedbackUri,
        expect.objectContaining({
          headers: expect.objectContaining({
            "x-ms-correlationid": "mocked-correlation-id",
          }),
        }),
      );

      const actualBody = JSON.parse(mockFetch.mock.calls[0][1].body);
      expect(actualBody).toEqual(payload);
    });

    it("should call fetch with the payload with unlike and empty parameters", async () => {
      payload.like = "dislike";
      payload.description = "";
      payload.contact = "";
      const mockFetch = jest.fn().mockResolvedValueOnce({});

      globalThis.fetch = mockFetch;

      await SubmitFeedback({
        databaseId: "test",
        containerId: "test",
        mode: "User",
        params: {
          likeQuery: false,
          generatedQuery: "GeneratedQuery",
          userPrompt: "UserPrompt",
          description: undefined,
          contact: undefined,
        },
        explorer: new Explorer(),
      });

      expect(mockFetch).toHaveBeenCalledWith(
        feedbackUri,
        expect.objectContaining({
          method: "POST",
          headers: {
            "content-type": "application/json",
            "x-ms-correlationid": "mocked-correlation-id",
            Authorization: "token mocked-token",
          },
        }),
      );

      const actualBody = JSON.parse(mockFetch.mock.calls[0][1].body);
      expect(actualBody).toEqual(payload);
    });

    it("should handle errors and call handleError", async () => {
      globalThis.fetch = jest.fn().mockRejectedValueOnce(new Error("Mock error"));

      await SubmitFeedback({
        databaseId: "test",
        containerId: "test",
        mode: "User",
        params: {
          likeQuery: true,
          generatedQuery: "GeneratedQuery",
          userPrompt: "UserPrompt",
          description: "Description",
          contact: "Contact",
        },
        explorer: new Explorer(),
      }).catch((error) => {
        // eslint-disable-next-line jest/no-conditional-expect
        expect(error.message).toEqual("Mock error");
      });

      expect(handleError).toHaveBeenCalledWith(new Error("Mock error"), expect.any(String));
    });
  });
});
