import { useState } from "react";
import { connect } from "react-redux";
import type { ISite, IRootState, IUser, IRole, ISiteRoles } from "@ax/types";
import { appActions } from "@ax/containers/App";
import { usersActions } from "@ax/containers/Users";
import { ErrorToast, FieldsBehavior, MainWrapper, SearchField, Notification, Button, Modal } from "@ax/components";
import { useModal } from "@ax/hooks";

import SiteItem from "./SiteItem";
import RolesModal from "./SiteItem/RolesModal";
import RoleItem from "./SiteItem/RolesModal/RoleItem";
import OptionItem from "./OptionItem";

import * as S from "./style";

const UserCreate = (props: IUserCreateProps) => {
	const { setHistoryPush, createUser, sites, site, users, updateUser, roles, isSaving } = props;

	const isSiteView = !!site;

	const initState: IState = { name: "", email: "", roles: [], isSuperAdmin: false };
	const [state, setState] = useState(initState);

	const getSortedSitesByName = (sites: ISite[]) =>
		sites.sort((site1: ISite, site2: ISite) => site1.name.localeCompare(site2.name));
	const sortedByNameSites = getSortedSitesByName(sites);

	const [sitesList, setSiteList] = useState(sortedByNameSites);
	const [userAlreadyExists, setUserAlreadyExists] = useState(false);

	const { isOpen, toggleModal } = useModal(false);
	const { isOpen: isOpenAdvise, toggleModal: toggleAdviseModal } = useModal(false);

	const handleNameChange = (value: string) => setState({ ...state, name: value });

	const handleEmailChange = (value: string) => setState({ ...state, email: value });

	const handleCreate = async () => {
		const { email } = state;
		const globalUser = users.find((user) => user.email === email);
		setUserAlreadyExists(false);

		const BASE_URL = isSiteView ? "/sites/users" : "/users";

		if (isOpenAdvise) {
			toggleAdviseModal();
		}

		if (isSiteView && globalUser?.id) {
			const { id, roles } = globalUser;
			const userAlreadyExists = roles.find(
				(siteRole: ISiteRoles) => siteRole.siteId === "all" || siteRole.siteId === site.id,
			);
			if (userAlreadyExists) {
				setUserAlreadyExists(true);
			} else {
				const form = { ...globalUser, roles: [...roles, ...state.roles] };
				const updated = await updateUser(id, form, false);
				if (updated) {
					setHistoryPush(BASE_URL);
				}
			}
		} else {
			const created = await createUser(state);
			if (created) {
				setHistoryPush(BASE_URL);
			}
		}
	};

	const selectSite = (id: number | string) => {
		const { roles } = state;
		const hasSite = roles.find((siteRole: ISiteRoles) => siteRole.siteId === id);
		if (hasSite) {
			const filteredRoles = roles.filter(
				(siteRole: ISiteRoles) =>
					(Number.isInteger(id) && siteRole.siteId !== id && siteRole.siteId !== "all") ||
					(!Number.isInteger(id) && siteRole.siteId !== id),
			);
			setState({ ...state, roles: filteredRoles });
		} else {
			setState({ ...state, roles: [...state.roles, { siteId: id, roles: [] }] });
		}
	};

	const filterSitesList = (query: string) => {
		const filteredSites = sites.filter((site) =>
			site.name.toLowerCase().replace(" ", "").includes(query.toLowerCase().replace(" ", "")),
		);
		const sortedSites = getSortedSitesByName(filteredSites);
		setSiteList(sortedSites);
	};

	const handleAddRoles = (newRoles: ISiteRoles) => {
		const oldRoles = state.roles.filter((role: ISiteRoles) => role.siteId !== newRoles.siteId);
		const updatedRoles = newRoles.roles.length > 0 ? [...oldRoles, newRoles] : oldRoles;
		setState({ ...state, roles: updatedRoles });
	};

	const handleAddSiteRoles = (newRoles: number[]) => {
		if (!site) return;
		const oldRoles = state.roles.filter((role: ISiteRoles) => role.siteId !== site.id);
		const newSiteRoles = { siteId: site.id, roles: newRoles };
		const updatedRoles = newRoles.length > 0 ? [...oldRoles, newSiteRoles] : oldRoles;
		setState({ ...state, roles: updatedRoles });
	};

	const toggleSuperAdmin = () => setState({ ...state, isSuperAdmin: !state.isSuperAdmin });

	const rightButtonProps = {
		label: "Add User",
		action: state.roles.length === 0 && !state.isSuperAdmin ? toggleAdviseModal : handleCreate,
		disabled: isSaving,
	};

	const name = state.name.trim() === "" ? "Name" : state.name;

	const sitesID = state.roles.map((roleSite: ISiteRoles) => roleSite.siteId);

	const siteSelectedRoles = isSiteView
		? state.roles.find((roleSite: ISiteRoles) => roleSite.siteId === site.id)
		: undefined;

	const rolesAll = state.roles.find((roleSite: ISiteRoles) => roleSite.siteId === "all");
	const allDescription =
		"The user will have access to all existing and future sites depending on the permissions assigned to the role.";

	const rolesGlobal = state.roles.find((roleSite: ISiteRoles) => roleSite.siteId === "global");
	const globalDescription = "Global data will be accessible to the user based on the permissions assigned to the role.";

	const mainModalAction = {
		title: "Create User",
		onClick: handleCreate,
	};

	const secondaryModalAction = { title: "Cancel", onClick: toggleAdviseModal };

	return (
		<MainWrapper backLink={true} title="New User" rightButton={rightButtonProps}>
			<ErrorToast size="l" />
			{userAlreadyExists && (
				<S.NotificationWrapper data-testid="user-notification-wrapper">
					<Notification type="error" text="User already has access to this site." />
				</S.NotificationWrapper>
			)}
			<S.Wrapper>
				<S.SubTitle>User data</S.SubTitle>
				<S.NameTitle>{name}</S.NameTitle>
				<FieldsBehavior
					title="Name"
					name="name"
					fieldType="TextField"
					placeholder="Type a name"
					mandatory={true}
					value={state.name}
					onChange={handleNameChange}
					autoComplete="user-name"
				/>
				<FieldsBehavior
					title="Email"
					name="email"
					fieldType="TextField"
					placeholder="Type an email"
					mandatory={true}
					value={state.email}
					onChange={handleEmailChange}
					autoComplete="user-email"
				/>
				{isSiteView ? (
					<>
						<S.SettingsWrapper>
							<S.HeadingWrapper>
								<S.Heading>Roles Assigned</S.Heading>
								{(!siteSelectedRoles || siteSelectedRoles.roles.length === 0) && (
									<Button type="button" buttonStyle="text" onClick={toggleModal} icon="addCircle">
										Add Role
									</Button>
								)}
							</S.HeadingWrapper>
							<S.SettingContent>
								<S.SettingText>You can add a one or more roles to this user.</S.SettingText>
							</S.SettingContent>
						</S.SettingsWrapper>
						<S.RoleList data-testid="user-role-list">
							{siteSelectedRoles?.roles.map((siteRoleId: number) => {
								const role = roles.find((role: IRole) => role.id === siteRoleId);
								return role && <RoleItem key={role.name} role={role} isReadOnly={true} />;
							})}
							{siteSelectedRoles && siteSelectedRoles.roles.length > 0 && (
								<Button type="button" buttonStyle="line" onClick={toggleModal}>
									Manage user roles
								</Button>
							)}
						</S.RoleList>
						<RolesModal
							isOpen={isOpen}
							toggleModal={toggleModal}
							roles={roles}
							addRoles={handleAddSiteRoles}
							selectedRoles={siteSelectedRoles ? siteSelectedRoles.roles : []}
							isGlobal={false}
						/>
					</>
				) : (
					<>
						<S.OptionsWrapper>
							<S.Label>User type</S.Label>
							<OptionItem
								name="superadmin"
								title="Super admin"
								description="The user will have full access to all features and their configuration. They will also have access to all sites."
								onChange={toggleSuperAdmin}
								value={state.isSuperAdmin}
							/>
							<OptionItem
								name="member"
								title="Member"
								description="You can assign a specific role to this user and give them access to all sites or just some of them."
								onChange={toggleSuperAdmin}
								value={!state.isSuperAdmin}
							/>
							<S.HelpText>Show the diference between types & roles in our Documentation</S.HelpText>
						</S.OptionsWrapper>
						{!state.isSuperAdmin && (
							<S.MemberWrapper>
								<S.SettingsWrapper>
									<S.Heading>Global data Permissions</S.Heading>
									<S.SettingContent>
										<S.SettingText>The user can have access to global data with specific role.</S.SettingText>
									</S.SettingContent>
								</S.SettingsWrapper>
								<S.GlobalPermissionsFieldWrapper>
									<SiteItem
										sites={sitesID}
										item={{ name: "Global data permissions", id: "global", onChange: selectSite }}
										roles={roles}
										addRoles={handleAddRoles}
										selected={rolesGlobal ? rolesGlobal.roles : []}
										featured={true}
										description={globalDescription}
									/>
								</S.GlobalPermissionsFieldWrapper>
								<S.SettingsWrapper>
									<S.Heading>Sites access</S.Heading>
									<S.SettingContent>
										<S.SettingText>
											The user can have access to all sites with specific roles. You can also manually select one or
											more sites.
										</S.SettingText>
									</S.SettingContent>
								</S.SettingsWrapper>
								<S.SearchFieldWrapper>
									<SearchField
										disabled={!!rolesAll}
										placeholder="Search"
										onChange={filterSitesList}
										searchOnEnter={false}
										focus={false}
									/>
								</S.SearchFieldWrapper>
								<S.SelectAllSitesFieldWrapper>
									<SiteItem
										sites={sitesID}
										item={{ name: "Access to All Sites", id: "all", onChange: selectSite }}
										roles={roles}
										addRoles={handleAddRoles}
										selected={rolesAll ? rolesAll.roles : []}
										featured={true}
										description={allDescription}
									/>
								</S.SelectAllSitesFieldWrapper>
								<S.SiteList data-testid="user-site-list">
									{sitesList.length > 0 &&
										sitesList.map((site: ISite) => {
											const rolesSite = state.roles.find((roleSite: ISiteRoles) => roleSite.siteId === site.id);
											return (
												<SiteItem
													disabled={!!rolesAll}
													sites={sitesID}
													key={site.id}
													item={{ name: site.name, id: site.id, onChange: selectSite }}
													roles={roles}
													addRoles={handleAddRoles}
													selected={rolesSite ? rolesSite.roles : []}
												/>
											);
										})}
								</S.SiteList>
							</S.MemberWrapper>
						)}
					</>
				)}
			</S.Wrapper>
			<Modal
				isOpen={isOpenAdvise}
				hide={toggleAdviseModal}
				title="Create User?"
				secondaryAction={secondaryModalAction}
				mainAction={mainModalAction}
				size="S"
			>
				<S.ModalContent>
					Before creating an account, <strong>select the user&apos;s permissions and site access</strong>. If you
					proceed without selecting any permissions, the user{" "}
					<strong>won&apos;t have access to anything or view any content</strong>.
				</S.ModalContent>
			</Modal>
		</MainWrapper>
	);
};

interface IDispatchProps {
	setHistoryPush(path: string): void;
	createUser(data: { name: string; email: string; roles: ISiteRoles[] }): Promise<boolean>;
	updateUser(id: number, data: IUser, isProfile: boolean): Promise<boolean>;
}
interface IProfileProps {
	users: IUser[];
	sites: ISite[];
	site: ISite | null;
	roles: IRole[];
	isSaving: boolean;
}

interface IState {
	name: string;
	email: string;
	roles: ISiteRoles[];
	isSuperAdmin: boolean;
}

const mapStateToProps = (state: IRootState) => ({
	users: state.users.users,
	sites: state.sites.sites,
	site: state.sites.currentSiteInfo,
	roles: state.users.roles,
	isSaving: state.app.isSaving,
});

const mapDispatchToProps = {
	setHistoryPush: appActions.setHistoryPush,
	createUser: usersActions.createUser,
	updateUser: usersActions.updateUser,
};

export type IUserCreateProps = IProfileProps & IDispatchProps;

export default connect(mapStateToProps, mapDispatchToProps)(UserCreate);
