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 } from "react-router";

import {
  ConceptIndexModel,
  ContentIndexModel,
  ContentTypeModel,
  ContentTOCModel,
  Href,
  ModelCatalogModel,
} from "../../models";
import {
  useConceptDetail,
  useConceptIndex,
  useContent,
  useContentIndex,
  useContentTOC,
  useModelCatalog,
  useContentType,
  useCompleteSource,
} from "../useModelCatalog";
import { DateUtil } from "../../utils";

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
}));

const JSON_TYPE = "application/json";

describe("modelcatalog 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.split("?")[0]})(en)`,
          href: new Href(url),
          locale: "en",
          targetModel: targetModel,
        }),
      },
    ]);
  };

  // replace the real XHR object with the mock XHR object before each test
  // eslint-disable-next-line jest/no-hooks
  beforeEach(() => {
    useLocation.mockReturnValue({
      state: null,
    });
    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("useModelCatalog", () => {
    assertTargetModel(
      () =>
        useModelCatalog("modelcatalog", "/modelcatalog", [ModelCatalogModel]),
      "modelcatalog",
      "/modelcatalog",
      ModelCatalogModel,
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useConceptIndex", () => {
    assertTargetModel(
      () => useConceptIndex("/conceptindex"),
      "conceptindex",
      "/conceptindex?entryDate=" + DateUtil.now(),
      ConceptIndexModel,
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useConceptDetail", () => {
    assertTargetModel(
      () => useConceptDetail("/conceptdetail"),
      "conceptdetail",
      "/concepts/conceptdetail?entryDate=" + DateUtil.now(),
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useContentIndex", () => {
    assertTargetModel(
      () => useContentIndex("/contentindex"),
      "contentindex",
      "/contentindex",
      ContentIndexModel,
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useContentTOC", () => {
    assertTargetModel(
      () => useContentTOC("/contenttoc"),
      "contenttoc",
      "/content/contenttoc?entryDate=" + DateUtil.now(),
      ContentTOCModel,
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useContent", () => {
    assertTargetModel(
      () => useContent("/contentdetail"),
      "content",
      "/content/contentdetail?entryDate=" + DateUtil.now(),
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useCompleteSource", () => {
    assertTargetModel(
      () => useCompleteSource("/contentdetail"),
      "content",
      "/content/contentdetail?complete=true&entryDate=" + DateUtil.now(),
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useCompleteSource 2", () => {
    assertTargetModel(
      () => useCompleteSource("/contentdetail?complete=false"),
      "content",
      "/content/contentdetail?complete=true&entryDate=" + DateUtil.now(),
    );
  });

  // eslint-disable-next-line jest/expect-expect
  it("useContentType", () => {
    assertTargetModel(
      () => useContentType("/contenttypes/contenttype"),
      "contenttypes",
      "/contenttypes/contenttype",
      ContentTypeModel,
    );
  });
});
