import * as React from "react";

import { ThemeProvider } from "styled-components";
import { render, cleanup, screen, fireEvent, act } from "@testing-library/react";
import { parseTheme } from "@ax/helpers";
import "@testing-library/jest-dom";
import userEvent from "@testing-library/user-event";

import SearchField, { ISearchFieldProps } from "@ax/components/SearchField";
import globalTheme from "@ax/themes/theme.json";

afterEach(cleanup);

describe("Search field component rendering", () => {
	it("should render the component opened", () => {
		const onChangeMock = jest.fn();
		const defaultProps: ISearchFieldProps = {
			onChange: onChangeMock,
		};

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

		const searchField = screen.getByTestId("search-field-wrapper");
		const iconSearchWrapper = screen.queryByTestId("icon-search-wrapper");
		const fieldWrapper = screen.getByTestId("field-wrapper");

		expect(searchField).toBeTruthy();
		expect(iconSearchWrapper).toBeFalsy();
		expect(fieldWrapper).toBeTruthy();
	});

	it("should render the component opened with placeholder", () => {
		const onChangeMock = jest.fn();
		const defaultProps: ISearchFieldProps = {
			onChange: onChangeMock,
			placeholder: "Search",
		};

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

		const searchField = screen.getByTestId("search-field-wrapper");
		const iconSearchWrapper = screen.queryByTestId("icon-search-wrapper");
		const fieldWrapper = screen.getByTestId("field-wrapper");
		const placeholderText = screen.queryByPlaceholderText(/Search/i);

		expect(searchField).toBeTruthy();
		expect(iconSearchWrapper).toBeFalsy();
		expect(fieldWrapper).toBeTruthy();
		expect(placeholderText).toBeTruthy();
	});

	it("should render the component closed", () => {
		const onChangeMock = jest.fn();
		const defaultProps: ISearchFieldProps = {
			onChange: onChangeMock,
			closeOnInactive: true,
		};

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

		const searchField = screen.getByTestId("search-field-wrapper");
		const iconSearchWrapper = screen.getByTestId("icon-search-wrapper");
		const fieldWrapper = screen.queryByTestId("field-wrapper");

		expect(searchField).toBeTruthy();
		expect(iconSearchWrapper).toBeTruthy();
		expect(fieldWrapper).toBeFalsy();
	});

	it("should render the component disabled", () => {
		const onChangeMock = jest.fn();
		const defaultProps: ISearchFieldProps = {
			onChange: onChangeMock,
			closeOnInactive: false,
			disabled: true,
		};

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

		const input = screen.getByTestId("search-input");
		expect(input).toBeDisabled();
	});
});

describe("Search field filters", () => {
	it("should render the component with search filters", () => {
		const onChangeMock = jest.fn();

		const searchFilters = [
			{ value: "filterby", label: "Filter by" },
			{ value: "from", label: "Old URL" },
			{ value: "to", label: "New URL" },
		];

		const defaultProps: ISearchFieldProps = {
			onChange: onChangeMock,
			searchFilters,
		};

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

		const searchField = screen.getByTestId("search-field-wrapper");
		const iconSearchWrapper = screen.queryByTestId("icon-search-wrapper");
		const fieldWrapper = screen.getByTestId("field-wrapper");
		const filterWrapper = screen.queryByTestId("filter-wrapper");

		expect(searchField).toBeTruthy();
		expect(iconSearchWrapper).toBeFalsy();
		expect(fieldWrapper).toBeTruthy();
		expect(filterWrapper).toBeTruthy();
	});

	it("should call onFilterChange when selecting option", async () => {
		const onChangeMock = jest.fn();
		const onFilterChangeMock = jest.fn();

		const searchFilters = [
			{ value: "filterby", label: "Filter by" },
			{ value: "from", label: "Old URL" },
			{ value: "to", label: "New URL" },
		];

		const defaultProps: ISearchFieldProps = {
			onChange: onChangeMock,
			searchFilters,
			onFilterChange: onFilterChangeMock,
		};

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

		const filterWrapper = screen.queryByTestId("filter-wrapper");
		expect(filterWrapper).toBeTruthy();

		await act(async () => userEvent.click(screen.getByLabelText("filterSelect")));

		const selectedItem = screen.getByText("Old URL");
		await act(async () => userEvent.click(selectedItem));

		expect(onFilterChangeMock).toBeCalledTimes(1);
		expect(screen.getByText("Old URL")).toBeInTheDocument();
	});
});

describe("search field events", () => {
	it("should open on icon search click and show field and close icon", () => {
		const onChangeMock = jest.fn();
		const defaultProps: ISearchFieldProps = {
			onChange: onChangeMock,
			closeOnInactive: true,
		};

		const { rerender } = render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const searchField = screen.getByTestId("search-field-wrapper");
		const iconSearchWrapper = screen.queryByTestId("icon-search-wrapper");
		const fieldWrapper = screen.queryByTestId("field-wrapper");

		expect(searchField).toBeTruthy();
		expect(iconSearchWrapper).toBeTruthy();
		expect(fieldWrapper).toBeFalsy();

		fireEvent.click(screen.getByTestId("icon-search-wrapper"));

		rerender(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const iconSearchWrapper2 = screen.queryByTestId("icon-search-wrapper");
		const iconCloseWrapper = screen.queryByTestId("icon-close-wrapper");
		const fieldWrapper2 = screen.queryByTestId("field-wrapper");
		expect(fieldWrapper2).toBeTruthy();
		expect(iconSearchWrapper2).toBeFalsy();
		expect(iconCloseWrapper).toBeTruthy();
	});

	it("should close and clear on close icon click and hide field and search icon if closeOnActive", () => {
		const onChangeMock = jest.fn();
		const defaultProps: ISearchFieldProps = {
			onChange: onChangeMock,
			closeOnInactive: true,
		};

		const { rerender } = render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const iconSearchWrapper = screen.getByTestId("icon-search-wrapper");
		expect(iconSearchWrapper).toBeTruthy();
		fireEvent.click(iconSearchWrapper);

		rerender(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const closeButton = screen.getByTestId("button-minimal");
		expect(closeButton).toBeTruthy();
		fireEvent.click(closeButton);

		rerender(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const iconSearchWrapper2 = screen.queryByTestId("icon-search-wrapper");
		const iconCloseWrapper2 = screen.queryByTestId("icon-close-wrapper");
		const fieldWrapper = screen.queryByTestId("field-wrapper");
		expect(fieldWrapper).toBeFalsy();
		expect(iconSearchWrapper2).toBeTruthy();
		expect(iconCloseWrapper2).toBeFalsy();
		expect(onChangeMock).toBeCalledTimes(1);
	});

	it("should clear and not close on close icon click if not closeOnActive and input is not empty", () => {
		const onChangeMock = jest.fn();
		const defaultProps: ISearchFieldProps = {
			onChange: onChangeMock,
			closeOnInactive: false,
		};

		const { rerender } = render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const input = screen.getByTestId("search-input");
		fireEvent.change(input, { target: { value: "prueba" } });
		const closeButton = screen.getByTestId("button-minimal");
		expect(closeButton).toBeTruthy();
		fireEvent.click(closeButton);

		rerender(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const iconSearchWrapper = screen.queryByTestId("icon-search-wrapper-2");
		const iconCloseWrapper2 = screen.queryByTestId("icon-close-wrapper");
		const fieldWrapper = screen.queryByTestId("field-wrapper");
		expect(fieldWrapper).toBeTruthy();
		expect(iconSearchWrapper).toBeTruthy();
		expect(iconCloseWrapper2).toBeFalsy();
		expect(onChangeMock).toBeCalledTimes(1);
	});

	it("show press enter on input type", () => {
		const onChangeMock = jest.fn();
		const defaultProps: ISearchFieldProps = {
			onChange: onChangeMock,
			closeOnInactive: true,
			searchOnEnter: true,
		};

		const { rerender } = render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const iconSearchWrapper = screen.getByTestId("icon-search-wrapper");
		expect(iconSearchWrapper).toBeTruthy();
		fireEvent.click(iconSearchWrapper);

		rerender(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const fieldWrapper = screen.getByTestId("field-wrapper");
		const input = screen.getByTestId("search-input");
		expect(fieldWrapper).toBeTruthy();
		fireEvent.change(input, { target: { value: "prueba" } });
		expect(screen.queryByText("Press ENTER")).toBeTruthy();
	});

	it("should call onchange on input type", () => {
		const onChangeMock = jest.fn();
		const defaultProps: ISearchFieldProps = {
			onChange: onChangeMock,
			closeOnInactive: true,
			searchOnEnter: false,
		};

		const { rerender } = render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const iconSearchWrapper = screen.getByTestId("icon-search-wrapper");
		expect(iconSearchWrapper).toBeTruthy();
		fireEvent.click(iconSearchWrapper);

		rerender(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const fieldWrapper = screen.getByTestId("field-wrapper");
		const input = screen.getByTestId("search-input");
		expect(fieldWrapper).toBeTruthy();
		fireEvent.change(input, { target: { value: "a" } });
		expect(onChangeMock).toBeCalledTimes(1);
	});

	it("should call onchange on key enter", () => {
		const onChangeMock = jest.fn();
		const defaultProps: ISearchFieldProps = {
			onChange: onChangeMock,
			closeOnInactive: true,
			searchOnEnter: true,
		};

		const { rerender } = render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const iconSearchWrapper = screen.getByTestId("icon-search-wrapper");
		expect(iconSearchWrapper).toBeTruthy();
		fireEvent.click(iconSearchWrapper);

		rerender(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SearchField {...defaultProps} />
			</ThemeProvider>,
		);

		const fieldWrapper = screen.getByTestId("field-wrapper");
		const input = screen.getByTestId("search-input");
		expect(fieldWrapper).toBeTruthy();
		fireEvent.change(input, { target: { value: "prueba" } });
		fireEvent.keyDown(input, { key: "Enter", code: "Enter", charCode: 13 });
		expect(onChangeMock).toBeCalledTimes(1);
	});
});
