import { fireEvent, render } from "@testing-library/react";

import { Tooltip } from "../Tooltip";

import Base from "./BaseWrapper";

describe("rendering Tooltip", () => {
  describe("initial state", () => {
    let tooltip;

    beforeEach(() => {
      tooltip = render(
        <Base>
          <Tooltip data-testid="test-id" />
        </Base>,
      );
    });

    it("default tag is span, therefore it renders 3 elements with tag span", () => {
      const { container } = tooltip;
      expect(container.querySelectorAll("span").length).toBe(3);
    });
    it("has default class tooltip", () => {
      const { getByTestId } = tooltip;
      expect(getByTestId("test-id")).toHaveClass("tooltip");
    });
    it("has default role tooltip", () => {
      const { getByTestId } = tooltip;
      expect(getByTestId("test-id").getAttribute("role")).toBe("tooltip");
    });
    it("has hidden attribute", () => {
      const { getByTestId } = tooltip;
      expect(getByTestId("test-id").hidden).toBe(true);
    });
    it("has data-tooltip attribute", () => {
      const { getByTestId } = tooltip;
      expect(getByTestId("test-id").getAttribute("data-tooltip")).toBe("true");
    });
    it("has span with class tooltip__arrow", () => {
      const { container } = tooltip;
      expect(container.getElementsByClassName("tooltip__arrow").length).toBe(1);
      expect(
        container.getElementsByClassName("tooltip__arrow")[0].tagName,
      ).toBe("SPAN");
    });
    it("has span with class tooltip__dialog", () => {
      const { container } = tooltip;
      expect(container.getElementsByClassName("tooltip__dialog").length).toBe(
        1,
      );
      expect(
        container.getElementsByClassName("tooltip__dialog")[0].tagName,
      ).toBe("SPAN");
    });
    it("has hidden attribute set to true", () => {
      const { getByTestId } = tooltip;
      expect(getByTestId("test-id").hidden).toBe(true);
    });
    it("renders button with generated aria-describeby", () => {
      const { container } = tooltip;
      const pattern = /id-\d+/;
      expect(container.querySelector("button")).toBeInTheDocument();

      expect(
        pattern.test(
          container.querySelector("button").getAttribute("aria-describedby"),
        ),
      ).toBeTruthy();
    });
    it("renders button with generated aria-owns", () => {
      const { container } = tooltip;
      const pattern = /id-\d+/;
      expect(container.querySelector("button")).toBeInTheDocument();
      expect(
        pattern.test(
          container.querySelector("button").getAttribute("aria-owns"),
        ),
      ).toBeTruthy();
    });
    it("renders button with data-tooltip-trigger set to true", () => {
      const { container } = tooltip;
      expect(container.querySelector("button")).toBeInTheDocument();
      expect(
        container.querySelector("button").getAttribute("data-tooltip-trigger"),
      ).toBe("true");
    });
  });
  describe("passed props", () => {
    it("when tag  is set to div, renders 5 elements with tag div (3 + 2 root divs defined here)", () => {
      const { container } = render(
        <Base>
          <Tooltip tag="div" />
        </Base>,
      );
      expect(container.querySelectorAll("div").length).toBe(5);
    });
    it("renders children", () => {
      const { getByText } = render(
        <Base>
          <Tooltip>test</Tooltip>
        </Base>,
      );
      expect(getByText("test")).toBeInTheDocument();
    });
    it("renders dialog", () => {
      const { getByText } = render(
        <Base>
          <Tooltip dialog="test" />
        </Base>,
      );
      expect(getByText("test")).toBeInTheDocument();
    });
    it("has additional class when className is set ", () => {
      const { getByTestId } = render(
        <Base>
          <Tooltip data-testid="test-id" className="test-class" />
        </Base>,
      );
      expect(getByTestId("test-id")).toHaveClass("tooltip");
      expect(getByTestId("test-id")).toHaveClass("test-class");
    });
    [
      "auto",
      "top",
      "top-start",
      "top-end",
      "bottom",
      "bottom-start",
      "bottom-end",
      "right",
      "right-start",
      "right-end",
      "left",
      "left-start",
      "left-end",
    ].map((placement) => {
      it(`has data-tooltip-placement set to ${placement} which is passed by placement prop`, () => {
        const { getByTestId } = render(
          <Base>
            <Tooltip data-testid="test-id" placement={placement} />
          </Base>,
        );
        expect(
          getByTestId("test-id").getAttribute("data-tooltip-placement"),
        ).toBe(placement);
      });
    });
    it("renders trigger element instead of button", () => {
      const { container } = render(
        <Base>
          <Tooltip
            data-testid="test-id"
            renderTrigger={(props) => {
              return <p {...props} />;
            }}
          />
        </Base>,
      );
      expect(container.querySelector("p")).toBeInTheDocument();
      expect(container.querySelector("button")).not.toBeInTheDocument();
    });
    it("trigger element has generated aria-describeby", () => {
      const { container } = render(
        <Base>
          <Tooltip
            data-testid="test-id"
            renderTrigger={(props) => {
              return <p {...props} />;
            }}
          />
        </Base>,
      );
      const pattern = /id-\d+/;
      expect(container.querySelector("p")).toBeInTheDocument();

      expect(
        pattern.test(
          container.querySelector("p").getAttribute("aria-describedby"),
        ),
      ).toBeTruthy();
    });
    it("trigger element has generated aria-owns", () => {
      const { container } = render(
        <Base>
          <Tooltip
            data-testid="test-id"
            renderTrigger={(props) => {
              return <p {...props} />;
            }}
          />
        </Base>,
      );
      const pattern = /id-\d+/;
      expect(container.querySelector("p")).toBeInTheDocument();
      expect(
        pattern.test(container.querySelector("p").getAttribute("aria-owns")),
      ).toBeTruthy();
    });
    it("trigger element has data-tooltip-trigger set to true", () => {
      const { container } = render(
        <Base>
          <Tooltip
            data-testid="test-id"
            renderTrigger={(props) => {
              return <p {...props} />;
            }}
          />
        </Base>,
      );
      expect(container.querySelector("p")).toBeInTheDocument();
      expect(
        container.querySelector("p").getAttribute("data-tooltip-trigger"),
      ).toBe("true");
    });
  });
  describe("fires events", () => {
    let tooltip;

    beforeEach(() => {
      tooltip = render(
        <Base>
          <Tooltip data-testid="test-id" />
        </Base>,
      );
    });
    it("button does not get class is-active when focused", () => {
      const { container } = tooltip;
      fireEvent.focus(container.querySelector("button"));
      expect(container.querySelector("button")).not.toHaveClass("is-active");
    });

    it("tooltip is not visible when button is focused", () => {
      const { container, getByTestId } = tooltip;
      fireEvent.focus(container.querySelector("button"));
      expect(getByTestId("test-id")).not.toHaveClass("is-visible");
    });
    it("button has class is-active when clicked", () => {
      const { container } = tooltip;
      fireEvent.click(container.querySelector("button"));
      expect(container.querySelector("button")).toHaveClass("is-active");
    });

    it("tooltip has class is-visible when button is clicked", () => {
      const { container, getByTestId } = tooltip;
      fireEvent.click(container.querySelector("button"));
      expect(getByTestId("test-id")).toHaveClass("is-visible");
    });
    it("has hidden attribute set to false after button click", () => {
      const { getByTestId, container } = tooltip;
      fireEvent.click(container.querySelector("button"));
      expect(getByTestId("test-id").hidden).toBe(false);
    });
    it("keeps hidden attribute set to true after button focus", () => {
      const { getByTestId, container } = tooltip;
      fireEvent.focus(container.querySelector("button"));
      expect(getByTestId("test-id").hidden).toBe(true);
    });
    it("button loses class is-active after blur", () => {
      const { container } = tooltip;
      fireEvent.click(container.querySelector("button"));
      fireEvent.blur(container.querySelector("button"));
      expect(container.querySelector("button")).not.toHaveClass("is-active");
    });

    it("tooltip loses class is-visible after blur", () => {
      const { container, getByTestId } = tooltip;
      fireEvent.click(container.querySelector("button"));
      fireEvent.blur(container.querySelector("button"));
      expect(getByTestId("test-id")).not.toHaveClass("is-visible");
    });
    it("button loses class is-active after second click", () => {
      const { container } = tooltip;
      fireEvent.click(container.querySelector("button"));
      fireEvent.click(container.querySelector("button"));
      expect(container.querySelector("button")).not.toHaveClass("is-active");
    });

    it("tooltip loses class is-visible after second click", () => {
      const { container, getByTestId } = tooltip;
      fireEvent.click(container.querySelector("button"));
      fireEvent.click(container.querySelector("button"));
      expect(getByTestId("test-id")).not.toHaveClass("is-visible");
    });
    it("hides on blur after being opened by click", () => {
      const { getByTestId, container } = tooltip;
      fireEvent.click(container.querySelector("button"));
      fireEvent.blur(container.querySelector("button"));
      expect(getByTestId("test-id")).not.toHaveClass("is-visible");
    });
    it("stays visible when tooltip content is clicked", () => {
      const { getByTestId, container } = tooltip;
      fireEvent.click(container.querySelector("button"));
      fireEvent.mouseDown(getByTestId("test-id"));
      fireEvent.blur(container.querySelector("button"));
      expect(getByTestId("test-id")).toHaveClass("is-visible");
    });
    it("hides when clicking outside tooltip and trigger", () => {
      const { getByTestId, container } = tooltip;
      fireEvent.click(container.querySelector("button"));
      fireEvent.click(document.body);
      expect(getByTestId("test-id")).not.toHaveClass("is-visible");
    });
    it("hides on Escape key press", () => {
      const { getByTestId, container } = tooltip;
      fireEvent.click(container.querySelector("button"));
      fireEvent.keyDown(container.querySelector("button"), { key: "Escape" });
      expect(getByTestId("test-id")).not.toHaveClass("is-visible");
    });
  });
});
