import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { TextArea } from ".";

const CLASS_NAME = "mobius-text-area";

describe("TextArea", () => {
  it("should render without error", () => {
    const view = render(<TextArea label="First name" />);
    expect(view).toBeTruthy();
  });

  it("should call onChange with the updated value when the user types", async () => {
    const callback = vi.fn();
    const { getByLabelText } = render(
      <TextArea label="First name" onChange={callback} />,
    );
    await userEvent.type(getByLabelText("First name"), "John");
    expect(callback).toHaveBeenCalledWith(
      expect.objectContaining({
        target: screen.getByLabelText("First name"),
      }),
    );
  });

  it("focuses correctly via keyboard", async () => {
    const callbackFirstName = vi.fn();
    const callbackLastName = vi.fn();
    render(
      <>
        <TextArea label="First name" onChange={callbackFirstName} />
        <TextArea label="Last name" onChange={callbackLastName} />
      </>,
    );
    await userEvent.tab();
    await userEvent.type(document.activeElement!, "John");
    expect(callbackFirstName).toHaveBeenCalledWith(
      expect.objectContaining({
        target: screen.getByLabelText("First name"),
      }),
    );

    await userEvent.tab();
    await userEvent.type(document.activeElement!, "Doe");
    expect(callbackLastName).toHaveBeenCalledWith(
      expect.objectContaining({
        target: screen.getByLabelText("Last name"),
      }),
    );
  });

  describe("with errors", () => {
    it("should render the error", () => {
      const { getByText } = render(
        <TextArea label="Message" name="message" errorMessage="Required" />,
      );
      expect(getByText("Required")).toBeInTheDocument();
    });

    it("should set aria-invalid to true", () => {
      const { getByLabelText } = render(
        <TextArea label="Message" name="message" errorMessage="Required" />,
      );
      expect(getByLabelText("Message")).toHaveAccessibleDescription("Required");
    });

    it("should set the correct aria-describedby attribute", () => {
      const { getByLabelText } = render(
        <TextArea label="Message" name="message" errorMessage="Required" />,
      );
      expect(getByLabelText("Message")).toHaveAccessibleDescription("Required");
    });
  });

  describe("uses correct class names", () => {
    it("uses Mobius class", () => {
      render(<TextArea label="Test" data-testid="test" />);
      expect(screen.getByTestId("test").closest("div")).toHaveClass("mobius");
    });

    it("uses base Mobius class", () => {
      render(<TextArea label="Test" data-testid="test" />);
      expect(screen.getByTestId("test").closest("div")).toHaveClass(CLASS_NAME);
    });

    it("includes custom class name", () => {
      render(
        <TextArea
          label="Message"
          name="message"
          data-testid="test"
          className="my-class"
        />,
      );
      expect(screen.getByTestId("test").closest("div")).toHaveClass("my-class");
      expect(screen.getByTestId("test").closest("div")).toHaveClass(CLASS_NAME);
    });

    it("includes disabled class name", () => {
      render(<TextArea label="Test" data-testid="test" isDisabled />);
      expect(screen.getByTestId("test")).toHaveClass("--is-disabled");
    });

    it("includes valid class name", () => {
      render(<TextArea label="Test" data-testid="test" isInvalid={false} />);
      expect(screen.getByTestId("test")).toHaveClass("--is-valid");
    });

    it("includes invalid class name", () => {
      render(<TextArea label="Test" data-testid="test" isInvalid />);
      expect(screen.getByTestId("test")).toHaveClass("--is-invalid");
    });
  });

  describe("when disabled", () => {
    it("has disabled attribute set on textarea field", () => {
      render(<TextArea label="Test" data-testid="test" isDisabled />);
      expect(screen.getByTestId("test")).toBeDisabled();
    });
  });
});
