import React from "react";
import axios, { AxiosResponse } from "axios";
import { ThemeProvider } from "styled-components";
import configureStore from "redux-mock-store";
import thunk from "redux-thunk";
import { Router } from "react-router-dom";
import { mock } from "jest-mock-extended";
import "@testing-library/jest-dom";
import { render, cleanup, screen, act } from "./../../../../../config/jest/test-utils";
import userEvent from "@testing-library/user-event";
import { createMemoryHistory } from "history";

import { parseTheme } from "@ax/helpers";
import globalTheme from "@ax/themes/theme.json";
import UserCreate, { IUserCreateProps } from "./../../../../modules/Users/UserCreate";

import {
	usersStoreMock,
	sitesStoreGlobalMock,
	sitesStoreMock,
	appStoreMock,
} from "../../../../__mocks__/store/UsersCreate";

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

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

const defaultProps = mock<IUserCreateProps>();

const user = userEvent.setup();

const history = createMemoryHistory();

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

describe("UserCreate module rendering", () => {
	it("should render the componets with not site view", async () => {
		const initialStore = {
			users: usersStoreMock,
			sites: sitesStoreGlobalMock,
			app: appStoreMock,
		};

		const store = mockStore(initialStore);

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

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

		const wrapper = screen.getByTestId("main-wrapper");
		expect(wrapper).toBeTruthy();

		const fields = screen.getAllByTestId("fields-behavior-wrapper");
		expect(fields.length).toBe(2);

		const siteList = screen.getByTestId("user-site-list");
		expect(siteList).toBeTruthy();

		const roleList = screen.queryByTestId("user-role-list");
		expect(roleList).toBeFalsy();

		const siteItems = screen.getAllByTestId("user-site-item");
		expect(siteItems.length).toBe(4);

		const siteItemsFeatured = screen.getAllByTestId("wrapper-cell-featured");
		expect(siteItemsFeatured.length).toBe(2);

		const searchField = screen.getByTestId("search-field-wrapper");
		expect(searchField).toBeTruthy();
	});

	it("should render the componets with site view", async () => {
		const initialStore = {
			users: usersStoreMock,
			sites: sitesStoreMock,
			app: appStoreMock,
		};

		const store = mockStore(initialStore);

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

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

		const wrapper = screen.getByTestId("main-wrapper");
		expect(wrapper).toBeTruthy();

		const fields = screen.getAllByTestId("fields-behavior-wrapper");
		expect(fields.length).toBe(2);

		const siteList = screen.queryByTestId("user-site-list");
		expect(siteList).toBeFalsy();

		const roleList = screen.getByTestId("user-role-list");
		expect(roleList).toBeTruthy();

		const siteItems = screen.queryAllByTestId("user-site-item");
		expect(siteItems.length).toBe(0);

		const siteItemsFeatured = screen.queryAllByTestId("wrapper-cell-featured");
		expect(siteItemsFeatured.length).toBe(0);

		const searchField = screen.queryByTestId("search-field-wrapper");
		expect(searchField).toBeFalsy();
	});
});

describe("UserCreate module events", () => {
	it("should change inputs", async () => {
		const initialStore = {
			users: usersStoreMock,
			sites: sitesStoreGlobalMock,
			app: appStoreMock,
		};

		const store = mockStore(initialStore);

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

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

		const inputName = screen.getByLabelText("name");
		expect(inputName).toBeTruthy();
		expect(inputName).toHaveValue("");

		await user.type(inputName, "nombre test");
		expect(inputName).toHaveValue("nombre test");

		const inputEmail = screen.getByLabelText("email");
		expect(inputEmail).toBeTruthy();
		expect(inputEmail).toHaveValue("");

		await user.type(inputEmail, "email@test.com");
		expect(inputEmail).toHaveValue("email@test.com");
	});

	it("should show error if user exists", async () => {
		const initialStore = {
			users: usersStoreMock,
			sites: sitesStoreMock,
			app: appStoreMock,
		};

		const store = mockStore(initialStore);

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

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

		const inputName = screen.getByLabelText("name");
		await user.type(inputName, "nombre test");
		const inputEmail = screen.getByLabelText("email");
		await user.type(inputEmail, "admin@secuoyas.com");

		expect(screen.queryByTestId("user-notification-wrapper")).toBeFalsy();

		const addButton = screen.getByText("Add User");
		await user.click(addButton);
		const createButton = screen.getByText("Create User");
		await user.click(createButton);

		expect(screen.getByTestId("user-notification-wrapper")).toBeTruthy();
	});

	it("should update user if not exists in site", async () => {
		const mockedResponse: AxiosResponse = {
			data: [],
			status: 200,
			statusText: "OK",
			headers: {},
			config: {},
		};

		mockedAxios.mockResolvedValueOnce(mockedResponse);

		const initialStore = {
			users: usersStoreMock,
			sites: sitesStoreMock,
			app: appStoreMock,
		};

		const store = mockStore(initialStore);

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

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

		const inputName = screen.getByLabelText("name");
		await user.type(inputName, "nombre test");
		const inputEmail = screen.getByLabelText("email");
		await user.type(inputEmail, "prueba@secuoyas.com");

		const addButton = screen.getByText("Add User");
		await user.click(addButton);

		const createButton = screen.getByText("Create User");
		await user.click(createButton);

		expect(axios).toHaveBeenCalled();
	});

	it("should create user if in global", async () => {
		const mockedResponse: AxiosResponse = {
			data: [],
			status: 200,
			statusText: "OK",
			headers: {},
			config: {},
		};

		mockedAxios.mockResolvedValue(mockedResponse);

		const initialStore = {
			users: usersStoreMock,
			sites: sitesStoreGlobalMock,
			app: appStoreMock,
		};

		const store = mockStore(initialStore);

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

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

		const inputName = screen.getByLabelText("name");
		await user.type(inputName, "nombre test");
		const inputEmail = screen.getByLabelText("email");
		await user.type(inputEmail, "prueba@secuoyas.com");
		const allCheck = screen.getByLabelText("Access to All Sites");
		await user.click(allCheck);

		const addButton = screen.getByText("Add User");
		await user.click(addButton);

		expect(axios).toBeCalledTimes(1);
	});

	it("should disable site checks if all check is checked", async () => {
		const initialStore = {
			users: usersStoreMock,
			sites: sitesStoreGlobalMock,
			app: appStoreMock,
		};

		const store = mockStore(initialStore);

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

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

		const allCheck = screen.getByLabelText("Access to All Sites");
		const siteCheck = screen.getByLabelText("Site 1");
		expect(siteCheck).not.toBeDisabled();

		await user.click(allCheck);

		expect(siteCheck).toBeDisabled();
	});
});
