import { render, screen, cleanup } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import assert from "node:assert";
import {
  describe, test, mock, afterEach, 
} from "node:test";
import { Label } from "./index";

describe("Label", () => {
  afterEach(() => {
    cleanup();
  });

  /* COMMON */

  test("renders without crashing", () => {
    render(<Label />);
    const label = document.querySelector("label");
    assert.notStrictEqual(label, null);
  });

  test("renders label text", () => {
    render(<Label label={"Username"} />);
    assert.notStrictEqual(screen.queryByText("Username"), null);
  });

  test("renders children instead of label", () => {
    render(
      <Label label={"Should not appear"}>
        <span data-testid={"child"}>Custom content</span>
      </Label>
    );

    assert.notStrictEqual(screen.queryByTestId("child"), null);
    assert.strictEqual(screen.queryByText("Should not appear"), null);
  });

  test("passes htmlFor attribute", () => {
    render(<Label htmlFor={"username-input"} />);
    const label = document.querySelector("label");
    assert.strictEqual(label?.getAttribute("for"), "username-input");
  });

  test("passes title attribute", () => {
    render(<Label title={"Field label"} />);
    const label = document.querySelector("label");
    assert.strictEqual(label?.getAttribute("title"), "Field label");
  });

  test("passes extra attributes", () => {
    render(
      <Label
        extraAttrs={{
          "data-testid": "custom-label",
          "aria-label": "Username field",
        }}
      />
    );

    const label = document.querySelector("label");
    assert.strictEqual(label?.getAttribute("data-testid"), "custom-label");
    assert.strictEqual(label?.getAttribute("aria-label"), "Username field");
  });

  test("applies base class", () => {
    render(<Label baseClass={"customLabel"} />);
    const label = document.querySelector("label");
    assert.strictEqual(label?.className.includes("customLabel"), true);
  });

  test("applies extra classes", () => {
    render(
      <Label
        extraClasses={{
          large: true,
          bold: true,
          hidden: false,
        }}
      />
    );

    const label = document.querySelector("label");
    const classNames = label?.className || "";
    assert.strictEqual(classNames.includes("large"), true);
    assert.strictEqual(classNames.includes("bold"), true);
    assert.strictEqual(classNames.includes("hidden"), false);
  });

  /* REQUIRED STATE */

  test("shows isRequired modifier when isRequired=true", () => {
    render(<Label isRequired={true} />);
    const label = document.querySelector("label");
    assert.strictEqual(label?.className.includes("isRequired"), true);
  });

  test("does not show isRequired modifier when isRequired=false", () => {
    render(<Label isRequired={false} />);
    const label = document.querySelector("label");
    assert.strictEqual(label?.className.includes("isRequired"), false);
  });

  test("updates isRequired modifier when prop changes", () => {
    const { rerender } = render(<Label isRequired={false} />);
    let label = document.querySelector("label");
    assert.strictEqual(label?.className.includes("isRequired"), false);

    rerender(<Label isRequired={true} />);
    label = document.querySelector("label");
    assert.strictEqual(label?.className.includes("isRequired"), true);
  });

  /* INTERACTIONS */

  test("calls onClick when clicked", async () => {
    const onClick = mock.fn();
    const user = userEvent.setup();

    render(<Label onClick={onClick} label={"Click me"} />);
    await user.click(screen.getByText("Click me"));

    assert.strictEqual(onClick.mock.calls.length, 1);
  });

  /* INTEGRATION */

  test("focuses associated input when clicked", async () => {
    const user = userEvent.setup();

    render(
      <>
        <Label htmlFor={"test-input"} label={"Test field"} />
        <input id={"test-input"} data-testid={"test-input"} />
      </>
    );

    await user.click(screen.getByText("Test field"));
    const input = screen.getByTestId("test-input");
    assert.strictEqual(document.activeElement, input);
  });

  /* EDGE CASES */

  test("handles empty label", () => {
    render(<Label label={""} />);
    const span = document.querySelector("span");
    assert.strictEqual(span?.textContent, "");
  });

  test("handles no props", () => {
    render(<Label />);
    const label = document.querySelector("label");
    assert.notStrictEqual(label, null);
    const span = document.querySelector("span");
    assert.notStrictEqual(span, null);
  });

  test("handles long text", () => {
    const longText = "Very long label text that should still render properly without any issues or truncation";
    render(<Label label={longText} />);
    assert.notStrictEqual(screen.queryByText(longText), null);
  });
});