/**
 * TEAM: frontend_infra
 * @flow
 */

// TODO: Fix this eslint issue on next edit. This is an autogenerated comment.
// eslint-disable-next-line flexport/no-legacy-dependencies
import {mount, ReactWrapper} from "enzyme";
import {act} from "react-dom/test-utils";
import MultiselectFilter, {
  getFilterValueFromArray,
  type Option,
} from "../MultiselectFilter";

// Popper uses document.createRange, which JSDOM doesn't support
jest.mock("popper.js");

const testOptions: $ReadOnlyArray<Option<string>> = [
  {
    value: "test1",
    label: "Schedule Pick Up",
  },
  {
    value: "test2",
    label: "Pending Pick Up",
  },
  {
    value: "test3",
    label: "Other data",
  },
  {
    value: "test4",
    label: "Yet other data",
  },
];

function mountMultiSelectFilter(propOverrides: {...} = {}) {
  // $FlowFixMe[cannot-spread-inexact] upgrade 0.121.1 -> 0.122.0
  const props = {
    label: "test",
    value: getFilterValueFromArray([], testOptions),
    onChange: () => {},
    options: testOptions,
    ...propOverrides,
  };

  return mount(<MultiselectFilter {...props} />);
}

function openFilter(filter: ReactWrapper<typeof MultiselectFilter>) {
  filter.find("FilterButton").simulate("click");
}

describe("Multifilter", () => {
  it("can select a value", () => {
    const handleChange = jest.fn();
    const wrapper = mountMultiSelectFilter({
      onChange: handleChange,
    });

    openFilter(wrapper);

    const firstOption = wrapper.find("Checkbox").at(1);
    act(() => firstOption.props().onChange(true));

    expect(handleChange).toHaveBeenCalledWith({
      specificValues: ["test1"],
      type: "specificValues",
    });
  });

  it("can clear a value", () => {
    const handleChange = jest.fn();
    const wrapper = mountMultiSelectFilter({
      value: getFilterValueFromArray(["test1"], testOptions),
      onChange: handleChange,
    });

    openFilter(wrapper);

    const firstOption = wrapper.find("Checkbox").at(0);
    act(() => firstOption.props().onChange(false));

    expect(handleChange).toHaveBeenCalledWith({
      type: "unfiltered",
      showAs: "noneSelected",
    });
  });

  it("can select all with the select all option", () => {
    const handleChange = jest.fn();
    const wrapper = mountMultiSelectFilter({
      value: getFilterValueFromArray(["test1"], testOptions),
      onChange: handleChange,
    });

    openFilter(wrapper);

    const selectAllOption = wrapper.find("Checkbox").at(0);
    act(() => selectAllOption.props().onChange(true));

    expect(handleChange).toHaveBeenCalledWith({
      type: "unfiltered",
      showAs: "allSelected",
    });

    // Pass update back into component as props
    wrapper.setProps({value: handleChange.mock.calls[0][0]});
    expect(wrapper.find("Checkbox").every({checked: true})).toBe(true);
  });

  it("can deselect all with the select all option", () => {
    const handleChange = jest.fn();
    const wrapper = mountMultiSelectFilter({
      value: getFilterValueFromArray(["test1", "test2"], testOptions),
      onChange: handleChange,
    });

    openFilter(wrapper);

    const selectAllOption = wrapper.find("Checkbox").at(0);
    act(() => selectAllOption.props().onChange(false));

    // Deselecting all is equivalent to selecting all
    expect(handleChange).toHaveBeenCalledWith({
      type: "unfiltered",
      showAs: "noneSelected",
    });

    // Even though we tell the onChange handler that everything is selected,
    // we want to uncheck all the checkboxes in the UI
    wrapper.setProps({value: handleChange.mock.calls[0][0]});
    expect(wrapper.find("Checkbox").every({checked: false})).toBe(true);
  });

  it("can remove all values", () => {
    const handleRemove = jest.fn();
    const wrapper = mountMultiSelectFilter({
      value: getFilterValueFromArray(["test1"], testOptions),
      onRemove: handleRemove,
    });

    const removeButton = wrapper.find({iconName: "cancel"}).find("button");
    removeButton.simulate("click");

    expect(handleRemove).toHaveBeenCalled();

    // Pass update back into component as props
    wrapper.setProps({value: {type: "unfiltered", showAs: "noneSelected"}});
    expect(wrapper.find("Checkbox").every({checked: false})).toBe(true);
  });

  it("disables remove button when disabled", () => {
    const handleRemove = jest.fn();
    const wrapper = mountMultiSelectFilter({
      value: getFilterValueFromArray(["test1"], testOptions),
      onRemove: handleRemove,
      disabled: true,
    });

    const removeButton = wrapper.find({iconName: "cancel"}).find("button");
    removeButton.simulate("click");

    expect(handleRemove).not.toHaveBeenCalled();
  });

  it("updates when value changes", () => {
    const wrapper = mountMultiSelectFilter({
      value: getFilterValueFromArray(["test1"], testOptions),
    });

    expect(wrapper.text()).toContain("Schedule Pick Up");

    wrapper.setProps({value: {type: "unfiltered", showAs: "noneSelected"}});

    expect(wrapper.text()).not.toContain("Schedule Pick Up");
  });
});
