import React from "react";
import axios from "axios";

import { ThemeProvider } from "styled-components";
import { parseTheme } from "@ax/helpers";
import { CalledWithMock, mock } from "jest-mock-extended";
import configureStore from "redux-mock-store";
import thunk from "redux-thunk";
import { Router } from "react-router-dom";

import { IActivateRole, IGetRoles } from "@ax/types";
import { history } from "@ax/routes";
import globalTheme from "@ax/themes/theme.json";
import Roles, { IRolesProps } from "@ax/modules/Users/Roles";

import { render, cleanup, screen, act, fireEvent } from "./../../../../../config/jest/test-utils";
import { rolesDataMock, usersDataMock } from "./../../../../__mocks__/store/Roles";
import { rolesDataResponse } from "./../../../../__mocks__/axios/Roles";

afterEach(cleanup);

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

describe("Roles module rendering", () => {
	it("should render component", async () => {
		mockedAxios.mockResolvedValue(rolesDataResponse);
		window.HTMLElement.prototype.scrollIntoView = jest.fn();
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock },
			sites: {
				currentSiteInfo: null,
			},
		};
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const initialState = { ...initialStore, ...defaultProps };

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const usersWrapper = screen.getByTestId("users-wrapper");
		expect(usersWrapper).toBeTruthy();
		const tableListWrapper = screen.getByTestId("roles-table-list-wrapper");
		expect(tableListWrapper).toBeTruthy();
	});

	it("should render role items", async () => {
		mockedAxios.mockResolvedValue(rolesDataResponse);
		window.HTMLElement.prototype.scrollIntoView = jest.fn();
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock },
			sites: {
				currentSiteInfo: null,
			},
		};
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const initialState = { ...initialStore, ...defaultProps };

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const roleItems = screen.getAllByTestId("role-item");
		expect(roleItems).toBeTruthy();
	});

	it("should render tag colors", async () => {
		mockedAxios.mockResolvedValue(rolesDataResponse);
		window.HTMLElement.prototype.scrollIntoView = jest.fn();
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock },
			sites: {
				currentSiteInfo: null,
			},
		};
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const initialState = { ...initialStore, ...defaultProps };

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const tags = screen.getAllByTestId("tag-fixed");

		expect(tags).toBeTruthy();
		expect(tags.length).toEqual(5);

		const styles = getComputedStyle(tags[0]);
		expect(styles.backgroundColor).toEqual("rgb(199, 236, 248)");
	});

	it("should render empty state when no roles", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: [] },
			sites: {
				currentSiteInfo: null,
			},
		};
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const initialState = { ...initialStore, ...defaultProps };

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const emptyState = screen.getByTestId("empty-wrapper");
		expect(emptyState).toBeTruthy();
	});

	it("should render toggle fields", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock },
			sites: {
				currentSiteInfo: null,
			},
		};
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const initialState = { ...initialStore, ...defaultProps };

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const toggleFields = screen.getAllByTestId("toggle-field-wrapper");
		expect(toggleFields.length).toEqual(5);
	});

	it("should render toggle field as disabled when it is not editable role", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock },
			sites: {
				currentSiteInfo: null,
			},
		};
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const initialState = { ...initialStore, ...defaultProps };

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const adminRoleToggleField = screen.getAllByTestId<HTMLInputElement>("toggle-field-input");
		expect(adminRoleToggleField[0]).toBeTruthy();

		expect(adminRoleToggleField[0].disabled).toEqual(true);
	});

	it("should render avatars when is siteView and there is users", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock, users: usersDataMock },
			sites: {
				currentSiteInfo: { id: 1 },
			},
		};
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const initialState = { ...initialStore, ...defaultProps };

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const avatarCell = screen.getAllByTestId("avatar-cell");
		expect(avatarCell.length).toBeTruthy();
	});

	it("should render users length label when user items are greater than 5", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock, users: usersDataMock },
			sites: {
				currentSiteInfo: { id: 1 },
			},
		};
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const initialState = { ...initialStore, ...defaultProps };

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const usersLength = screen.getByTestId("users-length");
		expect(usersLength).toBeTruthy();
	});

	it("should render user avatars tooltip on hover", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock, users: usersDataMock },
			sites: {
				currentSiteInfo: { id: 1 },
			},
		};
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const initialState = { ...initialStore, ...defaultProps };

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const avatarCells = screen.getAllByTestId("avatar-cell");
		expect(avatarCells.length).toBeTruthy();
		const usersLength = screen.getByTestId("users-length");
		expect(usersLength).toBeTruthy();
		fireEvent.mouseOver(avatarCells[0]);
		const avatarTooltips = screen.getByTestId("avatars-tooltip");
		expect(avatarTooltips).toBeTruthy();
	});

	it("should not render side modal if it's not open", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock, users: usersDataMock },
			sites: {
				currentSiteInfo: { id: 1 },
			},
		};
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const initialState = { ...initialStore, ...defaultProps };

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const roleSideModal = screen.queryByTestId("role-side-modal");
		expect(roleSideModal).not.toBeTruthy();
	});
});

describe("Roles module events", () => {
	it("should display sorting options when clicking name filter", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock },
			sites: {
				currentSiteInfo: null,
			},
		};
		const initialState = { ...initialStore, ...defaultProps };
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);
		await act(async () => {
			render(Component, { store });
		});

		const nameHeaderButton = screen.getByTestId("name-filter-header");
		expect(nameHeaderButton).toBeTruthy();
		fireEvent.click(nameHeaderButton);
		const listItem = screen.getAllByTestId("list-item");
		expect(listItem.length).toEqual(2);

		const sortAscendingName = listItem[0];
		const sortDescendingName = listItem[1];

		expect(sortAscendingName.textContent).toEqual("Ascendent");
		expect(sortDescendingName.textContent).toEqual("Descendent");
	});

	it("should render FullArrowUp icon if is filtered by ascending name", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock },
			sites: {
				currentSiteInfo: null,
			},
		};
		const initialState = { ...initialStore, ...defaultProps };
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const nameHeaderButton = screen.getByTestId("name-filter-header");
		expect(nameHeaderButton).toBeTruthy();
		fireEvent.click(nameHeaderButton);
		const listItem = screen.getAllByTestId("list-item");
		expect(listItem.length).toEqual(2);

		const sortAscendingName = listItem[0];
		const sortDescendingName = listItem[1];

		expect(sortAscendingName.textContent).toEqual("Ascendent");
		expect(sortDescendingName.textContent).toEqual("Descendent");
		fireEvent.click(sortAscendingName);
		const arrowIcon = screen.getByTestId("icon-component-fullarrowup");
		expect(arrowIcon).toBeTruthy();
	});

	it("should render FullArrowDown icon if is filtered by descending name", async () => {
		mockedAxios.mockResolvedValue(rolesDataResponse);
		window.HTMLElement.prototype.scrollIntoView = jest.fn();
		const getRolesMock = jest.fn();
		const activateRolesMock = jest.fn();
		defaultProps.getRoles = getRolesMock as CalledWithMock<Promise<void>, [params?: IGetRoles | undefined]>;
		defaultProps.activateRoles = activateRolesMock as CalledWithMock<Promise<boolean>, [params: IActivateRole]> &
			((params: IActivateRole) => Promise<boolean>);

		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock },
			sites: {
				currentSiteInfo: null,
			},
		};
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		mockedAxios.mockResolvedValue(rolesDataResponse);
		const store = mockStore(initialStore);

		const initialState = { ...initialStore, ...defaultProps };

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const nameHeaderButton = screen.getByTestId("name-filter-header");
		expect(nameHeaderButton).toBeTruthy();
		fireEvent.click(nameHeaderButton);
		const listItem = screen.getAllByTestId("list-item");
		expect(listItem.length).toEqual(2);

		const sortAscendingName = listItem[0];
		const sortDescendingName = listItem[1];

		expect(sortAscendingName.textContent).toEqual("Ascendent");
		expect(sortDescendingName.textContent).toEqual("Descendent");
		fireEvent.click(sortDescendingName);
		const arrowIcon = screen.getByTestId("icon-component-fullarrowdown");
		expect(arrowIcon).toBeTruthy();
	});

	it("should select role when click check field", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock },
			sites: {
				currentSiteInfo: null,
			},
		};

		const initialState = { ...initialStore, ...defaultProps };
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const checkFieldLabels = screen.getAllByTestId("check-field-label");
		const checkFieldInputs = screen.getAllByTestId<HTMLInputElement>("check-field-input");
		expect(checkFieldLabels).toBeTruthy();
		expect(checkFieldInputs).toBeTruthy();
		fireEvent.change(checkFieldInputs[0], { target: { checked: true, value: "Clicked" } });
		expect(checkFieldInputs[0].value).toBe("Clicked");
		expect(checkFieldInputs[0].checked).toBeTruthy();
	});

	it("should display sidemodal on click", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock },
			sites: {
				currentSiteInfo: null,
			},
		};
		const initialState = { ...initialStore, ...defaultProps };
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const roleItems = screen.getAllByTestId("role-item-permissions");
		expect(roleItems.length).toBeTruthy();
		fireEvent.click(roleItems[0]);
		const roleSideModal = screen.getByTestId("role-side-modal");
		expect(roleSideModal).toBeTruthy();
	});

	it("should display role data in side modal", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock },
			sites: {
				currentSiteInfo: null,
			},
		};
		const initialState = { ...initialStore, ...defaultProps };
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const roleItems = screen.getAllByTestId("role-item-permissions");
		const roleItemNames = screen.getAllByTestId("role-item-name");

		expect(roleItems).toBeTruthy();
		expect(roleItemNames).toBeTruthy();
		expect(roleItemNames[0].textContent).toEqual("Administrator");

		fireEvent.click(roleItems[0]);
		const roleSideModal = screen.getByTestId("role-side-modal");
		expect(roleSideModal).toBeTruthy();
		const roleSideModalTitle = screen.getByTestId("role-side-modal-title");
		expect(roleSideModalTitle.textContent).toEqual("Administrator Permissions");
		const roleSideModalPermissions = screen.getByTestId("role-side-modal-total-permissions");
		expect(roleSideModalPermissions.textContent).toEqual("86/95");
	});

	it("should display role permissions list", async () => {
		const initialStore = {
			app: { isLoading: false },
			users: { roles: rolesDataMock },
			sites: {
				currentSiteInfo: null,
			},
		};
		const initialState = { ...initialStore, ...defaultProps };
		const middlewares: any = [thunk];
		const mockStore = configureStore(middlewares);
		const store = mockStore(initialStore);

		const Component = (
			<Router history={history}>
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<Roles {...initialState} />
				</ThemeProvider>
			</Router>
		);

		await act(async () => {
			render(Component, { store });
		});

		const roleItems = screen.getAllByTestId("role-item-permissions");
		expect(roleItems).toBeTruthy();
		fireEvent.click(roleItems[0]);
		const roleSideModal = screen.getByTestId("role-side-modal");
		expect(roleSideModal).toBeTruthy();
		const rolePermissions = screen.getAllByTestId("role-permission");
		expect(rolePermissions.length).toBeGreaterThan(0);
	});
});
