import { createRef } from "react";
import { render, screen } from "@testing-library/react";
import { Grid } from ".";

import { getBreakpointMap, DEFAULT_SPAN } from "./Item";

describe("Test for Grid", () => {
  it("should render without errors", () => {
    const view = render(
      <Grid>
        <Grid.Item span={11}>span=11</Grid.Item>
        <Grid.Item span={1}>span=1</Grid.Item>
      </Grid>,
    );
    expect(view).toBeTruthy();
  });

  it("forwards ref to the grid container", () => {
    const ref = createRef<HTMLDivElement>();
    render(
      <Grid ref={ref}>
        <Grid.Item>Item</Grid.Item>
      </Grid>,
    );
    expect(ref.current).toBeInstanceOf(HTMLDivElement);
  });

  it("forwards ref to the grid item", () => {
    const ref = createRef<HTMLDivElement>();
    render(
      <Grid>
        <Grid.Item ref={ref}>Item</Grid.Item>
      </Grid>,
    );
    expect(ref.current).toBeInstanceOf(HTMLDivElement);
  });

  it("uses mobius class on Grid.Item", () => {
    render(
      <Grid>
        <Grid.Item>Item</Grid.Item>
      </Grid>,
    );
    expect(screen.getByText("Item")).toHaveClass("mobius");
  });

  describe("given the span prop is an array", () => {
    it("should render default as fallback", () => {
      const span = [1, 2, 3];

      const { container } = render(
        <Grid>
          <Grid.Item span={span}>span={DEFAULT_SPAN}</Grid.Item>
        </Grid>,
      );
      expect(container).toBeTruthy();
      expect(screen.getByText(`span=${DEFAULT_SPAN}`)).toHaveStyle(
        `grid-column: span ${DEFAULT_SPAN};`,
      );
    });
  });

  describe("given the span prop is a custom number", () => {
    it("should render using the custom value", () => {
      const span = 5;

      const { container } = render(
        <Grid>
          <Grid.Item span={span}>span={span}</Grid.Item>
        </Grid>,
      );
      expect(container).toBeTruthy();
      expect(screen.getByText(`span=${span}`)).toHaveStyle(
        `grid-column: span ${span};`,
      );
    });
  });
});

describe("getBreakpointMap", () => {
  describe("given only the smallest breakpoint is provided", () => {
    it("returns the smallest breakpoint repeated across the map", () => {
      const config = {
        xs: 6,
        sm: undefined,
        md: undefined,
        lg: undefined,
        xl: undefined,
        xxl: undefined,
      };

      const breakpointMap = getBreakpointMap(config);

      const expected = {
        xs: 6,
        sm: 6,
        md: 6,
        lg: 6,
        xl: 6,
        xxl: 6,
      };

      expect(breakpointMap).toEqual(expected);
    });
  });

  describe("given only a single breakpoint is provided", () => {
    it("returns the breakpoint, which is then repeated across the higher breakpoints", () => {
      const config = {
        xs: undefined,
        sm: undefined,
        md: undefined,
        lg: 9,
        xl: undefined,
        xxl: undefined,
      };

      const breakpointMap = getBreakpointMap(config);

      const expected = {
        xs: undefined,
        sm: undefined,
        md: undefined,
        lg: 9,
        xl: 9,
        xxl: 9,
      };

      expect(breakpointMap).toEqual(expected);
    });
  });

  describe("given only the largest breakpoint is provided", () => {
    it("returns the largest breakpoint", () => {
      const config = {
        xs: undefined,
        sm: undefined,
        md: undefined,
        lg: undefined,
        xl: undefined,
        xxl: 2,
      };

      const breakpointMap = getBreakpointMap(config);

      const expected = {
        xs: undefined,
        sm: undefined,
        md: undefined,
        lg: undefined,
        xl: undefined,
        xxl: 2,
      };

      expect(breakpointMap).toEqual(expected);
    });
  });
});
