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

import * as React from "react";
import {render} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import SelectionList from "../SelectionList";
import SelectionListOption from "../SelectionListOption";

function mountSelectionList(
  props: ?$Shape<React.ElementConfig<typeof SelectionList>>
) {
  return render(
    <SelectionList onSelection={() => {}} {...props}>
      {props?.children ?? ""}
    </SelectionList>
  );
}

/** Tests behavior specifically tied to SelectionList's connecting behavior
 * between Dropdown and SelectionList, those components' tests will cover
 * nested behavior */
describe("SelectionList", () => {
  it("renders given options", () => {
    const options = ["bread", "water", "salt", "washington"];
    const result = mountSelectionList({
      children: options.map(option => (
        <SelectionListOption key={option} value={option} />
      )),
    });

    options.forEach(option => {
      expect(result.getByText(option) != null).toBe(true);
    });
  });
  it("SelectionListOption options can contain complex content", async () => {
    const content = "foo";
    const result = mountSelectionList({
      children: (
        <SelectionListOption value={content}>
          <svg />
          <div>
            <span>{content}</span>
          </div>
        </SelectionListOption>
      ),
    });

    expect(result.getByText(content) != null).toBe(true);
  });
  it("selected option is has selected effect", async () => {
    const options = ["bread", "water", "salt", "washington"];
    const selected = "bread";
    const result = mountSelectionList({
      selected,
      children: options.map(option => (
        <SelectionListOption key={option} value={option} />
      )),
    });

    const selectedOptionElement = result.container.querySelector(
      `[data-qa-id="option-${selected}"]`
    );

    expect(
      selectedOptionElement?.querySelector("[class*=optionBackgroundActive]") !=
        null
    ).toBe(true);
  });
  it("'onSelection' works", async () => {
    const options = ["bread", "water", "salt", "washington"];
    const onSelection = jest.fn();
    const result = mountSelectionList({
      onSelection,
      children: options.map(option => (
        <SelectionListOption key={option} value={option} />
      )),
    });

    expect(onSelection.mock.calls.length).toBe(0);

    options.forEach((option, index) => {
      const optionElement = result.container.querySelector(
        `[data-qa-id="option-${option}"]`
      );
      if (optionElement == null)
        throw Error("Options missing in SelectionList.");

      userEvent.click(optionElement);

      expect(onSelection.mock.calls.length).toBe(index + 1);
    });
  });
  it("Cannot select already selected option", async () => {
    const options = ["bread", "water", "salt", "washington"];
    const selected = options[0];
    const onSelection = jest.fn();
    const result = mountSelectionList({
      onSelection,
      selected,
      children: options.map(option => (
        <SelectionListOption key={option} value={option} />
      )),
    });
    expect(onSelection.mock.calls.length).toBe(0);

    const optionElement = result.container.querySelector(
      `[data-qa-id="option-${selected}"]`
    );

    if (optionElement == null) throw Error("Options missing in SelectionList.");

    userEvent.click(optionElement);

    expect(onSelection.mock.calls.length).toBe(0);
  });
});
