import { useEffect, useRef, useState } from "react";
import { withErrorBoundary } from "react-error-boundary";
import { connect } from "react-redux";
import type { RouteComponentProps } from "react-router-dom";

import {
	CancelScheduleModal,
	ErrorPage,
	ErrorToast,
	HeadingsPreviewModal,
	KeywordsPreviewModal,
	Loading,
	MainWrapper,
	Modal,
	Notification,
	OcassionalToast,
	RestoreModal,
	ScheduleModal,
} from "@ax/components";
import { appActions } from "@ax/containers/App";
import { pageEditorActions } from "@ax/containers/PageEditor";
import { pageStatus } from "@ax/containers/PageEditor/interfaces";
import { sitesActions } from "@ax/containers/Sites";
import { structuredDataActions } from "@ax/containers/StructuredData";
import { usersActions } from "@ax/containers/Users";
import { RouteLeavingGuard } from "@ax/guards";
import { dateToString, getDefaultTheme } from "@ax/helpers";
import { useIsDirty, useModals, usePermissions } from "@ax/hooks";
import type {
	HeadingFilter,
	IErrorItem,
	ILanguage,
	INotification,
	IPageLanguage,
	IRootState,
	ISavePageParams,
	ISite,
	IUserEditing,
} from "@ax/types";

import Editor from "./Editor";
import Preview from "./Preview";

import * as S from "./style";

const GlobalEditor = (props: IProps) => {
	const {
		pageID,
		isLoading,
		isSaving,
		pageName,
		lang,
		setLanguage,
		createNewTranslation,
		globalLangs,
		pageLanguages,
		getPage,
		errors,
		setSelectedContent,
		setTab,
		editorContent,
		sitePageID,
		setHistoryPush,
		setCurrentPageID,
		setCurrentSiteInfo,
		savedSiteInfo,
		userEditing,
		isNewTranslation,
		currentSiteErrorPages,
		getUserCurrentPermissions,
		schedulePublication,
		restorePage,
		updateEditorContent,
		schemaVersion,
	} = props;

	const isAllowedTo = usePermissions({
		publishPages: "global.globalData.publishUnpublishAllGlobalData",
		createPages: "global.globalData.createAllGlobalData",
		deletePages: "global.globalData.deleteAllGlobalData",
		editContentPages: "global.globalData.editAllGlobalData",
	});

	const defaultTab = isAllowedTo.editContentPages ? "edit" : "view";

	const [isReadOnly, setIsReadOnly] = useState(false);
	const [selectedTab, setSelectedTab] = useState(defaultTab);
	const [notification, setNotification] = useState<INotification | null>(null);
	const [toastMsg, setToastMsg] = useState<string | null>(null);
	const [errorPagesChecked, setErrorPagesChecked] = useState(false);
	const [headingsFilter, setHeadingsFilter] = useState<HeadingFilter>("all");
	const [keywordsFilter, setKeywordsFilter] = useState<string[]>([]);
	const [scheduleDate, setScheduleDate] = useState({
		date: dateToString(new Date(), "yyy/MM/dd"),
		time: "12:00 am",
	});
	const [pendingNavigateCallback, setPendingNavigateCallback] = useState<(() => void) | null>(null);
	const browserRef = useRef<HTMLDivElement>(null);

	const { isOpen, toggleModal } = useModals([
		"userEditing",
		"unpublish",
		"schedule",
		"cancelSchedule",
		"restore",
		"headingsPreview",
		"keywordsPreview",
		"dirtyNavigate",
	]);

	const { isDirty, setIsDirty, resetDirty } = useIsDirty(editorContent, isNewTranslation);

	const isPublished = props.pageStatus === pageStatus.PUBLISHED || props.pageStatus === pageStatus.UPLOAD_PENDING;
	const isDraft = props.pageStatus === pageStatus.MODIFIED || !!editorContent.draftFromPage;
	const hasDraft: boolean = editorContent && !!editorContent.haveDraftPage;
	const isLivePageChanged = editorContent?.liveChanged;
	const structuredData = editorContent ? editorContent.structuredData : "";
	const isEditLive = isPublished && hasDraft;
	const isScheduled = props.pageStatus === pageStatus.SCHEDULED;
	const isDeleted = editorContent.deleted;
	const defaultContentTab = "content";

	const errorNotificationText =
		"There are some errors on the page so you can not publish yet. Please review them in the error panel.";
	const validatedNotificationText = "Everything seems ok, you can publish the page.";

	const deletedNotificationText =
		"This page has been deleted and can’t be edited. It will be permanently removed from the trash after 30 days.";
	const globalNotificationText = "You’ re working on the Global Page. Make sure you want to make changes to this page.";

	const modifiedNotificationText =
		"You made some changes to the Live version that aren't implemented on this Draft. Check it out before you continue working.";

	const backLinkRoute = "/data";

	const theme = getDefaultTheme();

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		const { pageID, getPage, sendPagePing, setStructuredDataFilter } = props;

		editorContent?.structuredData && setStructuredDataFilter(editorContent.structuredData);
		const handleGetPage = async () => await getPage(pageID, true);
		setTab(defaultContentTab);
		setToastMsg(null);
		handleGetPage();
		if (!pageID) {
			setIsDirty(false);
		}

		const interval = setInterval(() => {
			pageID && sendPagePing(pageID);
		}, 30000);
		return () => clearInterval(interval);
	}, []);

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		resetDirty();
	}, [lang]);

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		const { pageID, sendPagePing, currentUserID } = props;
		if (userEditing && userEditing.id !== currentUserID) {
			setIsReadOnly(true);
			!isOpen("userEditing") && toggleModal("userEditing");
		} else {
			setIsReadOnly(false);
			pageID && sendPagePing(pageID);
			isOpen("userEditing") && toggleModal("userEditing");
		}
	}, [userEditing]);

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		if (!errorPagesChecked && !isLoading && editorContent) {
			const pageId = editorContent.id;
			const hasErrors = currentSiteErrorPages.some((errorPageId) => pageId === errorPageId);
			hasErrors && reviewPage();
			setErrorPagesChecked(true);
		}
	}, [editorContent]);

	const setRoute = (path: string) => props.setHistoryPush(path, true);

	const removePage = async () => {
		const { deletePage } = props;
		const path = "/data";

		const deleted = await deletePage();

		if (deleted) {
			setRoute(path);
		}
	};

	const publishPage = async () => {
		const { updatePageStatus, savePage, pageID, validatePage, skipReviewOnPublish } = props;

		const validated = skipReviewOnPublish ? true : await validatePage(true);

		if (validated) {
			const publishPage = {
				status: pageStatus.UPLOAD_PENDING,
			};

			const isSaved =
				pageID && !isNewTranslation
					? await updatePageStatus([pageID], pageStatus.UPLOAD_PENDING)
					: await savePage({ publishPage });

			if (isSaved) {
				resetDirty();
			}
		} else {
			setNotification({ text: errorNotificationText, type: "error" });
		}
	};

	const publishChanges = async () => {
		const { savePage, validatePage, skipReviewOnPublish } = props;

		const validated = skipReviewOnPublish ? true : await validatePage(true);

		if (validated) {
			const publishPage = {
				status: pageStatus.UPLOAD_PENDING,
			};

			const isSaved = await savePage({ publishPage });
			if (isSaved) {
				resetDirty();
			}
		} else {
			setNotification({ text: errorNotificationText, type: "error" });
		}
	};

	const unpublishPage = async () => {
		const { updatePageStatus, pageID } = props;

		const isSaved = await updatePageStatus([pageID], pageStatus.OFFLINE_PENDING);
		if (isSaved) {
			resetDirty();
		}
	};

	const reviewPage = async () => {
		const { validatePage } = props;
		const validated = await validatePage(false);
		if (validated) {
			setNotification({ text: validatedNotificationText, type: "success" });
		} else {
			setNotification({ text: errorNotificationText, type: "error" });
		}
	};

	const handlePublishDraft = async () => {
		const { savePage, validatePage, skipReviewOnPublish } = props;

		const validated = skipReviewOnPublish ? true : await validatePage(true);

		if (validated) {
			const isSaved = await savePage({ publishDraft: true });
			if (isSaved) resetDirty();
		} else {
			setNotification({ text: errorNotificationText, type: "error" });
		}
	};

	const handleDiscardDraft = () => {
		const { discardDraft } = props;
		resetDirty();
		discardDraft();
	};

	const handleDiscarChanges = () => {
		const { getPage, pageID } = props;
		resetDirty();
		getPage(pageID, true);
	};

	const handleCreateDraft = async () => {
		const { savePage } = props;

		const isSaved = await savePage({ createDraft: true });
		if (isSaved) resetDirty();
	};

	const handleSchedulePublication = async () => {
		const date = new Date(`${scheduleDate.date} ${scheduleDate.time}`);
		const dateString = dateToString(date, "dd/MM/yyyy HH:mm:ss");
		const saved = await schedulePublication(dateString, isDraft);
		if (saved) {
			resetDirty();
			toggleModal("schedule");
		}
	};

	const handleCancelSchedulePublication = async () => {
		const saved = await schedulePublication(null, isDraft);
		if (saved) {
			setScheduleDate({ date: "", time: "12:00 am" });
			resetDirty();
			toggleModal("cancelSchedule");
		}
	};

	const getPublishButton = (status: string) => {
		switch (status) {
			case pageStatus.OFFLINE:
			case pageStatus.OFFLINE_PENDING:
				return {
					label: status === pageStatus.OFFLINE_PENDING ? "Cancel Unpublishing" : "Publish",
					action: publishPage,
				};
			case pageStatus.PUBLISHED:
			case pageStatus.UPLOAD_PENDING:
				return !hasDraft && isDirty
					? {
							label: "Create new draft",
							action: handleCreateDraft,
						}
					: {
							label: status === pageStatus.UPLOAD_PENDING ? "Cancel publication" : "Unpublish",
							action: hasDraft ? () => toggleModal("unpublish") : unpublishPage,
						};
			case pageStatus.MODIFIED:
			case pageStatus.SCHEDULED:
				return {
					label: isDraft ? "Publish changes" : "Publish",
					action: isDraft ? handlePublishDraft : publishPage,
				};
			default:
				return null;
		}
	};

	const menuOptions = [];

	if (isAllowedTo.publishPages && !isScheduled && !isPublished && props.pageStatus !== pageStatus.OFFLINE_PENDING) {
		menuOptions.push({
			label: "Schedule",
			icon: "calendar",
			action: () => toggleModal("schedule"),
		});
	}

	if (isAllowedTo.publishPages && isScheduled) {
		menuOptions.push({
			label: "Cancel Schedule",
			icon: "cancelEvent",
			action: () => toggleModal("cancelSchedule"),
		});
	}

	if (
		isAllowedTo.editContentPages &&
		(props.pageStatus === pageStatus.PUBLISHED ||
			props.pageStatus === pageStatus.OFFLINE ||
			props.pageStatus === pageStatus.OFFLINE_PENDING ||
			props.pageStatus === pageStatus.SCHEDULED ||
			(isDraft && isDirty))
	) {
		menuOptions.push({
			label: "Review",
			icon: "question",
			action: reviewPage,
		});
	}

	if (isAllowedTo.editContentPages && !isScheduled && (isDraft || (isPublished && isDirty))) {
		menuOptions.push({
			label: "Discard changes",
			icon: "close",
			action: isDraft ? handleDiscardDraft : handleDiscarChanges,
		});
	}

	if (props.pageStatus === pageStatus.PUBLISHED && !hasDraft && isDirty && isAllowedTo.publishPages) {
		menuOptions.push({
			label: "Unpublish",
			icon: "offline",
			action: isDraft ? () => toggleModal("unpublish") : unpublishPage,
		});
	}

	if (!isDraft && isAllowedTo.deletePages) {
		menuOptions.push({
			label: "Delete page",
			icon: "delete",
			action: removePage,
		});
	}

	const downArrowMenu = {
		displayed: !isReadOnly && !isDeleted,
		button: isAllowedTo.publishPages ? getPublishButton(props.pageStatus) : undefined,
		options: menuOptions,
	};

	const isEditable = editorContent?.editable;

	const handleSavePage = async (setToast?: (msg: string) => void) => {
		const { savePage } = props;

		const isSaved = await savePage({ setToast });
		if (isSaved) {
			resetDirty();
			setToastMsg(null);
		}
	};

	const goToPages = (path: string) => setRoute(path);

	const goToError = async (editorID: number | null, tab: string, template: boolean, parentEditorID?: number) => {
		const realEditorID = parentEditorID ? parentEditorID : template ? 0 : editorID;
		if (realEditorID !== null) {
			await setSelectedContent(realEditorID);
			setTab(tab);
		}
	};

	const goToPackage = () => setHistoryPush("/sites/settings/content-types", false);

	const modalText = (
		<>
			Some content <strong>is not saved</strong> on this page.
		</>
	);

	const getSaveLabel = () => {
		switch (props.pageStatus) {
			case pageStatus.PUBLISHED:
			case pageStatus.UPLOAD_PENDING:
				return !isDirty && !isNewTranslation ? "Saved" : isPublished && hasDraft ? "Save & publish" : "Publish changes";
			default:
				return !pageID || isNewTranslation || (isDirty && props.pageStatus !== pageStatus.MODIFIED)
					? "Save"
					: isDirty && props.pageStatus === pageStatus.MODIFIED
						? "Save draft"
						: "Saved";
		}
	};

	const rightButtonProps = isAllowedTo.editContentPages
		? {
				label: isSaving ? "Saving" : getSaveLabel(),
				disabled: (!isDirty && pageID !== null && !isNewTranslation) || isSaving || isReadOnly,
				action: isPublished ? publishChanges : handleSavePage,
			}
		: undefined;

	const goToLivePage = () => {
		const currentPageUrl = editorContent.fullUrl;
		if (currentPageUrl) {
			window.open(currentPageUrl, "_blank");
		}
	};

	const executeToggleDraftPage = async () => {
		const { getPage } = props;
		const pageID = isDraft ? editorContent.draftFromPage : editorContent.haveDraftPage;
		await getPage(pageID);
		resetDirty(true, true);
	};

	const toggleDraftPage = () => {
		if (isDirty) {
			onNavigateWithDirty(executeToggleDraftPage);
			return;
		}
		executeToggleDraftPage();
	};

	const onNavigateWithDirty = (navigateCallback: () => void) => {
		setPendingNavigateCallback(() => navigateCallback);
		toggleModal("dirtyNavigate");
	};

	const handleConfirmDirtyNavigation = () => {
		toggleModal("dirtyNavigate");
		if (pendingNavigateCallback) {
			pendingNavigateCallback();
			setPendingNavigateCallback(null);
		}
	};

	const handleCancelDirtyNavigation = () => {
		toggleModal("dirtyNavigate");
		setPendingNavigateCallback(null);
	};

	let pageStatusActions =
		props.pageStatus === pageStatus.PUBLISHED || isDraft
			? [
					{
						label: "Go to live page",
						icon: "view",
						action: goToLivePage,
					},
				]
			: [];

	pageStatusActions =
		isDraft || hasDraft
			? [
					{
						label: isDraft ? "View live" : "Edit draft",
						icon: isDraft ? "active" : "modified",
						action: toggleDraftPage,
					},
					...pageStatusActions,
				]
			: pageStatusActions;

	const goBackToSite = () => {
		if (sitePageID) {
			setCurrentSiteInfo(savedSiteInfo);
			setCurrentPageID(sitePageID);
			getUserCurrentPermissions();
			const path = "/sites/pages/editor";
			setHistoryPush(path, true);
		}
	};

	const handleGoBack = () => {
		props.setHistoryPush(backLinkRoute, true);
	};

	const mainAction = { title: "Preview Page", onClick: toggleModal };
	const secondaryAction = { title: "Ok, go back", onClick: handleGoBack };

	const mainUnpublishAction = { title: "Ok", onClick: () => toggleModal("unpublish") };

	const mainScheduleModalAction = {
		title: "Schedule",
		onClick: handleSchedulePublication,
	};

	const secondaryScheduleModalAction = {
		title: "Cancel",
		onClick: () => toggleModal("schedule"),
	};

	const mainCancelScheduleModalAction = {
		title: "Cancel Schedule",
		onClick: handleCancelSchedulePublication,
	};

	const secondaryCancelScheduleModalAction = {
		title: "Back",
		onClick: () => toggleModal("cancelSchedule"),
	};

	const tabIcons = isAllowedTo.editContentPages
		? [
				{ name: "edit", text: "Edit mode" },
				{ name: "view", text: "Preview mode" },
			]
		: [{ name: "view", text: "Preview mode" }];

	const handleSelectedTab = async (tab: string) => {
		if (tab === "view" && (!isPublished || isDraft)) {
			handleSavePage(setToastMsg);
		}
		setSelectedTab(tab);
	};

	const tabsPreview = {
		icons: tabIcons,
		selectedTab,
		action: (tab: string) => handleSelectedTab(tab),
		disabled: isOpen("headingsPreview") || isOpen("keywordsPreview"),
	};

	const filteredLanguages = globalLangs.filter((lang) =>
		pageLanguages.find((pageLang) => lang.id === pageLang.languageId),
	);

	const contentLanguages: ILanguage[] = [];
	pageLanguages.forEach((pageLang) => {
		const contentLang = globalLangs.find((lang) => lang.id === pageLang.languageId);
		if (contentLang) {
			contentLanguages.push(contentLang);
		}
	});

	const getSelectedPageLanguage = (language: ILanguage) =>
		pageLanguages.find((pageLang) => pageLang.languageId === language.id);

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

		const selectedPageLanguage = getSelectedPageLanguage(language);

		if (selectedPageLanguage) {
			createNewTranslation(false);
			setCurrentPageID(selectedPageLanguage.pageId);
			await getPage(selectedPageLanguage.pageId, true, isDraft);
			resetDirty();
		} else {
			isAllowedTo.editContentPages && setSelectedTab("edit");
			createNewTranslation(true);
			await getPage(pageID, true);
		}
	};

	const handleRestorePage = async () => {
		const isRestored = await restorePage(pageID);
		if (isRestored) {
			isOpen("restore") && toggleModal("restore");
			await getPage(pageID);
		}
	};

	const handleAddKeywords = (newKeywords: string[]) => {
		const keywords: string[] = [...editorContent.metaKeywords, ...newKeywords];
		updateEditorContent(0, "metaKeywords", keywords);
		handleSavePage();
	};

	const handledeleteKeyword = (keyword: string) => {
		const newKeywords = (editorContent.metaKeywords as string[]).filter((key) => key !== keyword);
		updateEditorContent(0, "metaKeywords", newKeywords);
		handleSavePage();
	};

	const handleToggleHeadingsEditor = () => {
		toggleModal("headingsPreview");
		setTab(defaultContentTab);
	};

	const handleToggleKeywordsEditor = () => {
		toggleModal("keywordsPreview");
		setTab(defaultContentTab);
	};

	return isLoading ? (
		<Loading />
	) : (
		<>
			<RouteLeavingGuard when={isDirty} action={goToPages} text={modalText} />
			<MainWrapper
				title={pageName}
				subtitle={structuredData}
				backLink={backLinkRoute}
				rightButton={rightButtonProps}
				downArrowMenu={downArrowMenu}
				fixedAppBar={true}
				pageStatus={props.pageStatus}
				language={lang}
				languageAction={handleLanguage}
				availableLanguages={isAllowedTo.createPages && !isDeleted ? globalLangs : filteredLanguages}
				currentLanguages={contentLanguages}
				currentPageID={pageID}
				fullWidth={true}
				errors={errors}
				errorActions={{ goToError, goToPackage }}
				inversed={true}
				isFromEditor={true}
				pageStatusActions={pageStatusActions}
				tabs={tabsPreview}
				isDirty={isDirty}
				scheduledPublication={editorContent?.publicationScheduled}
				isSaving={isSaving}
			>
				{selectedTab === "edit" ? (
					<>
						{isLivePageChanged && (
							<S.NotificationWrapper>
								<Notification type="warning" text={modifiedNotificationText} />
							</S.NotificationWrapper>
						)}
						{isDeleted && (
							<S.NotificationWrapper>
								<Notification
									type="error"
									text={deletedNotificationText}
									btnText="Restore page"
									onClick={() => toggleModal("restore")}
								/>
							</S.NotificationWrapper>
						)}
						{sitePageID && (
							<S.NotificationWrapper>
								<Notification type="info" text={globalNotificationText} btnText="Go Back" onClick={goBackToSite} />
							</S.NotificationWrapper>
						)}
						{notification && (
							<S.NotificationWrapper>
								<Notification
									type={notification.type}
									text={notification.text}
									btnText={notification.btnText}
									onClick={notification.onClick}
									resetError={() => setNotification(null)}
								/>
							</S.NotificationWrapper>
						)}
						<ErrorToast size="l" fixed />
						<S.Content>
							<Editor
								isGlobal={true}
								isEditable={isEditable}
								isReadOnly={isReadOnly}
								theme={theme}
								browserRef={browserRef}
								setNotification={setNotification}
								isEditLive={isEditLive}
								isDisabled={isDeleted}
								toggleHeadingsPreview={handleToggleHeadingsEditor}
								isHeadingsPreviewOpen={isOpen("headingsPreview")}
								headingsFilter={headingsFilter}
								toggleKeywordsPreview={handleToggleKeywordsEditor}
								isKeywordsPreviewOpen={isOpen("keywordsPreview")}
								keywordsFilter={keywordsFilter}
							/>
						</S.Content>
					</>
				) : (
					<>
						<Preview theme={theme} />
						{toastMsg?.length && <OcassionalToast icon="warning" message={toastMsg} />}
					</>
				)}
				<Modal
					isOpen={isOpen("userEditing")}
					hide={() => toggleModal("userEditing")}
					size="S"
					title="This page is currently being edited"
					mainAction={mainAction}
					secondaryAction={secondaryAction}
				>
					{isOpen("userEditing") && (
						<S.ModalContent>
							<p>
								<strong>{userEditing?.name}</strong> is currently working on this page. You can preview the page but{" "}
								<strong>you cannot make changes to it</strong> until {userEditing?.name} leaves the page.
							</p>
						</S.ModalContent>
					)}
				</Modal>
				<Modal
					isOpen={isOpen("unpublish")}
					hide={() => toggleModal("unpublish")}
					size="S"
					title="Unpublish Modified Page"
					mainAction={mainUnpublishAction}
				>
					{isOpen("unpublish") && (
						<S.ModalContent>
							<p>
								There are some saved changes that are not published on this page. To Unpublish this page,{" "}
								<strong>you must publish these changes or discard them.</strong>
							</p>
						</S.ModalContent>
					)}
				</Modal>
				<ScheduleModal
					isOpen={isOpen("schedule")}
					toggleModal={() => toggleModal("schedule")}
					mainModalAction={mainScheduleModalAction}
					secondaryModalAction={secondaryScheduleModalAction}
					scheduleDate={scheduleDate}
					setScheduleDate={setScheduleDate}
				/>
				<CancelScheduleModal
					isOpen={isOpen("cancelSchedule")}
					toggleModal={() => toggleModal("cancelSchedule")}
					mainModalAction={mainCancelScheduleModalAction}
					secondaryModalAction={secondaryCancelScheduleModalAction}
				/>
				<RestoreModal
					isOpen={isOpen("restore")}
					toggleModal={() => toggleModal("restore")}
					{...{
						isChild: false,
						hasIssues: schemaVersion !== editorContent.schemaVersionTimestamp,
						restorePage: handleRestorePage,
					}}
				/>
				<HeadingsPreviewModal
					isOpen={isOpen("headingsPreview")}
					toggleModal={handleToggleHeadingsEditor}
					browserRef={browserRef}
					headingsFilter={headingsFilter}
					setHeadingsFilter={setHeadingsFilter}
				/>
				<KeywordsPreviewModal
					isOpen={isOpen("keywordsPreview")}
					toggleModal={handleToggleKeywordsEditor}
					browserRef={browserRef}
					keywords={editorContent?.metaKeywords || []}
					keywordsFilter={keywordsFilter}
					setKeywordsFilter={setKeywordsFilter}
					addKeywords={handleAddKeywords}
					deleteKeyword={handledeleteKeyword}
				/>
			</MainWrapper>
			<Modal
				isOpen={isOpen("dirtyNavigate")}
				hide={handleCancelDirtyNavigation}
				size="S"
				title="Unsaved changes"
				mainAction={{ title: "Yes, discard changes", onClick: handleConfirmDirtyNavigation }}
				secondaryAction={{ title: "Cancel", onClick: handleCancelDirtyNavigation }}
			>
				<S.ModalContent>
					Some content <strong>is not saved</strong> on this page. If you exit without saving it, it will be lost. Do
					you want to discard your changes?
				</S.ModalContent>
			</Modal>
		</>
	);
};

const mapStateToProps = (state: IRootState): IPageEditorStateProps => ({
	isSaving: state.app.isSaving,
	pageID: state.pageEditor.currentPageID as number,
	pageStatus: state.pageEditor.currentPageStatus as string,
	pageName: state.pageEditor.currentPageName,
	isLoading: state.app.isLoading,
	lang: state.app.lang,
	globalLangs: state.app.globalLangs,
	pageLanguages: state.pageEditor.currentPageLanguages,
	editorContent: state.pageEditor.editorContent,
	errors: state.pageEditor.errors,
	sitePageID: state.pageEditor.sitePageID,
	savedSiteInfo: state.sites.savedSiteInfo,
	userEditing: state.pageEditor.userEditing,
	currentUserID: state.users.currentUser?.id || null,
	isNewTranslation: state.pageEditor.isNewTranslation,
	currentSiteErrorPages: state.sites.currentSiteErrorPages,
	skipReviewOnPublish: state.app.globalSettings.skipReviewOnPublish,
	schemaVersion: state.structuredData.schemaVersion,
});

interface IPageEditorStateProps {
	pageID: number;
	pageStatus: string;
	pageName: string;
	isSaving: boolean;
	isLoading: boolean;
	lang: { locale: string; id: number | null };
	globalLangs: ILanguage[];
	pageLanguages: IPageLanguage[];
	editorContent: any;
	errors: IErrorItem[];
	sitePageID: number | null;
	savedSiteInfo: any;
	userEditing: IUserEditing | null;
	currentUserID: number | null;
	isNewTranslation: boolean;
	currentSiteErrorPages: number[];
	skipReviewOnPublish?: boolean;
	schemaVersion: string;
}

const mapDispatchToProps = {
	getPage: pageEditorActions.getPage,
	savePage: pageEditorActions.savePage,
	deletePage: pageEditorActions.deletePage,
	validatePage: pageEditorActions.validatePage,
	updatePageStatus: pageEditorActions.updatePageStatus,
	setHistoryPush: appActions.setHistoryPush,
	setLanguage: appActions.setLanguage,
	createNewTranslation: pageEditorActions.createNewTranslation,
	setTab: pageEditorActions.setTab,
	setSelectedContent: pageEditorActions.setSelectedContent,
	setCurrentPageID: pageEditorActions.setCurrentPageID,
	setCurrentSiteInfo: sitesActions.setCurrentSiteInfo,
	sendPagePing: pageEditorActions.sendPagePing,
	setStructuredDataFilter: structuredDataActions.setFilter,
	discardDraft: pageEditorActions.discardDraft,
	getUserCurrentPermissions: usersActions.getUserCurrentPermissions,
	schedulePublication: pageEditorActions.schedulePublication,
	restorePage: pageEditorActions.restorePage,
	updateEditorContent: pageEditorActions.updateEditorContent,
};

interface IPageEditorDispatchProps {
	getPage(pageID?: number, global?: boolean, preferDraft?: boolean): Promise<void>;
	savePage(data?: {
		createDraft?: boolean;
		publishPage?: { status: string };
		publishDraft?: boolean;
		setToast?: (msg: string) => void;
	}): Promise<boolean>;
	deletePage(params?: ISavePageParams): Promise<boolean>;
	validatePage(publish?: boolean): Promise<boolean>;
	updatePageStatus(id: number[], status: string): Promise<boolean>;
	setHistoryPush(path: string, isEditor: boolean): void;
	setLanguage(lang: { locale: string; id: number | null }): void;
	createNewTranslation(isNewTranslation: boolean): void;
	setTab(tab: string): void;
	setSelectedContent(editorID: number): Promise<void>;
	setCurrentSiteInfo(currentSiteInfo: ISite | null): void;
	setCurrentPageID(currentPageID: number): void;
	sendPagePing(pageID: number): Promise<boolean>;
	setStructuredDataFilter(filter: string | null): void;
	discardDraft(): Promise<void>;
	getUserCurrentPermissions(): Promise<void>;
	schedulePublication(date: string | null, isDraft: boolean): Promise<boolean>;
	restorePage(id: number | number[]): Promise<boolean>;
	updateEditorContent(selectedEditorID: number, key: string, value: any): void;
}

type IProps = IPageEditorStateProps & IPageEditorDispatchProps & RouteComponentProps;

const GlobalEditorWithErrorBoundary = withErrorBoundary(GlobalEditor, {
	fallback: <ErrorPage type="wrongEditor" />,
});

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