import { createRef } from "react";
import { render } from "@testing-library/react";
import { Progress } from ".";

const BASE_CLASS = "mobius";
const PROGRESS_CLASS = "mobius-progress";
const PROGRESS_LABEL_CLASS = "mobius-progress__label";

describe("Progress", () => {
  describe("classnames", () => {
    function setup() {
      return render(
        <Progress
          label="Progress"
          className="test"
          minValue={0}
          maxValue={10}
        />,
      );
    }

    const classNames = [BASE_CLASS, PROGRESS_CLASS, "test"];
    it.each(classNames)("should have classname %s", className => {
      const view = setup();
      expect(view.container.firstChild).toHaveClass(className);
    });
  });

  describe("aria values", () => {
    const value = 5;
    const minValue = 0;
    const maxValue = 10;

    it("should use value and % as default for aria-valuetext", () => {
      const { container } = render(
        <Progress
          label="Progress"
          minValue={minValue}
          maxValue={maxValue}
          value={value}
        />,
      );

      const progressBar = container.firstChild;

      expect(progressBar).toHaveAttribute(
        "aria-valuetext",
        `${(value / maxValue) * 100}%`,
      );
      expect(progressBar).toHaveAttribute("aria-valuemax", `${maxValue}`);
      expect(progressBar).toHaveAttribute("aria-valuemin", `${minValue}`);
      expect(progressBar).toHaveAttribute("aria-valuenow", `${value}`);
    });

    it("should use id if set for wrapper div", () => {
      const view = render(
        <Progress
          id="testId"
          label="Progress"
          minValue={minValue}
          maxValue={maxValue}
          value={value}
        />,
      );

      expect(view.container.firstChild).toHaveAttribute("id", "testId");
    });

    it("sets aria-labelledby to match label on wrapper div", () => {
      const { container } = render(
        <Progress
          id="testId"
          label="Test"
          minValue={minValue}
          maxValue={maxValue}
          value={value}
        />,
      );

      const labelId = container
        .getElementsByClassName(PROGRESS_LABEL_CLASS)[0]
        ?.getAttribute("id");

      const labelledById = container
        .getElementsByClassName(PROGRESS_CLASS)[0]
        ?.getAttribute("aria-labelledby");

      expect(labelledById).toEqual(labelId);
    });

    describe("when showLabel is false", () => {
      it("should visually hide label, but keep it accessible", () => {
        const { queryByText } = render(
          <Progress
            label="Progress"
            minValue={minValue}
            maxValue={maxValue}
            value={value}
            showLabel={false}
          />,
        );

        const label = queryByText("Progress");

        expect(label).toHaveStyle("clip: rect(0 0 0 0)");
      });
    });
  });

  const valueFormatter = (value: number, minValue: number, maxValue: number) =>
    `${value},${minValue},${maxValue}`;

  describe("custom formatter", () => {
    const value = 5;
    const minValue = 0;
    const maxValue = 10;

    function setup() {
      return render(
        <Progress
          label="Progress"
          minValue={minValue}
          maxValue={maxValue}
          value={value}
          valueFormatter={valueFormatter}
        />,
      );
    }

    it("should use custom formatter for aria-valuetext", () => {
      const view = setup();
      expect(view.container.firstChild).toHaveAttribute(
        "aria-valuetext",
        `${value},${minValue},${maxValue}`,
      );
    });

    it("should use custom formatter for value text", () => {
      const view = setup();
      expect(view.getByTestId("value-label")).toHaveTextContent(
        `${value},${minValue},${maxValue}`,
      );
    });
  });

  it("forwards ref", () => {
    const ref = createRef<HTMLDivElement>();
    render(<Progress ref={ref} label="Progress" value={50} />);
    expect(ref.current).toBeInstanceOf(HTMLDivElement);
  });
});
