import { render, screen, cleanup } from "@testing-library/react";
import assert from "node:assert";
import { describe, test, afterEach } from "node:test";
import { getStrWithSpaces } from "./lib";
import { FormatText } from "./index";

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

  /* PLAIN TEXT */

  test("adds non-breaking spaces after short words", () => {
    render(<FormatText>в лесу родилась ёлочка</FormatText>);
    const text = screen.getByText(/в/u);
    assert.strictEqual(text.textContent, "в\u00A0лесу родилась ёлочка");
  });

  test("handles English short words", () => {
    render(<FormatText>a cat and a dog</FormatText>);
    const text = screen.getByText(/a/u);
    assert.strictEqual(text.textContent, "a\u00A0cat\u00A0and\u00A0a\u00A0dog");
  });

  test("handles numbers", () => {
    render(<FormatText>в 2024 году</FormatText>);
    const text = screen.getByText(/в/u);
    assert.strictEqual(text.textContent, "в\u00A02024 году");
  });

  /* DASHES */

  test("replaces hyphens with em dash", () => {
    render(<FormatText>Москва - столица</FormatText>);
    const text = screen.getByText(/Москва/u);
    assert.strictEqual(text.textContent, "Москва\u00A0—\u00A0столица");
  });

  /* WHITESPACE */

  test("collapses multiple spaces", () => {
    const result = getStrWithSpaces("много    пробелов");
    assert.strictEqual(result, "много пробелов");
  });

  test("handles tabs and newlines", () => {
    const result = getStrWithSpaces("много\tпробелов\nи строк");
    assert.strictEqual(result, "много пробелов\u00A0и\u00A0строк");
  });

  test("adds non-breaking spaces after short words with multiple spaces", () => {
    const result = getStrWithSpaces("много    пробелов и    строк");
    assert.strictEqual(result, "много пробелов\u00A0и\u00A0строк");
  });

  /* CHILDREN TYPES */

  test("handles React elements", () => {
    render(
      <FormatText>
        <span data-testid={"element"}>в лесу</span>
      </FormatText>
    );
    assert.strictEqual(screen.getByTestId("element").textContent, "в\u00A0лесу");
  });

  test("handles nested elements", () => {
    render(
      <FormatText>
        <div>
          <span data-testid={"nested"}>и в поле</span>
        </div>
      </FormatText>
    );
    assert.strictEqual(screen.getByTestId("nested").textContent, "и\u00A0в\u00A0поле");
  });

  test("handles Fragments", () => {
    render(
      <FormatText>
        <>
          <span data-testid={"fragment"}>в лесу</span>
        </>
      </FormatText>
    );
    assert.strictEqual(screen.getByTestId("fragment").textContent, "в\u00A0лесу");
  });

  test("handles arrays of children", () => {
    render(
      <FormatText>
        {[ "в ", <strong key={"1"}>лесу</strong> ]}
      </FormatText>
    );
    const strong = document.querySelector("strong");
    assert.strictEqual(strong?.textContent, "лесу");
  });

  /* COMPONENTS */

  test("handles functional components", () => {
    const TestComponent = ({ children }: { children: string; }) => (
      <span data-testid={"comp"}>{children}</span>
    );
    render(
      <FormatText>
        <TestComponent>в лесу</TestComponent>
      </FormatText>
    );
    assert.strictEqual(screen.getByTestId("comp").textContent, "в\u00A0лесу");
  });

  test("handles components with props", () => {
    const TestComponent = ({ text }: { text: string; }) => (
      <span data-testid={"comp"}>{text}</span>
    );
    render(
      <FormatText>
        <TestComponent text={"в лесу"} />
      </FormatText>
    );
    assert.strictEqual(screen.getByTestId("comp").textContent, "в\u00A0лесу");
  });

  /* PUNCTUATION */

  test("preserves punctuation", () => {
    render(<FormatText>в лесу, в поле!</FormatText>);
    const text = screen.getByText(/в/u);
    assert.strictEqual(text.textContent, "в\u00A0лесу,\u00A0в\u00A0поле!");
  });

  /* EDGE CASES */

  test("handles empty and falsy values", () => {
    const { container } = render(
      <>
        <FormatText>{""}</FormatText>
        <FormatText>{null}</FormatText>
        <FormatText>{undefined}</FormatText>
        <FormatText />
      </>
    );
    assert.notStrictEqual(container, null);
  });

  /* MIXED CONTENT */

  test("handles mixed text and elements", () => {
    render(
      <FormatText>
        в лесу <strong>родилась</strong> ёлочка
      </FormatText>
    );
    const strong = document.querySelector("strong");
    assert.strictEqual(strong?.textContent, "родилась");
    const text = document.body.textContent;
    assert.strictEqual(text?.includes("в\u00A0лесу"), true);
    assert.strictEqual(text?.includes("ёлочка"), true);
  });
});
