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, fireEvent, act } from "@testing-library/react";
import { parseTheme } from "@ax/helpers";
import CategoryFilter, { ICategoryFilterProps } from "@ax/components/TableFilters/CategoryFilter";
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<ICategoryFilterProps>();

describe("Category filter component rendering", () => {
	it("should render category filter", async () => {
		const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
		defaultProps.filterItems = filterItemsMock;
		defaultProps.value = [{ value: "all", label: "All" }];
		defaultProps.siteID = null;
		defaultProps.structuredData = {
			from: "profile",
			indexable: true,
			key: "profile",
			showList: true,
			source: "STORY_PROFILE",
			title: "Profile",
			type: "AsyncCheckGroup",
		};
		const data = {
			data: [
				{ name: 1, title: "Mentor", value: 1 },
				{ name: 2, title: "Professor", value: 2 },
				{ name: 3, title: "Student", value: 3 },
			],
			status: 200,
			statusText: "Ok",
			headers: {},
			config: {},
		};

		mockedAxios.mockResolvedValue(data);

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

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

	it("should render the component with no options", async () => {
		const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
		defaultProps.filterItems = filterItemsMock;
		defaultProps.value = [{ value: "all", label: "All" }];
		defaultProps.siteID = null;
		defaultProps.structuredData = {
			from: "profile",
			indexable: true,
			key: "profile",
			showList: true,
			source: "STORY_PROFILE",
			title: "Profile",
			type: "AsyncCheckGroup",
		};
		const data = {
			data: [],
			status: 500,
			statusText: "Internal Server Error",
			headers: {},
			config: {},
		};
		mockedAxios.mockResolvedValue(data);

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

		const categoryFilterButton = screen.getByTestId("floating-menu-button");
		expect(categoryFilterButton).toBeTruthy();
		fireEvent.click(categoryFilterButton);
		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("CategoryFilter events", () => {
	it("should render check group on click floating menu button", async () => {
		const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
		defaultProps.filterItems = filterItemsMock;
		defaultProps.value = [{ value: "all", label: "All" }];
		defaultProps.siteID = null;
		defaultProps.structuredData = {
			from: "profile",
			indexable: true,
			key: "profile",
			showList: true,
			source: "STORY_PROFILE",
			title: "Profile",
			type: "AsyncCheckGroup",
		};
		const data = {
			data: [
				{ name: 1, title: "Mentor", value: 1 },
				{ name: 2, title: "Professor", value: 2 },
				{ name: 3, title: "Student", value: 3 },
			],
			status: 200,
			statusText: "Ok",
			headers: {},
			config: {},
		};

		mockedAxios.mockResolvedValue(data);

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

		const typeFilterButton = screen.getByTestId("floating-menu-button");
		expect(typeFilterButton).toBeTruthy();
		fireEvent.click(typeFilterButton);
		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(4);
	});

	it("should check option on click", async () => {
		const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
		defaultProps.filterItems = filterItemsMock;
		defaultProps.value = [{ value: "all", label: "All" }];
		defaultProps.siteID = null;
		defaultProps.structuredData = {
			from: "profile",
			indexable: true,
			key: "profile",
			showList: true,
			source: "STORY_PROFILE",
			title: "Profile",
			type: "AsyncCheckGroup",
		};
		const data = {
			data: [
				{ name: 1, title: "Mentor", value: 1 },
				{ name: 2, title: "Professor", value: 2 },
				{ name: 3, title: "Student", value: 3 },
			],
			status: 200,
			statusText: "Ok",
			headers: {},
			config: {},
		};

		mockedAxios.mockResolvedValue(data);

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

		const typeFilterButton = screen.getByTestId("floating-menu-button");
		expect(typeFilterButton).toBeTruthy();
		fireEvent.click(typeFilterButton);
		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(4);
		fireEvent.change(checkFieldInputs[1], { target: { checked: true, value: "1" } });
		expect(checkFieldInputs[1].checked).toBe(true);
	});

	it("should call filterItems action on change", async () => {
		const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
		defaultProps.filterItems = filterItemsMock;
		defaultProps.value = [{ value: "all", label: "All" }];
		defaultProps.siteID = null;
		defaultProps.structuredData = {
			from: "profile",
			indexable: true,
			key: "profile",
			showList: true,
			source: "STORY_PROFILE",
			title: "Profile",
			type: "AsyncCheckGroup",
		};
		const data = {
			data: [
				{ name: 1, title: "Mentor", value: 1 },
				{ name: 2, title: "Professor", value: 2 },
				{ name: 3, title: "Student", value: 3 },
			],
			status: 200,
			statusText: "Ok",
			headers: {},
			config: {},
		};

		mockedAxios.mockResolvedValue(data);

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

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

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