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

import { ErrorToast, MainWrapper, Notification, TableList, Toast } from "@ax/components";
import { appActions } from "@ax/containers/App";
import { menuActions, navigationActions } from "@ax/containers/Navigation";
import { capitalize, isMultipleNavigationModules } from "@ax/helpers";
import { useBulkSelection, useModal, usePermission, useToast } from "@ax/hooks";
import type { IFooter, IHeader, ILanguage, INavigation, IRootState, ISite } from "@ax/types";

import { NavigationModulesWarning } from "./atoms";
import BulkHeader from "./BulkHeader";
import DefaultItem from "./Item";
import DefaultNav from "./Nav";
import ReplaceNavModal from "./ReplaceNavModal";

import * as S from "./style";

const ITEMS_PER_PAGE = 50;
const DEFAULT_TYPES = ["Headers", "Footers"];

const DefaultsList = (props: IProps): JSX.Element => {
	const {
		currentDefaultsContent,
		lang,
		siteLanguages,
		setLanguage,
		totalItems,
		setSelectedDefault,
		getHeaders,
		getFooters,
		selectedDefault,
		setHistoryPush,
		setHeader,
		setFooter,
		restoreNavigation,
		deleteNavigation,
		getMenus,
		resetDefaultsValues,
		currentSiteInfo,
	} = props;

	const [isBulkLoading, setIsBulkLoading] = useState(false);
	const [page, setPage] = useState(1);
	const [deletedNav, setDeletedNav] = useState<number | number[] | null>(null);
	const [updatedPages, setUpdatedPages] = useState<number | null>(null);
	const { isVisible, toggleToast, setIsVisible } = useToast();
	const { isVisible: isPagesVisible, toggleToast: togglePagesToast, setIsVisible: setIsPagesVisible } = useToast();
	const [isScrolling, setIsScrolling] = useState(false);
	const tableRef = useRef<HTMLDivElement>(null);
	const [isNavigationNotificationOpen, setIsNavigationNotificationOpen] = useState(false);
	const { isOpen: isReplaceOpened, toggleModal: toggleReplaceModal } = useModal();

	const isAllowedToCreate = usePermission(`navigation.createSite${selectedDefault}`);
	const isAllowedToDelete = usePermission(`navigation.deleteSite${selectedDefault}`);

	const navIds = useMemo(() => currentDefaultsContent?.map((nav) => nav.id), [currentDefaultsContent]);

	const {
		resetBulkSelection,
		selectedItems,
		isSelected,
		areItemsSelected,
		checkState,
		addToBulkSelection,
		selectAllItems,
		setHoverCheck,
	} = useBulkSelection(navIds);

	const currentType = selectedDefault === "Headers" ? "header" : "footer";

	const showNavigationModulesWarning = isMultipleNavigationModules();

	useEffect(() => {
		const fetchDefaults = async () => {
			const params = {
				page,
				itemsPerPage: ITEMS_PER_PAGE,
				pagination: true,
				deleted: false,
				include_draft: false,
				selectedDefault,
				lang,
			};
			selectedDefault === "Headers" ? await getHeaders(params) : await getFooters(params);
		};
		fetchDefaults();
		if (tableRef.current) {
			tableRef.current.scrollTo(0, 0);
		}
	}, [lang, page, selectedDefault, getHeaders, getFooters]);

	useEffect(() => {
		const init = async (_lang: typeof lang) => {
			await resetDefaultsValues();
			await getMenus();
		};
		init(lang);
	}, [lang, resetDefaultsValues, getMenus]);

	useEffect(() => {
		const isNavigationModulesChanged = Boolean(
			currentSiteInfo?.navigationModules?.[currentType] &&
				currentDefaultsContent.some(
					(navigation) => navigation.component !== currentSiteInfo?.navigationModules?.[currentType],
				),
		);
		setIsNavigationNotificationOpen(isNavigationModulesChanged);
	}, [currentDefaultsContent, currentSiteInfo, currentType]);

	const handleClick = (newDefault: string) => {
		resetBulkSelection();
		setPage(1);
		setSelectedDefault(newDefault);
	};

	const setContent = (item: IHeader | IFooter) => {
		const { type, id } = item;
		type === "header" ? setHeader(id) : setFooter(id);
	};

	const addNewDefault = () => {
		setHeader(null);
		setFooter(null);
		setHistoryPush("/sites/navigations/editor", true);
	};

	const rightButtonProps = isAllowedToCreate
		? {
				label: "New",
				action: addNewDefault,
			}
		: undefined;

	const pagination = {
		setPage,
		itemsPerPage: ITEMS_PER_PAGE,
		totalItems,
		currPage: page,
	};

	const undoAction = async () => {
		if (deletedNav) {
			await restoreNavigation(deletedNav, currentType);
		}
		setIsVisible(false);
	};

	const toastProps = {
		action: undoAction,
		setIsVisible,
		message: deletedNav ? `${capitalize(currentType)} deleted` : "",
	};

	const toastPagesProps = {
		setIsVisible: setIsPagesVisible,
		message: `${updatedPages} pages updated with new ${currentType}s.`,
	};

	const handleToast = (pages: number) => {
		setUpdatedPages(pages);
		togglePagesToast();
	};

	const bulkDelete = async () => {
		setIsBulkLoading(true);
		const deleted = await deleteNavigation(selectedItems.all, currentType, toggleReplaceModal);
		setDeletedNav(selectedItems.all);
		if (deleted) {
			toggleToast();
		}
		setIsBulkLoading(false);
	};

	const onScroll = (e: React.UIEvent<HTMLDivElement>) => setIsScrolling((e.target as HTMLDivElement).scrollTop > 0);

	const bulkActions = isAllowedToDelete
		? [
				{
					icon: "delete",
					text: "delete",
					action: bulkDelete,
				},
			]
		: [];

	const TableHeader = useMemo(
		() => (
			<BulkHeader
				showBulk={areItemsSelected(navIds)}
				bulkActions={bulkActions}
				selectAllItems={selectAllItems}
				totalItems={totalItems}
				selectItems={() => (checkState.isAllSelected ? resetBulkSelection() : selectAllItems())}
				selectedItems={selectedItems}
				checkState={checkState}
				isScrolling={isScrolling}
				setHoverCheck={setHoverCheck}
				isLoading={isBulkLoading}
			/>
		),
		[
			areItemsSelected,
			navIds,
			bulkActions,
			selectAllItems,
			resetBulkSelection,
			totalItems,
			selectedItems,
			checkState,
			isScrolling,
			setHoverCheck,
			isBulkLoading,
		],
	);

	const goToSiteSettings = () => setHistoryPush("/sites/settings/globals");

	const handleLanguage = (language: ILanguage) => {
		const { locale, id } = language;
		setPage(1);
		setLanguage({ locale, id });
	};

	return (
		<MainWrapper
			title="Navigation modules"
			rightButton={rightButtonProps}
			language={lang}
			availableLanguages={siteLanguages}
			languageAction={handleLanguage}
		>
			<S.DefaultListWrapper>
				<DefaultNav current={selectedDefault} defaultTypes={DEFAULT_TYPES} onClick={handleClick} />
				<S.TableWrapper>
					<ErrorToast />
					{isNavigationNotificationOpen && (
						<Notification
							type="warning"
							text="The design of the navigation modules has changed. Please, check the previously created and save them."
						/>
					)}
					{showNavigationModulesWarning && <NavigationModulesWarning goTo={goToSiteSettings} />}
					<TableList
						tableHeader={TableHeader}
						pagination={pagination}
						onScroll={onScroll}
						hasFixedHeader={true}
						tableRef={tableRef}
					>
						{currentDefaultsContent?.map((defaultContent) => {
							const isItemSelected = isSelected(defaultContent.id);
							return (
								<DefaultItem
									defaultContent={defaultContent}
									key={defaultContent.id}
									languages={siteLanguages}
									lang={lang}
									toggleToast={toggleToast}
									setDeletedNav={setDeletedNav}
									isSelected={isItemSelected}
									onChange={addToBulkSelection}
									handleClick={setContent}
									setHistoryPush={setHistoryPush}
									toggleReplaceModal={toggleReplaceModal}
									hoverCheck={checkState.hoverCheck}
								/>
							);
						})}
					</TableList>
				</S.TableWrapper>
				{isVisible && <Toast {...toastProps} />}
				{isPagesVisible && <Toast {...toastPagesProps} />}
			</S.DefaultListWrapper>
			{isReplaceOpened && (
				<ReplaceNavModal
					isOpen={isReplaceOpened}
					toggleModal={toggleReplaceModal}
					type={currentType}
					navID={deletedNav}
					toggleToast={handleToast}
				/>
			)}
		</MainWrapper>
	);
};

const mapStateToProps = (state: IRootState) => ({
	siteLanguages: state.sites.currentSiteLanguages,
	lang: state.app.lang,
	selectedDefault: state.navigation.selectedDefault,
	currentDefaultsContent: state.navigation.currentDefaultsContent,
	totalItems: state.navigation.totalItems,
	currentSiteInfo: state.sites.currentSiteInfo,
});

interface IDispatchProps {
	setLanguage(lang: { locale: string; id: number | null }): void;
	getHeaders(params: Record<string, unknown>): Promise<void>;
	getFooters(params: Record<string, unknown>): Promise<void>;
	setSelectedDefault(id: string): void;
	setHistoryPush(path: string, isEditor?: boolean): void;
	setHeader(id: number | null): void;
	setFooter(id: number | null): void;
	restoreNavigation(navID: number | number[], type: string): Promise<boolean>;
	deleteNavigation(navID: number[], type: string, errorAction: () => void): Promise<boolean>;
	getMenus(): Promise<void>;
	resetDefaultsValues(): Promise<void>;
}

interface IDefaultsProps {
	lang: { locale: string; id: number | null };
	siteLanguages: ILanguage[];
	selectedDefault: string;
	currentDefaultsContent: INavigation[];
	totalItems: number;
	currentSiteInfo: ISite | null;
}

type IProps = IDefaultsProps & IDispatchProps;

const mapDispatchToProps = {
	setHistoryPush: appActions.setHistoryPush,
	setLanguage: appActions.setLanguage,
	getHeaders: navigationActions.getHeaders,
	getFooters: navigationActions.getFooters,
	setSelectedDefault: navigationActions.setSelectedDefault,
	setHeader: navigationActions.setHeader,
	setFooter: navigationActions.setFooter,
	restoreNavigation: navigationActions.restoreNavigation,
	deleteNavigation: navigationActions.deleteNavigation,
	getMenus: menuActions.getMenus,
	resetDefaultsValues: navigationActions.resetDefaultsValues,
};

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