import { Router } from "react-router-dom";

import "@testing-library/jest-dom";

import { parseTheme } from "@ax/helpers";
import globalTheme from "@ax/themes/theme.json";

import userEvent from "@testing-library/user-event";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import { createMemoryHistory } from "history";
import { mock } from "jest-mock-extended";
import type { Middleware } from "redux";
import configureStore from "redux-mock-store";
import thunk from "redux-thunk";
import { ThemeProvider } from "styled-components";

import { act, cleanup, fireEvent, render, screen } from "./../../../../../config/jest/test-utils";
import {
	deletedUserResponse,
	removeUserSiteResponse,
	rolesResponse,
	userResponse,
	usersResponse,
	usersSiteResponse,
} from "./../../../../__mocks__/axios/UserList";
import {
	appStoreMock,
	sitesStoreGlobalMock,
	sitesStoreMock,
	usersSiteStoreMock,
	usersStoreMock,
} from "../../../../__mocks__/store/UserList";
import UserList, { type IUserListProps } from "./../../../../modules/Users/UserList";

const middlewares: Middleware[] = [thunk];
const mockStore = configureStore(middlewares);

const defaultProps = mock<IUserListProps>();

const user = userEvent.setup();

const history = createMemoryHistory();

let mockedAxios: MockAdapter;

beforeAll(() => {
	mockedAxios = new MockAdapter(axios);
	window.HTMLElement.prototype.scrollIntoView = jest.fn();
});

afterEach(() => {
	cleanup();
	jest.clearAllMocks();
	mockedAxios.reset();
});

describe("UserList module rendering", () => {
	it("should render the componet with 3 global users", async () => {
		const initialStore = {
			users: usersStoreMock,
			sites: sitesStoreGlobalMock,
			app: appStoreMock,
		};

		const store = mockStore(initialStore);

		mockedAxios.onGet(`undefined/site/global/roles`).reply(200, rolesResponse.data);
		mockedAxios.onGet(`undefined/users`).reply(200, usersResponse.data);
		mockedAxios.onGet(`undefined/sites?recentSitesNumber=0`).reply(200, {});

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

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

		expect(screen.getByTestId("users-wrapper")).toBeTruthy();
		expect(screen.queryAllByTestId("user-item").length).toBe(3);
	});

	it("should render the componet with 2 site user", async () => {
		const initialStore = {
			users: usersSiteStoreMock,
			sites: sitesStoreMock,
			app: appStoreMock,
		};

		const initialState = { ...initialStore, ...defaultProps };
		const store = mockStore(initialStore);

		mockedAxios.onGet(`undefined/site/2/roles`).reply(200, rolesResponse.data);
		mockedAxios.onGet(`undefined/site/2/users`).reply(200, usersSiteResponse.data);
		mockedAxios.onGet(`undefined/sites?recentSitesNumber=0`).reply(200, {});

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

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

		expect(screen.getByTestId("users-wrapper")).toBeTruthy();
		expect(screen.queryAllByTestId("user-item").length).toBe(2);
	});

	it("should render the componet with no users", async () => {
		const initialStore = {
			users: { users: [], roles: [] },
			sites: sitesStoreGlobalMock,
			app: appStoreMock,
		};

		const store = mockStore(initialStore);

		mockedAxios.onGet(`undefined/site/global/roles`).reply(200, rolesResponse.data);
		mockedAxios.onGet(`undefined/users`).reply(200, usersResponse.data);
		mockedAxios.onGet(`undefined/sites?recentSitesNumber=0`).reply(200, {});

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

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

		expect(screen.getByTestId("users-wrapper")).toBeTruthy();
		expect(screen.getByTestId("empty-wrapper")).toBeTruthy();
		expect(screen.queryAllByTestId("user-item").length).toBe(0);
	});
});

describe("UserList module events", () => {
	it("should call action when user click on user", async () => {
		const initialStore = {
			users: usersStoreMock,
			sites: sitesStoreGlobalMock,
			app: appStoreMock,
		};

		const store = mockStore(initialStore);

		mockedAxios.onGet(`undefined/site/global/roles`).reply(200, rolesResponse.data);
		mockedAxios.onGet(`undefined/users`).reply(200, usersResponse.data);
		mockedAxios.onGet(`undefined/user/171`).reply(200, userResponse.data);
		mockedAxios.onGet(`undefined/sites?recentSitesNumber=0`).reply(200, {});

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

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

		const users = screen.queryAllByTestId("user-cell");
		expect(users.length).toBe(3);

		await act(async () => {
			fireEvent.click(users[0]);
		});

		expect(store.getActions()).toContainEqual({
			payload: { userForm: userResponse.data },
			type: "users/SET_USER_FORM",
		});
	});

	it("should delete an user with bulk", async () => {
		const getMockStore = (actions: any[]) => {
			const setUsers = actions.filter((action: any) => action.type === "users/SET_USERS");
			if (setUsers.length >= 2) {
				return {
					users: { ...usersStoreMock, users: deletedUserResponse.data },
					sites: sitesStoreGlobalMock,
					app: appStoreMock,
				};
			} else {
				return {
					users: usersStoreMock,
					sites: sitesStoreGlobalMock,
					app: appStoreMock,
				};
			}
		};

		const store = mockStore(getMockStore);

		mockedAxios.onGet(`undefined/site/global/roles`).reply(200, rolesResponse.data);
		mockedAxios.onGet(`undefined/users`).reply(200, usersResponse.data);
		mockedAxios.onGet(`undefined/users?order=dateCreated`).reply(200, deletedUserResponse.data);
		mockedAxios.onDelete("undefined/user/bulk").reply(200, {});
		mockedAxios.onGet(`undefined/sites?recentSitesNumber=0`).reply(200, {});

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

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

		expect(screen.queryByTestId("user-delete-bulk-modal")).toBeFalsy();

		expect(screen.queryAllByTestId("user-item").length).toBe(3);

		await user.click(screen.getByLabelText("Prueba Prueba"));
		await user.click(screen.getByText("delete"));

		expect(screen.getByTestId("user-delete-bulk-modal")).toBeTruthy();

		await act(async () => {
			fireEvent.click(screen.getByText("Delete"));
		});

		expect(screen.queryByTestId("user-delete-bulk-modal")).toBeFalsy();
		expect(screen.queryAllByTestId("user-item").length).toBe(2);

		expect(store.getActions()).toContainEqual({
			payload: { users: deletedUserResponse.data },
			type: "users/SET_USERS",
		});
	});

	it("should remove an user from site with bulk", async () => {
		const getMockStore = (actions: any[]) => {
			const setUsers = actions.filter((action: any) => action.type === "users/SET_USERS");
			if (setUsers.length >= 2) {
				return {
					users: { ...usersStoreMock, users: removeUserSiteResponse.data },
					sites: sitesStoreMock,
					app: appStoreMock,
				};
			} else {
				return {
					users: usersSiteStoreMock,
					sites: sitesStoreMock,
					app: appStoreMock,
				};
			}
		};

		const store = mockStore(getMockStore);

		mockedAxios.onGet(`undefined/site/2/roles`).reply(200, rolesResponse.data);
		mockedAxios.onGet(`undefined/site/2/users`).reply(200, usersSiteResponse.data);
		mockedAxios.onGet(`undefined/site/2/users?order=dateCreated`).reply(200, removeUserSiteResponse.data);
		mockedAxios.onPut("undefined/site/2/restrict").reply(200, {});
		mockedAxios.onGet(`undefined/sites?recentSitesNumber=0`).reply(200, {});

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

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

		expect(screen.queryByTestId("user-delete-bulk-modal")).toBeFalsy();

		expect(screen.queryAllByTestId("user-item").length).toBe(2);

		await user.click(screen.getByLabelText("Admin"));
		await user.click(screen.getByText("Remove from this site"));

		expect(screen.getByTestId("user-delete-bulk-modal")).toBeTruthy();

		await act(async () => {
			fireEvent.click(screen.getByText("Remove"));
		});

		expect(screen.queryByTestId("user-delete-bulk-modal")).toBeFalsy();
		expect(screen.queryAllByTestId("user-item").length).toBe(1);
	});
});
