import ApplicationModel from "../../../models/application/ApplicationModel";
import LinkModel from "../../../models/links/LinkModel";
import TabModel from "../../../models/tab/TabModel";
import CaseViewModel from "../../../models/caseview/CaseViewModel";
import FormModel from "../../../models/form/FormModel";
import Href from "../../../models/href/Href";

import {
  getApplication,
  getCaseView,
  getFirstModelByInstance,
  getForm,
  getTab,
  modelByHref,
  keyByHref,
  getActiveModels,
  getPreference,
  getModelsByType,
  getAllModelsByInstance,
  getActiveModelByInstance,
} from "../ModularUISelectors";

import application from "../../../models/application/__mock__/application";
import tab from "../../../models/tab/__mock__/tab";
import tabPerson from "../../../models/tab/__mock__/tabPerson";
import caseview from "../../../models/caseview/__mock__/caseview";
import form from "../../../models/form/__mock__/form";

describe("modularui selectors", () => {
  let state;

  beforeEach(() => {
    state = {
      router: {
        location: {
          pathname: "/books/book/24",
        },
      },
      preferences: {
        prefName: "prefValue",
      },
      modularui: {
        "application(/)(en)": {
          status: "FINISHED",
          lastModification: 1612538240042,
          model: application,
        },
        "tab(/books)(en)": {
          status: "FINISHED",
          lastModification: 1612538240050,
          model: tab,
        },
        "tab(/persons)(en)": {
          status: "FINISHED",
          lastModification: 1612538242250,
          model: tabPerson,
        },
        "caseview(/books/book/24)(en)": {
          status: "FINISHED",
          lastModification: 1612538679203,
          model: caseview,
        },
        "form(/books/books/createbook)(en)": {
          status: "FINISHED",
          lastModification: 1612538616810,
          model: form,
        },
      },
    };
  });

  it("returns null when state is not ready", () => {
    expect(getFirstModelByInstance(null)).toBeNull();
    expect(getFirstModelByInstance({})).toBeNull();

    expect(getActiveModelByInstance(null)).toBeNull();
    expect(getActiveModelByInstance({})).toBeNull();

    expect(modelByHref()).toBeNull();
    expect(modelByHref({})).toBeNull();

    expect(keyByHref()).toBeNull();
    expect(keyByHref({})).toBeNull();
  });

  it("returns an empty array when state is not ready", () => {
    expect(getAllModelsByInstance(null)).toHaveLength(0);
    expect(getAllModelsByInstance({})).toHaveLength(0);

    expect(getAllModelsByInstance(state, ApplicationModel)).toStrictEqual([
      application,
    ]);
    expect(getAllModelsByInstance(state, TabModel)).toStrictEqual([
      tab,
      tabPerson,
    ]);
  });

  it("returns null when a model cannot be found", () => {
    expect(getFirstModelByInstance(state, LinkModel)).toBeNull();
    expect(getActiveModelByInstance(state, LinkModel)).toBeNull();
    expect(modelByHref(state, "/bla")).toBeNull();
    expect(modelByHref(state, new Href("/bla"))).toBeNull();
  });

  it("should return the first model by instance", () => {
    expect(getFirstModelByInstance(state, ApplicationModel)).toBeInstanceOf(
      ApplicationModel,
    );
    expect(getActiveModelByInstance(state, ApplicationModel)).toBeInstanceOf(
      ApplicationModel,
    );
    expect(getActiveModelByInstance(state, TabModel)).toBeInstanceOf(TabModel);
    expect(getActiveModelByInstance(state, TabModel)).toBe(tab);
    expect(getActiveModelByInstance(state, TabModel)).not.toBe(tabPerson);

    expect(getApplication(state)).toBeInstanceOf(ApplicationModel);
    expect(getTab(state)).toBeInstanceOf(TabModel);
    expect(getCaseView(state)).toBeInstanceOf(CaseViewModel);
    expect(getForm(state)).toBeInstanceOf(FormModel);
  });

  it("can return a model by href", () => {
    expect(modelByHref(state, "/")).toBeInstanceOf(ApplicationModel);
  });

  it("can return a model key by href", () => {
    expect(keyByHref(state, "/")).toBe("application(/)(en)");
  });

  it("can retrieve activeModels", () => {
    const activeModels = getActiveModels(state);
    expect(activeModels).toStrictEqual([
      expect.objectContaining({ key: "tab", label: "Books", type: "Tab" }),
      expect.objectContaining({
        key: "caseview",
        label: "The safety of objects",
        type: "CaseView",
      }),
    ]);
  });

  it("can retrieve a preference", () => {
    expect(getPreference(state, "prefName")).toBe("prefValue");
    expect(getPreference(state, "notFound")).toBeUndefined();
  });

  it("can retrieve a model by type", () => {
    expect(getModelsByType(state, "Application")[0]).toBeInstanceOf(
      ApplicationModel,
    );
  });
});
