import React from "react";
import { mount } from "enzyme";
import { MultiSelect } from "content-src/components/MultiSelect";

describe("MultiSelect component", () => {
  let sandbox;
  let MULTISELECT_SCREEN_PROPS;
  let setScreenMultiSelects;
  let setActiveMultiSelect;
  beforeEach(() => {
    sandbox = sinon.createSandbox();
    setScreenMultiSelects = sandbox.stub();
    setActiveMultiSelect = sandbox.stub();
    MULTISELECT_SCREEN_PROPS = {
      id: "multiselect-screen",
      content: {
        position: "split",
        split_narrow_bkg_position: "-60px",
        image_alt_text: {
          string_id: "mr2022-onboarding-default-image-alt",
        },
        background:
          "url('chrome://activity-stream/content/data/content/assets/mr-settodefault.svg') var(--mr-secondary-position) no-repeat var(--mr-screen-background-color)",
        progress_bar: true,
        logo: {},
        title: "Test Title",
        tiles: {
          type: "multiselect",
          label: "Test Subtitle",
          data: [
            {
              id: "checkbox-1",
              defaultValue: true,
              label: {
                string_id: "mr2022-onboarding-set-default-primary-button-label",
              },
              action: {
                type: "SET_DEFAULT_BROWSER",
              },
            },
            {
              id: "checkbox-2",
              defaultValue: true,
              label: "Test Checkbox 2",
              action: {
                type: "SHOW_MIGRATION_WIZARD",
                data: {},
              },
            },
            {
              id: "checkbox-3",
              defaultValue: false,
              label: "Test Checkbox 3",
              action: {
                type: "SHOW_MIGRATION_WIZARD",
                data: {},
              },
            },
          ],
        },
        primary_button: {
          label: "Save and Continue",
          action: {
            type: "MULTI_ACTION",
            collectSelect: true,
            navigate: true,
            data: { actions: [] },
          },
        },
        secondary_button: {
          label: "Skip",
          action: {
            navigate: true,
          },
          has_arrow_icon: true,
        },
      },
      setScreenMultiSelects,
      setActiveMultiSelect,
    };
  });
  afterEach(() => {
    sandbox.restore();
  });

  it("should call setScreenMultiSelects with all ids of checkboxes", () => {
    mount(<MultiSelect {...MULTISELECT_SCREEN_PROPS} />);

    assert.calledOnce(setScreenMultiSelects);
    assert.calledWith(setScreenMultiSelects, [
      "checkbox-1",
      "checkbox-2",
      "checkbox-3",
    ]);
  });

  it("should not call setScreenMultiSelects if it's already set", () => {
    let map = sandbox
      .stub()
      .returns(MULTISELECT_SCREEN_PROPS.content.tiles.data);

    mount(
      <MultiSelect screenMultiSelects={{ map }} {...MULTISELECT_SCREEN_PROPS} />
    );

    assert.notCalled(setScreenMultiSelects);
    assert.calledOnce(map);
    assert.calledWith(map, sinon.match.func);
  });

  it("should call setActiveMultiSelect with ids of checkboxes with defaultValue true", () => {
    const wrapper = mount(<MultiSelect {...MULTISELECT_SCREEN_PROPS} />);

    wrapper.setProps({ activeMultiSelect: null });
    assert.calledOnce(setActiveMultiSelect);
    assert.calledWith(setActiveMultiSelect, ["checkbox-1", "checkbox-2"]);
  });

  it("should use activeMultiSelect ids to set checked state for respective checkbox", () => {
    const wrapper = mount(<MultiSelect {...MULTISELECT_SCREEN_PROPS} />);

    wrapper.setProps({ activeMultiSelect: ["checkbox-1", "checkbox-2"] });
    const checkBoxes = wrapper.find(".checkbox-container input");
    assert.strictEqual(checkBoxes.length, 3);

    assert.strictEqual(checkBoxes.first().props().checked, true);
    assert.strictEqual(checkBoxes.at(1).props().checked, true);
    assert.strictEqual(checkBoxes.last().props().checked, false);
  });

  it("cover the randomize property", async () => {
    MULTISELECT_SCREEN_PROPS.content.tiles.data.forEach(
      item => (item.randomize = true)
    );

    const wrapper = mount(<MultiSelect {...MULTISELECT_SCREEN_PROPS} />);

    const checkBoxes = wrapper.find(".checkbox-container input");
    assert.strictEqual(checkBoxes.length, 3);

    // We don't want to actually test the randomization, just that it doesn't
    // throw. We _could_ render the component until we get a different order,
    // and that should work the vast majority of the time, but it's
    // theoretically possible that we get the same order over and over again
    // until we hit the 2 second timeout. That would be an extremely low failure
    // rate, but we already know Math.random() works, so we don't really need to
    // test it anyway. It's not worth the added risk of false failures.
  });

  it("should filter out id when checkbox is unchecked", () => {
    const wrapper = mount(<MultiSelect {...MULTISELECT_SCREEN_PROPS} />);
    wrapper.setProps({ activeMultiSelect: ["checkbox-1", "checkbox-2"] });

    const ckbx1 = wrapper.find(".checkbox-container input").at(0);
    assert.strictEqual(ckbx1.prop("value"), "checkbox-1");
    ckbx1.getDOMNode().checked = false;
    ckbx1.simulate("change");
    assert.calledWith(setActiveMultiSelect, ["checkbox-2"]);
  });

  it("should add id when checkbox is checked", () => {
    const wrapper = mount(<MultiSelect {...MULTISELECT_SCREEN_PROPS} />);
    wrapper.setProps({ activeMultiSelect: ["checkbox-1", "checkbox-2"] });

    const ckbx3 = wrapper.find(".checkbox-container input").at(2);
    assert.strictEqual(ckbx3.prop("value"), "checkbox-3");
    ckbx3.getDOMNode().checked = true;
    ckbx3.simulate("change");
    assert.calledWith(setActiveMultiSelect, [
      "checkbox-1",
      "checkbox-2",
      "checkbox-3",
    ]);
  });

  it("should render radios and checkboxes with correct styles", async () => {
    const SCREEN_PROPS = { ...MULTISELECT_SCREEN_PROPS };
    SCREEN_PROPS.content.tiles.style = { flexDirection: "row", gap: "24px" };
    SCREEN_PROPS.content.tiles.data = [
      {
        id: "checkbox-1",
        defaultValue: true,
        label: { raw: "Test1" },
        action: { type: "OPEN_PROTECTION_REPORT" },
        style: { color: "red" },
        icon: { style: { color: "blue" } },
      },
      {
        id: "radio-1",
        type: "radio",
        group: "radios",
        defaultValue: true,
        label: { raw: "Test3" },
        action: { type: "OPEN_PROTECTION_REPORT" },
        style: { color: "purple" },
        icon: { style: { color: "yellow" } },
      },
    ];
    const wrapper = mount(<MultiSelect {...SCREEN_PROPS} />);

    // wait for effect hook
    await new Promise(resolve => queueMicrotask(resolve));
    // activeMultiSelect was called on effect hook with default values
    assert.calledWith(setActiveMultiSelect, ["checkbox-1", "radio-1"]);

    const container = wrapper.find(".multi-select-container");
    assert.strictEqual(container.prop("style").flexDirection, "row");
    assert.strictEqual(container.prop("style").gap, "24px");

    // checkboxes/radios are rendered with correct styles
    const checkBoxes = wrapper.find(".checkbox-container");
    assert.strictEqual(checkBoxes.length, 2);
    assert.strictEqual(checkBoxes.first().prop("style").color, "red");
    assert.strictEqual(checkBoxes.at(1).prop("style").color, "purple");

    const checks = wrapper.find(".checkbox-container input");
    assert.strictEqual(checks.length, 2);
    assert.strictEqual(checks.first().prop("style").color, "blue");
    assert.strictEqual(checks.at(1).prop("style").color, "yellow");
  });
});
