import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import { Provider } from "react-redux";
import { renderHook } from "@testing-library/react";
import xhrMock from "xhr-mock";

import { useLocation, useRouteMatch } from "react-router";

import {
  useApplication,
  useTab,
  useCaseView,
  useGroupingPanel,
  useDetailPanel,
  useUserProfile,
} from "../useModularUIModel";
import { useList, useListDetail } from "../useList";
import { usePanel } from "../usePanel";
import { useQuicksearch } from "../useSearch";
import {
  ApplicationModel,
  CaseSearchModel,
  CaseViewModel,
  DetailModel,
  GroupingPanelModel,
  Href,
  ListDetailModel,
  ListModel,
  TabModel,
  UserProfileModel,
} from "../../models";

const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);

jest.mock("react-router", () => ({
  ...jest.requireActual("react-router"), // Keep other methods from react-router as is
  useLocation: jest.fn(), // Mock useLocation
  useRouteMatch: jest.fn(),
}));

const JSON_TYPE = "application/json";

describe("modularui hooks", () => {
  /**
   */
  const assertTargetModel = (hook, key, url, targetModel) => {
    expect.assertions(2);

    xhrMock.get(`/BeInformed` + url, (req, res) => {
      expect(req.header("accept")).toBe(JSON_TYPE);
      expect(req.header("Content-Type")).toBe(JSON_TYPE);
      return res.status(200).body({ data: "ok" });
    });

    const store = mockStore({
      modularui: {},
      router: { location: {} },
      i18n: { locale: "en" },
    });
    /**
     */
    const wrapper = ({ children }) => (
      <Provider store={store}>{children}</Provider>
    );

    const { result } = renderHook(hook, {
      wrapper,
    });

    expect(result.current).toBeNull();

    expect(store.getActions()).toStrictEqual([
      { type: "START_PROGRESS" },
      {
        type: "MODULARUI/FETCH",
        payload: expect.objectContaining({
          key: `${key}(${url})(en)`,
          href: new Href(url),
          locale: "en",
          targetModel: targetModel,
        }),
      },
    ]);
  };

  // eslint-disable-next-line jest/no-hooks
  beforeEach(() => {
    useLocation.mockReturnValue({
      state: null,
    });
    useRouteMatch.mockReturnValue({
      isExact: true,
    });
    xhrMock.setup();
  });

  // put the real XHR object back and clear the mocks after each test
  // eslint-disable-next-line jest/no-hooks
  afterEach(() => xhrMock.teardown());

  // eslint-disable-next-line jest/expect-expect
  it("useApplication", () => {
    assertTargetModel(
      () => useApplication(),
      "application",
      "/",
      ApplicationModel,
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useTab", () => {
    assertTargetModel(() => useTab("/tab"), "tab", "/tab", TabModel);
  });

  // eslint-disable-next-line jest/expect-expect
  it("useCaseView", () => {
    assertTargetModel(
      () => useCaseView("/tab/caseview/1"),
      "caseview",
      "/tab/caseview/1",
      CaseViewModel,
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("usePanel", () => {
    assertTargetModel(
      () => usePanel("/tab/caseview/1/panel"),
      "panel",
      "/tab/caseview/1/panel",
      [ListModel, GroupingPanelModel, DetailModel, CaseSearchModel],
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useList", () => {
    assertTargetModel(() => useList("/tab/list"), "list", "/tab/list", [
      ListModel,
      CaseSearchModel,
    ]);
  });

  // eslint-disable-next-line jest/expect-expect
  it("useListDetail", () => {
    assertTargetModel(
      () => useListDetail("/tab/list/1"),
      "listdetail",
      "/tab/list/1",
      ListDetailModel,
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useGroupingPanel", () => {
    assertTargetModel(
      () => useGroupingPanel("/tab/groupingpanel"),
      "groupingpanel",
      "/tab/groupingpanel",
      GroupingPanelModel,
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useDetailPanel", () => {
    assertTargetModel(
      () => useDetailPanel("/tab/detailpanel"),
      "detailpanel",
      "/tab/detailpanel",
      DetailModel,
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useQuicksearch", () => {
    assertTargetModel(
      () => useQuicksearch("/quicksearch"),
      "quicksearch",
      "/quicksearch",
      CaseSearchModel,
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useUserProfile", () => {
    assertTargetModel(
      () => useUserProfile("/user"),
      "userprofile",
      "/user",
      UserProfileModel,
    );
  });
});
