import * as React from "react";
import axios from "axios";

import { ThemeProvider } from "styled-components";
import { CalledWithMock, mock } from "jest-mock-extended";
import { render, screen, cleanup, act, fireEvent } from "@testing-library/react";

import { parseTheme } from "@ax/helpers";
import SiteFilter, { ISiteFilterProps } from "@ax/components/TableFilters/SiteFilter";
import globalTheme from "@ax/themes/theme.json";
import { IQueryValue } from "@ax/types";

afterEach(cleanup);
jest.mock("axios");
const mockedAxios = axios as jest.MockedFunction<typeof axios>;
const defaultProps = mock<ISiteFilterProps>();

describe("SiteFilter component rendering", () => {
	it("should render site filter with label", async () => {
		defaultProps.value = { order: "", filterSites: "noFilter" };
		defaultProps.pointer = "filterSites";
		defaultProps.center = true;
		defaultProps.label = "Site";
		defaultProps.selectAllOption = "noFilter";
		defaultProps.filters = [
			{
				name: "all",
				value: "all",
				title: "All",
			},
		];
		const filterItems = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;

		defaultProps.filterItems = filterItems;
		const data = {
			data: [
				{ value: 1, label: "Site 1" },
				{ value: 2, label: "Site 2" },
				{ value: 3, label: "Site 3" },
				{ value: 4, label: "Site 4" },
				{ value: 5, label: "Site 5" },
			],
			status: 200,
			statusText: "Ok",
			headers: {},
			config: {},
		};

		mockedAxios.mockResolvedValue(data);

		await act(async () => {
			render(
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<SiteFilter {...defaultProps} />
				</ThemeProvider>,
			);
		});

		const siteFilter = screen.getByTestId("floating-menu");
		expect(siteFilter).toBeTruthy();
		expect(siteFilter.textContent).toEqual("Site");
	});

	it("should render the component with no options", async () => {
		defaultProps.value = { order: "", filterSites: "noFilter" };
		defaultProps.pointer = "filterSites";
		defaultProps.center = true;
		defaultProps.label = "Site";
		defaultProps.selectAllOption = "noFilter";
		defaultProps.filters = [
			{
				name: "all",
				value: "all",
				title: "All",
			},
		];
		const filterItems = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;

		defaultProps.filterItems = filterItems;

		const data = {
			data: [],
			status: 500,
			statusText: "Internal Server Error",
			headers: {},
			config: {},
		};

		mockedAxios.mockResolvedValue(data);

		await act(async () => {
			render(
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<SiteFilter {...defaultProps} />
				</ThemeProvider>,
			);
		});

		const siteFilterButton = screen.getByTestId("floating-menu-button");
		expect(siteFilterButton).toBeTruthy();
		fireEvent.click(siteFilterButton);
		const floatingMenu = screen.getByTestId("floating-menu");
		expect(floatingMenu).toBeTruthy();
		const checkGroupFieldGroup = screen.getByTestId("check-group-field-group");
		expect(checkGroupFieldGroup).toBeTruthy();
		const checkFieldInputs = screen.getAllByTestId<HTMLInputElement>("check-field-input");
		expect(checkFieldInputs).toHaveLength(1);
	});
});

describe("SiteFilter events", () => {
	it("should render check group on click", async () => {
		defaultProps.value = { order: "", filterSites: "noFilter" };
		defaultProps.pointer = "filterSites";
		defaultProps.center = true;
		defaultProps.label = "Site";
		defaultProps.selectAllOption = "noFilter";
		defaultProps.filters = [
			{
				name: "all",
				value: "all",
				title: "All",
			},
		];
		const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;

		defaultProps.filterItems = filterItemsMock;
		const data = {
			data: [
				{ value: 1, label: "Site 1" },
				{ value: 2, label: "Site 2" },
				{ value: 3, label: "Site 3" },
				{ value: 4, label: "Site 4" },
				{ value: 5, label: "Site 5" },
			],
			status: 200,
			statusText: "Ok",
			headers: {},
			config: {},
		};
		mockedAxios.mockResolvedValue(data);

		await act(async () => {
			render(
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<SiteFilter {...defaultProps} />
				</ThemeProvider>,
			);
		});

		const siteFilterButton = screen.getByTestId("floating-menu-button");
		expect(siteFilterButton).toBeTruthy();
		fireEvent.click(siteFilterButton);
		const floatingMenu = screen.getByTestId("floating-menu");
		expect(floatingMenu).toBeTruthy();
		const checkGroupFieldGroup = screen.getByTestId("check-group-field-group");
		expect(checkGroupFieldGroup).toBeTruthy();
		const checkFieldLabels = screen.getAllByTestId("check-field-label");
		expect(checkFieldLabels).toHaveLength(6);
	});

	it("should check option on click", async () => {
		defaultProps.value = { order: "", filterSites: "noFilter" };
		defaultProps.pointer = "filterSites";
		defaultProps.center = true;
		defaultProps.label = "Site";
		defaultProps.selectAllOption = "noFilter";
		defaultProps.filters = [
			{
				name: "all",
				value: "all",
				title: "All",
			},
		];
		const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;

		defaultProps.filterItems = filterItemsMock;
		const data = {
			data: [
				{ value: 1, label: "Site 1" },
				{ value: 2, label: "Site 2" },
				{ value: 3, label: "Site 3" },
				{ value: 4, label: "Site 4" },
				{ value: 5, label: "Site 5" },
			],
			status: 200,
			statusText: "Ok",
			headers: {},
			config: {},
		};

		mockedAxios.mockResolvedValue(data);

		await act(async () => {
			render(
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<SiteFilter {...defaultProps} />
				</ThemeProvider>,
			);
		});

		const siteFilterButton = screen.getByTestId("floating-menu-button");
		expect(siteFilterButton).toBeTruthy();
		fireEvent.click(siteFilterButton);
		const floatingMenu = screen.getByTestId("floating-menu");
		expect(floatingMenu).toBeTruthy();
		const checkGroupFieldGroup = screen.getByTestId("check-group-field-group");
		expect(checkGroupFieldGroup).toBeTruthy();
		const checkFieldInputs = screen.getAllByTestId<HTMLInputElement>("check-field-input");
		expect(checkFieldInputs).toHaveLength(6);
		fireEvent.click(checkFieldInputs[1]);
		expect(checkFieldInputs[1].checked).toBe(true);
	});

	it("should uncheck checked option on click", async () => {
		defaultProps.value = { order: "", filterSites: "noFilter" };
		defaultProps.pointer = "filterSites";
		defaultProps.center = true;
		defaultProps.label = "Site";
		defaultProps.selectAllOption = "noFilter";
		defaultProps.filters = [
			{
				name: "all",
				value: "all",
				title: "All",
			},
		];
		const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;

		defaultProps.filterItems = filterItemsMock;
		const data = {
			data: [
				{ value: 1, label: "Site 1" },
				{ value: 2, label: "Site 2" },
				{ value: 3, label: "Site 3" },
				{ value: 4, label: "Site 4" },
				{ value: 5, label: "Site 5" },
			],
			status: 200,
			statusText: "Ok",
			headers: {},
			config: {},
		};

		mockedAxios.mockResolvedValue(data);

		await act(async () => {
			render(
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<SiteFilter {...defaultProps} />
				</ThemeProvider>,
			);
		});

		const siteFilterButton = screen.getByTestId("floating-menu-button");
		expect(siteFilterButton).toBeTruthy();
		fireEvent.click(siteFilterButton);
		const floatingMenu = screen.getByTestId("floating-menu");
		expect(floatingMenu).toBeTruthy();
		const checkGroupFieldGroup = screen.getByTestId("check-group-field-group");
		expect(checkGroupFieldGroup).toBeTruthy();
		const checkFieldInputs = screen.getAllByTestId<HTMLInputElement>("check-field-input");
		expect(checkFieldInputs).toHaveLength(6);
		fireEvent.click(checkFieldInputs[1]);
		expect(checkFieldInputs[1].checked).toBe(true);
		fireEvent.click(checkFieldInputs[1]);
		expect(checkFieldInputs[1].checked).toBe(false);
	});

	it("should call filterItems action on change", async () => {
		defaultProps.value = { order: "", filterSites: "noFilter" };
		defaultProps.pointer = "filterSites";
		defaultProps.center = true;
		defaultProps.label = "Site";
		defaultProps.selectAllOption = "noFilter";
		defaultProps.filters = [
			{
				name: "all",
				value: "all",
				title: "All",
			},
		];
		const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;

		defaultProps.filterItems = filterItemsMock;
		const data = {
			data: [
				{ value: 1, label: "Site 1" },
				{ value: 2, label: "Site 2" },
				{ value: 3, label: "Site 3" },
				{ value: 4, label: "Site 4" },
				{ value: 5, label: "Site 5" },
			],
			status: 200,
			statusText: "Ok",
			headers: {},
			config: {},
		};

		mockedAxios.mockResolvedValue(data);

		await act(async () => {
			render(
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<SiteFilter {...defaultProps} />
				</ThemeProvider>,
			);
		});

		const siteFilterButton = screen.getByTestId("floating-menu-button");

		expect(siteFilterButton).toBeTruthy();
		fireEvent.click(siteFilterButton);
		const checkFieldInputs = screen.queryAllByTestId("check-field-input");
		fireEvent.click(checkFieldInputs[1]);
		expect(filterItemsMock).toHaveBeenCalledTimes(1);
		expect(filterItemsMock).toBeCalledWith("filterSites", [{ label: "Site 1", value: 1 }]);
	});
});
