import React from "react";

import "@testing-library/jest-dom";
import userEvent from "@testing-library/user-event";
import { render, cleanup, fireEvent, screen } from "@testing-library/react";

import CheckGroup from "@ax/components/Fields/CheckGroup";
import { ThemeProvider } from "styled-components";
import globalTheme from "@ax/themes/theme.json";

import { parseTheme } from "@ax/helpers";

afterEach(cleanup);

const defaultProps = {
	value: "",
	options: [],
	onChange: jest.fn(),
};

const user = userEvent.setup();

describe("CheckField component rendering", () => {
	it("should render the component with no CheckField", () => {
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<CheckGroup {...defaultProps} />
			</ThemeProvider>,
		);

		expect(screen.findByTestId("check-group-field-group")).toBeTruthy();
	});

	it("should render the component with CheckField", async () => {
		const checkFieldOptions = [
			{
				name: "name 1",
				value: 1,
			},
			{
				name: "name 2",
				value: 2,
			},
		];
		const props = {
			value: "",
			options: checkFieldOptions,
			onChange: jest.fn(),
		};
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<CheckGroup {...props} />
			</ThemeProvider>,
		);

		expect(screen.findByTestId("check-group-field-group")).toBeTruthy();
		expect(await screen.findAllByTestId("check-field-label")).toHaveLength(2);
	});

	it("should render the component with CheckField and no value", async () => {
		const checkFieldOptions = [
			{
				name: "name 1",
				value: 1,
			},
			{
				name: "name 2",
				value: 2,
			},
		];
		const props = {
			value: undefined,
			options: checkFieldOptions,
			onChange: jest.fn(),
		};
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<CheckGroup {...props} />
			</ThemeProvider>,
		);

		expect(screen.findByTestId("check-group-field-group")).toBeTruthy();
		expect(await screen.findAllByTestId("check-field-label")).toHaveLength(2);
	});

	it("should render the component with CheckField and value null", async () => {
		const checkFieldOptions = [
			{
				name: "name 1",
				value: 1,
			},
			{
				name: "name 2",
				value: 2,
			},
		];
		const props = {
			value: null,
			options: checkFieldOptions,
			onChange: jest.fn(),
		};
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<CheckGroup {...props} />
			</ThemeProvider>,
		);

		expect(screen.findByTestId("check-group-field-group")).toBeTruthy();
		expect(await screen.findAllByTestId("check-field-label")).toHaveLength(2);
	});
});

describe("CheckField events", () => {
	it("should call the onchange", async () => {
		const checkFieldOptions = [
			{
				name: "name 1",
				value: 1,
			},
			{
				name: "name 2",
				value: 2,
			},
		];
		const onChangeMock = jest.fn();

		const props = {
			value: "",
			options: checkFieldOptions,
			onChange: onChangeMock,
		};

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<CheckGroup {...props} />
			</ThemeProvider>,
		);

		expect(screen.findByTestId("check-group-field-group")).toBeTruthy();
		expect(await screen.findAllByTestId("check-field-label")).toHaveLength(2);
		const checkFieldInput = await screen.queryAllByTestId<HTMLInputElement>("check-field-input");
		fireEvent.change(checkFieldInput[0], {
			target: { value: "name", checked: true },
		});
		expect(checkFieldInput[0].value).toBe("name");
		expect(checkFieldInput[0].checked).toBe(true);
	});

	it("should pass 'all' in the onchange call", async () => {
		const checkFieldOptions = [
			{
				name: "all",
				value: 1,
			},
			{
				name: "surname",
				value: 2,
			},
		];
		const onChangeMock = jest.fn();

		const props = {
			value: "",
			options: checkFieldOptions,
			onChange: onChangeMock,
		};

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<CheckGroup {...props} />
			</ThemeProvider>,
		);

		expect(await screen.findAllByTestId("check-field-label")).toHaveLength(2);
		const checkFieldInput = await screen.queryAllByTestId<HTMLInputElement>("check-field-input");
		fireEvent.change(checkFieldInput[0], {
			target: { value: "all", checked: true },
		});
		expect(checkFieldInput[0].value).toBe("all");
	});

	it("should pass 'all' selected in the onchange call when all options selected", async () => {
		const checkFieldOptions = [
			{
				name: "all",
				value: 1,
			},
			{
				name: "name",
				value: 2,
			},
			{
				name: "surname",
				value: 3,
			},
		];
		const onChangeMock = jest.fn();

		const props = {
			value: [],
			options: checkFieldOptions,
			selectAllOption: "all",
			onChange: onChangeMock,
		};

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<CheckGroup {...props} />
			</ThemeProvider>,
		);
		expect(await screen.findAllByTestId("check-field-label")).toHaveLength(3);
		const checkFieldInputs = await screen.queryAllByTestId("check-field-input");

		await user.type(checkFieldInputs[1], "name");
		await user.type(checkFieldInputs[2], "surname");

		expect(onChangeMock).toHaveBeenCalledTimes(2);
		expect(onChangeMock).toBeCalledWith(["all"]);
	});

	it("should pass two selected values in the onchange call", async () => {
		const checkFieldOptions = [
			{
				name: "all",
				value: 1,
			},
			{
				name: "name",
				value: 2,
			},
			{
				name: "surname",
				value: 3,
			},
			{
				name: "surname 2",
				value: 4,
			},
		];
		const onChangeMock = jest.fn();

		const props = {
			value: [],
			options: checkFieldOptions,
			selectAllOption: "all",
			onChange: onChangeMock,
		};

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<CheckGroup {...props} />
			</ThemeProvider>,
		);

		expect(await screen.findAllByTestId("check-field-label")).toHaveLength(4);

		const checkFieldInputs = await screen.queryAllByTestId("check-field-input");

		await user.type(checkFieldInputs[1], "name");
		expect(onChangeMock).toHaveBeenCalledTimes(1);
		expect(onChangeMock).toBeCalledWith(["name"]);

		await user.type(checkFieldInputs[2], "surname");
		expect(onChangeMock).toHaveBeenCalledTimes(2);
		expect(onChangeMock).toBeCalledWith(["name", "surname"]);
	});

	it("should return only one value in the onchange call", async () => {
		const checkFieldOptions = [
			{
				name: "all",
				value: 1,
			},
			{
				name: "name",
				value: 2,
			},
			{
				name: "surname",
				value: 3,
			},
			{
				name: "surname 2",
				value: 4,
			},
		];
		const onChangeMock = jest.fn();

		const props = {
			value: [],
			options: checkFieldOptions,
			multipleSelection: false,
			onChange: onChangeMock,
		};

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<CheckGroup {...props} />
			</ThemeProvider>,
		);

		expect(await screen.findAllByTestId("check-field-label")).toHaveLength(4);

		const checkFieldInputs = await screen.queryAllByTestId("check-field-input");
		await user.type(checkFieldInputs[1], "name");

		expect(onChangeMock).toHaveBeenCalledTimes(1);
		expect(onChangeMock).toBeCalledWith(["name"]);

		await user.type(checkFieldInputs[2], "surname");
		expect(onChangeMock).toHaveBeenCalledTimes(2);
		expect(onChangeMock).toBeCalledWith(["surname"]);
	});

	it("should pass two selected values in the onchange call and remove not valid default value", async () => {
		const checkFieldOptions = [
			{
				name: "all",
				value: 1,
			},
			{
				name: "name",
				value: 2,
			},
			{
				name: "surname",
				value: 3,
			},
			{
				name: "surname 2",
				value: 4,
			},
		];
		const onChangeMock = jest.fn();

		const props = {
			value: ["novalid"],
			options: checkFieldOptions,
			selectAllOption: "all",
			onChange: onChangeMock,
		};

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<CheckGroup {...props} />
			</ThemeProvider>,
		);

		const checkFieldInputs = await screen.queryAllByTestId("check-field-input");

		await user.type(checkFieldInputs[1], "name");
		await user.type(checkFieldInputs[2], "surname");
		expect(onChangeMock).toBeCalledWith(["name", "surname"]);
	});
});
