import { MattrixwvCheckbox } from "$/index";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";


describe("Renders", () => {
	it("Renders with default properties", () => {
		render(<MattrixwvCheckbox/>);

		//Checkbox
		const checkbox = screen.getByTestId("mattrixwv-checkbox");
		expect(checkbox).toBeInTheDocument();
		expect(checkbox.id).toMatch(/_r_\d+/);
		expect(checkbox).toHaveClass("group");
		expect(checkbox).toHaveClass("focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2");
		expect(checkbox).toHaveClass("cursor-pointer");
		expect(checkbox).not.toHaveAttribute("data-disabled");
		expect(checkbox).not.toBeChecked();

		//Visible checkbox
		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkboxGraphic).toBeInTheDocument();
		expect(checkboxGraphic).toHaveClass("border", "rounded");
		expect(checkboxGraphic).toHaveClass("size-4");

		//Label
		const label = screen.queryByTestId("mattrixwv-checkbox-label");
		expect(label).not.toBeInTheDocument();
	});

	it("Renders with default properties with custom name and class name", () => {
		const className = "my-class-name";
		const name = "my-name";

		render(
			<MattrixwvCheckbox
				className={className}
				name={name}
			/>
		);

		//Checkbox
		const checkbox = screen.getByTestId("mattrixwv-checkbox");
		expect(checkbox).toBeInTheDocument();
		expect(checkbox).toHaveClass("group");
		expect(checkbox).toHaveClass("focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2");
		expect(checkbox).toHaveClass("cursor-pointer");
		expect(checkbox).not.toBeChecked();
		expect(checkbox).not.toHaveAttribute("aria-labelledby");

		//Visible checkbox
		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkbox).toContain(checkboxGraphic);
		expect(checkboxGraphic).toBeInTheDocument();
		expect(checkboxGraphic).toHaveClass("border", "rounded");
		expect(checkboxGraphic).toHaveClass("size-4");
		expect(checkboxGraphic).toHaveClass(className);

		//Label
		const label = screen.queryByTestId("mattrixwv-checkbox-label");
		expect(label).not.toBeInTheDocument();
	});
	it("Renders with default properties disabled", () => {
		render(<MattrixwvCheckbox disabled/>);

		//Checkbox
		const checkbox = screen.getByTestId("mattrixwv-checkbox");
		expect(checkbox).toBeInTheDocument();
		expect(checkbox.id).toMatch(/_r_\d+/);
		expect(checkbox).toHaveClass("group");
		expect(checkbox).toHaveClass("focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2");
		expect(checkbox).toHaveClass("cursor-not-allowed");
		expect(checkbox).toHaveAttribute("data-disabled");
		expect(checkbox).not.toBeChecked();

		//Visible checkbox
		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkbox).toContain(checkboxGraphic);
		expect(checkboxGraphic).toBeInTheDocument();
		expect(checkboxGraphic).toHaveClass("border", "rounded");
		expect(checkboxGraphic).toHaveClass("size-4");

		//Label
		const label = screen.queryByTestId("mattrixwv-checkbox-label");
		expect(label).not.toBeInTheDocument();
	});
});

describe("Checkbox", () => {
	it("Renders with box", () => {
		render(<MattrixwvCheckbox showBox={true}/>);

		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkboxGraphic).toHaveClass("border", "rounded");
	});

	it("Renders without box", () => {
		render(<MattrixwvCheckbox showBox={false}/>);

		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkboxGraphic).not.toHaveClass("border", "rounded");
	});
});

describe("Size", () => {
	it("Renders with no size", () => {
		render(<MattrixwvCheckbox size="none"/>);

		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkboxGraphic).toHaveClass("border", "rounded");
		expect(checkboxGraphic.className).not.toMatch(/size*/);
	});
	it("Renders with extra-small size", () => {
		render(<MattrixwvCheckbox size="xs"/>);

		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkboxGraphic).toHaveClass("border", "rounded");
		expect(checkboxGraphic).toHaveClass("size-3");
	});
	it("Renders with small size", () => {
		render(<MattrixwvCheckbox size="sm"/>);

		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkboxGraphic).toHaveClass("border", "rounded");
		expect(checkboxGraphic).toHaveClass("size-4");
	});
	it("Renders with medium size", () => {
		render(<MattrixwvCheckbox size="md"/>);

		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkboxGraphic).toHaveClass("border", "rounded");
		expect(checkboxGraphic).toHaveClass("size-5");
	});
	it("Renders with large size", () => {
		render(<MattrixwvCheckbox size="lg"/>);

		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkboxGraphic).toHaveClass("border", "rounded");
		expect(checkboxGraphic).toHaveClass("size-6");
	});
	it("Renders with extra-large size", () => {
		render(<MattrixwvCheckbox size="xl"/>);

		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkboxGraphic).toHaveClass("border", "rounded");
		expect(checkboxGraphic).toHaveClass("size-7");
	});
});

describe("Label", () => {
	it("Renders with label", () => {
		const textContent = "Text";

		render(<MattrixwvCheckbox>{textContent}</MattrixwvCheckbox>);

		const checkbox = screen.getByTestId("mattrixwv-checkbox");
		expect(checkbox).toBeInTheDocument();
		expect(checkbox).toHaveAttribute("aria-labelledby");

		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkbox).toContain(checkboxGraphic);
		expect(checkboxGraphic).toBeInTheDocument();

		const checkboxLabel = screen.getByTestId("mattrixwv-checkbox-label");
		expect(checkbox).toAppearBefore(checkboxLabel);
		expect(checkboxLabel.id).toMatch(/headlessui-label-_r_.+_/);
		expect(checkboxLabel).toHaveTextContent(textContent);
	});

	it("Renders with label classes", () => {
		const textContent = "Text";
		const className = "custom-class-name";

		render(<MattrixwvCheckbox labelClassName={className}>{textContent}</MattrixwvCheckbox>);

		const checkbox = screen.getByTestId("mattrixwv-checkbox");
		expect(checkbox).toBeInTheDocument();
		expect(checkbox).toHaveAttribute("aria-labelledby");

		const checkboxGraphic = screen.getByTestId("mattrixwv-checkbox-graphic");
		expect(checkbox).toContain(checkboxGraphic);
		expect(checkboxGraphic).toBeInTheDocument();

		const checkboxLabel = screen.getByTestId("mattrixwv-checkbox-label");
		expect(checkbox).toAppearBefore(checkboxLabel);
		expect(checkboxLabel.id).toMatch(/headlessui-label-_r_.+_/);
		expect(checkboxLabel).toHaveClass(className);
		expect(checkboxLabel).toHaveTextContent(textContent);
	});
});

describe("Checking", () => {
	it("Renders checked", async () => {
		render(<MattrixwvCheckbox checked/>);

		const checkbox = screen.getByTestId("mattrixwv-checkbox");
		expect(checkbox).toBeInTheDocument();
		expect(checkbox).toBeChecked();

		await userEvent.click(checkbox);
		expect(checkbox).toBeChecked();
	});
	it("Renders default checked", async () => {
		render(<MattrixwvCheckbox defaultChecked/>);

		const checkbox = screen.getByTestId("mattrixwv-checkbox");
		expect(checkbox).toBeInTheDocument();
		expect(checkbox).toBeChecked();

		await userEvent.click(checkbox);
		expect(checkbox).not.toBeChecked();
	});
	it("Handles changes", async () => {
		const label = "Some label";
		const handleClick = vi.fn();

		render(<MattrixwvCheckbox onChange={handleClick}>{label}</MattrixwvCheckbox>);

		const checkbox = screen.getByTestId("mattrixwv-checkbox");
		expect(checkbox).toBeInTheDocument();
		expect(checkbox).not.toBeChecked();
		expect(handleClick).toHaveBeenCalledTimes(0);

		await userEvent.click(checkbox);
		expect(checkbox).toBeChecked();
		expect(handleClick).toHaveBeenCalledTimes(1);

		const checkboxLabel = screen.getByTestId("mattrixwv-checkbox-label");
		expect(checkboxLabel).toBeInTheDocument();
		await userEvent.click(checkboxLabel);
		expect(checkbox).not.toBeChecked();
		expect(handleClick).toHaveBeenCalledTimes(2);
	});
});
