import { useEffect, useState } from "react";
import { connect } from "react-redux";

import { Button, ErrorToast, FieldsBehavior, ProfileImage, SearchField } from "@ax/components";
import { appActions } from "@ax/containers/App";
import { RouteLeavingGuard } from "@ax/guards";
import { useModal } from "@ax/hooks";
import type { IImage, IRole, IRootState, ISite, ISiteRoles, IUser } from "@ax/types";

import { timezones } from "../../Settings/Globals/constants";
import OptionItem from "../UserCreate/OptionItem";
import SiteItem from "../UserCreate/SiteItem";
import RolesModal from "../UserCreate/SiteItem/RolesModal";
import RoleItem from "../UserCreate/SiteItem/RolesModal/RoleItem";
import { PasswordModal, TypeChangeModal } from "./atoms";
import { shouldBeSaved } from "./helpers";

import * as S from "./style";

const UserForm = (props: IProps) => {
	const {
		user,
		form,
		setForm,
		setHistoryPush,
		currentUser,
		sites,
		roles,
		readOnlySites = false,
		isSiteView = false,
		site,
	} = props;

	const { id, username, name, email, image, company, position, timezone, isSuperAdmin } = form;

	const getSortedItemsByName = (items: ISite[]) =>
		items.sort((item1: ISite, item2: ISite) => item1.name.localeCompare(item2.name));

	const sortedByNameSites = getSortedItemsByName(sites);

	const { isOpen, toggleModal } = useModal(false);
	const { isOpen: isOpenRoleModal, toggleModal: toggleRoleModal } = useModal(false);
	const { isOpen: isOpenTypeChangeModal, toggleModal: toggleTypeChangeModal } = useModal(false);
	const [sitesList, setSiteList] = useState(sortedByNameSites);
	const [showMore, setShowMore] = useState(false);

	const allowedRoutes = ["/profile"];
	const { isDirty } = shouldBeSaved(user, form);

	const isSameUser = currentUser && currentUser.id === user.id;
	const isEditDisabled = !!currentUser && !currentUser.isSuperAdmin && isSiteView && !isSameUser;

	useEffect(() => {
		if (form.roles.length === 0) {
			setShowMore(true);
		}
	}, [form.roles]);

	const handleImageChange = (value: IImage) => setForm({ ...form, image: value || null });
	const handleNameChange = (value: string) => setForm({ ...form, name: value });
	const handleEmailChange = (value: string) => setForm({ ...form, email: value });
	const handleUsernameChange = (value: string) => setForm({ ...form, username: value });
	const handleCompanyChange = (value: string) => setForm({ ...form, company: value });
	const handlePositionChange = (value: string) => setForm({ ...form, position: value });
	const handleTimezoneChange = (value: string) => setForm({ ...form, timezone: value });

	const toggleSuperAdmin = () => {
		setForm({ ...form, isSuperAdmin: !form.isSuperAdmin });
		toggleTypeChangeModal();
	};

	const handleAddRoles = (newRoles: ISiteRoles) => {
		const oldRoles =
			newRoles.siteId === "all"
				? form.roles.filter((role: ISiteRoles) => role.siteId === "global")
				: form.roles.filter((role: ISiteRoles) => role.siteId !== newRoles.siteId);

		const updatedRoles = [...oldRoles, newRoles];

		setForm({ ...form, roles: updatedRoles });
	};

	const getAllSitesWithRoles = () => {
		const siteRoles = form.roles.find((role: ISiteRoles) => role.siteId === "all");
		return sites.map((site: ISite) => {
			return { siteId: site.id, roles: siteRoles ? siteRoles.roles : [] };
		});
	};

	const handleAddSiteRoles = (newRoles: number[]) => {
		if (!site) return;
		const hasAllSites = form.roles.find((role: ISiteRoles) => role.siteId === "all");
		const userRoles = hasAllSites ? getAllSitesWithRoles() : form.roles;
		const oldRoles = userRoles.filter((role: ISiteRoles) => role.siteId !== site.id);
		const newSiteRoles = { siteId: site.id, roles: newRoles };
		const updatedRoles = newRoles.length > 0 ? [...oldRoles, newSiteRoles] : oldRoles;
		setForm({ ...form, roles: updatedRoles });
	};

	const handleChangeType = (value: string) => {
		if ((isSuperAdmin && value === "member") || (!isSuperAdmin && value === "superadmin")) {
			toggleTypeChangeModal();
		}
	};

	const modalProps = {
		isOpen,
		toggleModal,
		id,
	};

	const mainTypeChangeModalAction = {
		title: "Change user type",
		onClick: toggleSuperAdmin,
	};

	const secondaryTypeChangeModalAction = { title: "Cancel", onClick: toggleTypeChangeModal };

	const modalTypeChangeProps = {
		isOpen: isOpenTypeChangeModal,
		toggleModal: toggleTypeChangeModal,
		email,
		isSuperAdmin,
		mainModalAction: mainTypeChangeModalAction,
		secondaryModalAction: secondaryTypeChangeModalAction,
	};

	const action = (path: string) => setHistoryPush(path);

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

	const selectSite = (id: number | string) => {
		const { roles } = form;
		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),
			);
			setForm({ ...form, roles: filteredRoles });
			if (id === "all") {
				setShowMore(true);
			}
		} else {
			setForm({ ...form, roles: [...form.roles, { siteId: id, roles: [] }] });
		}
	};

	const text = (
		<>
			Some changes <strong>are not saved</strong>.
		</>
	);

	const ShowMoreButton = () => (
		<Button type="button" buttonStyle="line" onClick={() => setShowMore(!showMore)}>
			{showMore ? "Show less sites & roles" : "Show more sites & roles"}
		</Button>
	);

	const getSiteName = (id: number | string) => {
		const currentSite = sites.find((site) => site.id === id);
		return currentSite?.name;
	};

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

	const siteSelectedRoles = isSiteView
		? form.roles.find((roleSite: ISiteRoles) => roleSite.siteId === site?.id || roleSite.siteId === "all")
		: undefined;

	const rolesAll = form.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 = form.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.";

	return (
		<>
			<RouteLeavingGuard when={isDirty} action={action} text={text} allowedRoutes={allowedRoutes} />
			{!isOpen && <ErrorToast size="l" />}

			<S.Wrapper>
				<S.Header>
					<S.AvatarWrapper>
						<ProfileImage imageUrl={image?.url} handleImage={handleImageChange} />
					</S.AvatarWrapper>
					<S.UserName>
						<S.SubTitle>USER DATA</S.SubTitle>
						<S.NameTitle>{user.name}</S.NameTitle>
					</S.UserName>
				</S.Header>
				<FieldsBehavior
					title="Name"
					name="name"
					fieldType="TextField"
					placeholder="Type a name"
					mandatory
					value={name}
					onChange={handleNameChange}
					disabled={isEditDisabled}
				/>
				<FieldsBehavior
					title="Email"
					name="email"
					fieldType="TextField"
					placeholder="Type an email"
					mandatory
					value={email}
					onChange={handleEmailChange}
					disabled={isSameUser || isEditDisabled}
				/>
				<FieldsBehavior
					title="Alias"
					name="username"
					fieldType="TextField"
					placeholder="Type an alias"
					mandatory
					value={username}
					onChange={handleUsernameChange}
					prefix="@"
					disabled={isEditDisabled}
				/>
				<FieldsBehavior
					title="Company"
					name="company"
					fieldType="TextField"
					placeholder="Type a company"
					value={company || ""}
					onChange={handleCompanyChange}
					disabled={isEditDisabled}
				/>
				{isSameUser && (
					<FieldsBehavior
						title="Password"
						name="password"
						fieldType="TextField"
						inputType="password"
						placeholder="Type a password"
						mandatory
						readonly
						value="********"
						icon="edit"
						onClickIcon={toggleModal}
					/>
				)}
				<FieldsBehavior
					title="Job title"
					name="position"
					fieldType="TextField"
					placeholder="Type a job"
					value={position || ""}
					onChange={handlePositionChange}
					disabled={isEditDisabled}
				/>
				<FieldsBehavior
					title="Time zone"
					name="timezone"
					fieldType="Select"
					value={timezone}
					options={timezones}
					onChange={handleTimezoneChange}
					mandatory={true}
					disabled={isEditDisabled}
				/>
				{isSiteView ? (
					isSuperAdmin ? (
						<>
							<S.SettingsWrapper>
								<S.Heading>Roles assigned</S.Heading>
								<S.SettingContent>
									<OptionItem
										name="superadmin"
										title="Super admin"
										description="You can manage all aspects of your site, including inviting people and managing their permissions."
										onChange={toggleSuperAdmin}
										value={isSuperAdmin}
										readOnly={readOnlySites}
									/>
								</S.SettingContent>
							</S.SettingsWrapper>
						</>
					) : (
						<>
							<S.SettingsWrapper>
								<S.HeadingWrapper>
									<S.Heading>Roles Assigned</S.Heading>
									{(!siteSelectedRoles || siteSelectedRoles.roles.length === 0) && (
										<Button type="button" buttonStyle="text" onClick={toggleRoleModal} 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>
								{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 && !isSameUser && (
									<Button type="button" buttonStyle="line" onClick={toggleRoleModal}>
										Manage user roles
									</Button>
								)}
							</S.RoleList>
							<RolesModal
								isOpen={isOpenRoleModal}
								toggleModal={toggleRoleModal}
								roles={roles}
								addRoles={handleAddSiteRoles}
								selectedRoles={siteSelectedRoles ? siteSelectedRoles.roles : []}
								allSites={siteSelectedRoles && siteSelectedRoles.siteId === "all"}
								isGlobal={false}
							/>
						</>
					)
				) : (
					<>
						{!readOnlySites && (
							<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={handleChangeType}
									value={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={handleChangeType}
									value={!isSuperAdmin}
								/>
								<S.HelpText>Show the diference between types & roles in our Documentation</S.HelpText>
							</S.OptionsWrapper>
						)}
						{isSuperAdmin && readOnlySites && (
							<S.SettingsWrapper>
								<S.Heading>Sites & roles assigned</S.Heading>
								<S.SettingContent>
									<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={isSuperAdmin}
										readOnly={readOnlySites}
									/>
								</S.SettingContent>
							</S.SettingsWrapper>
						)}
						{!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}
										readOnly={readOnlySites}
									/>
								</S.GlobalPermissionsFieldWrapper>
								<S.SettingsWrapper>
									<S.Heading>Sites & roles assigned</S.Heading>
									{form.roles.length > 0 ? (
										<S.SettingContent>
											<S.SettingText>
												{readOnlySites
													? "You have access to this sites and this specific roles for each one."
													: !rolesAll
														? "You can give access to one or more sites to this user and asigned specific roles."
														: "You can give access to all sites at the same time."}
											</S.SettingText>
										</S.SettingContent>
									) : null}

									<S.SiteList>
										{!rolesAll &&
											form.roles.map((siteRole: ISiteRoles, index: number) => {
												if (siteRole.siteId !== "all" && siteRole.siteId !== "global") {
													const siteName = getSiteName(siteRole.siteId);
													if (!siteName) return <></>;
													return (
														<SiteItem
															readOnly={readOnlySites}
															disabled={!!rolesAll}
															sites={sitesID}
															key={`${index}${siteName}`}
															item={{ name: siteName, id: siteRole.siteId, onChange: selectSite }}
															selected={siteRole.roles}
															roles={roles}
															addRoles={handleAddRoles}
														/>
													);
												} else {
													return null;
												}
											})}
									</S.SiteList>
									{!!rolesAll && (
										<S.SelectAllSitesFieldWrapper>
											<SiteItem
												readOnly={readOnlySites}
												sites={sitesID}
												item={{ name: "Access to All Sites", id: "all", onChange: selectSite }}
												featured={true}
												description={allDescription}
												roles={roles}
												selected={rolesAll ? rolesAll.roles : []}
												addRoles={handleAddRoles}
											/>
										</S.SelectAllSitesFieldWrapper>
									)}
									{!showMore && !readOnlySites ? <ShowMoreButton /> : null}
								</S.SettingsWrapper>
								{showMore ? (
									<>
										<S.SubTitle>Sites list</S.SubTitle>
										<S.SearchFieldWrapper>
											<SearchField
												disabled={!!rolesAll}
												placeholder="Search"
												onChange={filterSitesList}
												searchOnEnter={false}
											/>
										</S.SearchFieldWrapper>
										{!rolesAll && (
											<S.SelectAllSitesFieldWrapper>
												<SiteItem
													readOnly={readOnlySites}
													sites={sitesID}
													item={{ name: "Access to All Sites", id: "all", onChange: selectSite }}
													featured={true}
													description={allDescription}
													roles={roles}
													selected={[]}
													addRoles={handleAddRoles}
												/>
											</S.SelectAllSitesFieldWrapper>
										)}
										<S.SiteList>
											{sitesList.length > 0 &&
												sitesList.map((site: ISite) => {
													const rolesSite = form.roles.find((roleSite: any) => roleSite.siteId === site.id);
													return (
														!form.roles.find((roleSite: ISiteRoles) => roleSite.siteId === site.id) && (
															<SiteItem
																readOnly={readOnlySites}
																disabled={!!rolesAll}
																sites={sitesID}
																key={site.id}
																item={{ name: site.name, id: site.id, onChange: selectSite }}
																selected={rolesSite ? rolesSite.roles : []}
																roles={roles}
																addRoles={handleAddRoles}
															/>
														)
													);
												})}
										</S.SiteList>
										{showMore && form.roles.length > 0 && !readOnlySites ? <ShowMoreButton /> : null}
									</>
								) : null}
							</S.MemberWrapper>
						)}
					</>
				)}
			</S.Wrapper>
			<PasswordModal {...modalProps} />
			<TypeChangeModal {...modalTypeChangeProps} />
		</>
	);
};

const mapStateToProps = (state: IRootState) => ({
	isSaving: state.app.isSaving,
	isLoading: state.app.isLoading,
	currentUser: state.users.currentUser,
	sites: state.sites.allSites,
	roles: state.users.roles,
});

interface IDispatchProps {
	setHistoryPush(path: string): Promise<void>;
}

const mapDispatchToProps = {
	setHistoryPush: appActions.setHistoryPush,
};

interface IProfileProps {
	user: IUser;
	form: IUser;
	isSaving: boolean;
	isLoading: boolean;
	setForm: (form: IUser) => void;
	currentUser: IUser | null;
	sites: ISite[];
	readOnlySites?: boolean;
	isSiteView?: boolean;
	roles: IRole[];
	site: ISite | null;
}

type IProps = IProfileProps & IDispatchProps;

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