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

const CLASS_NAME = "mobius-text";

describe("Text", () => {
  it("should render without errors", () => {
    render(<Text elementType="h1">Sample text</Text>);
  });

  describe("given elementType", () => {
    it("is not applied as element attribute", () => {
      const { container } = render(<Text elementType="h4">Sample text</Text>);
      expect(container.firstChild).not.toHaveAttribute("elementtype", "h4");
    });
  });

  describe("uses correct class names", () => {
    it("uses Mobius class", () => {
      render(
        <Text elementType="h1" data-testid="test">
          Sample text
        </Text>,
      );
      expect(screen.getByTestId("test")).toHaveClass("mobius");
    });

    it("uses base Mobius class", () => {
      render(
        <Text elementType="h1" data-testid="test">
          Sample text
        </Text>,
      );
      expect(screen.getByTestId("test")).toHaveClass(CLASS_NAME);
    });

    it("includes custom class name", () => {
      render(
        <Text elementType="h1" className="my-class" data-testid="test">
          Sample text
        </Text>,
      );
      expect(screen.getByTestId("test")).toHaveClass("my-class");
      expect(screen.getByTestId("test")).toHaveClass(CLASS_NAME);
    });

    it.each([
      "h1",
      "h2",
      "h3",
      "h4",
      "body",
      "small",
      "legal",
      "title",
    ] as const)("applies --is-%s class", variant => {
      render(
        <Text variant={variant} data-testid="test">
          Sample text
        </Text>,
      );
      expect(screen.getByTestId("test")).toHaveClass(`--is-${variant}`);
    });

    it.each(["loose", "tight"] as const)(
      "applies --has-line-height-%s class",
      spacing => {
        render(
          <Text spacing={spacing} data-testid="test">
            Sample text
          </Text>,
        );
        expect(screen.getByTestId("test")).toHaveClass(
          `--has-line-height-${spacing}`,
        );
      },
    );
  });

  describe("semantic HTML", () => {
    it("renders a <p> element by default when no variant or elementType is provided", () => {
      const { container } = render(<Text>Default text</Text>);
      expect(container.firstChild?.nodeName).toBe("P");
    });

    it.each([
      ["h1", "H1"],
      ["h2", "H2"],
      ["h3", "H3"],
      ["h4", "H4"],
      ["p", "P"],
      ["span", "SPAN"],
    ] as const)(
      "renders <%s> when elementType='%s'",
      (elementType, expectedNodeName) => {
        const { container } = render(
          <Text elementType={elementType}>Text</Text>,
        );
        expect(container.firstChild?.nodeName).toBe(expectedNodeName);
      },
    );

    it("elementType controls the rendered element even when variant is set", () => {
      const { container } = render(
        <Text variant="h1" elementType="span">
          Text
        </Text>,
      );
      // elementType is always used as the rendered Component, regardless of variant
      expect(container.firstChild?.nodeName).toBe("SPAN");
    });

    it("infers element type from variant when no elementType is provided", () => {
      // h1-h4 variants render as their corresponding heading elements
      const { container } = render(<Text variant="h1">Heading text</Text>);
      expect(container.firstChild?.nodeName).toBe("H1");
    });
  });

  it("forwards ref", () => {
    const ref = createRef<HTMLParagraphElement>();
    render(<Text ref={ref}>Text</Text>);
    expect(ref.current).toBeInstanceOf(HTMLParagraphElement);
  });
});
