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

import { CheckField, Flag, FloatingMenu, Icon, LanguageMenu, Tag, Tooltip, TruncatedTooltip } from "@ax/components";
import { appActions } from "@ax/containers/App";
import { pageEditorActions } from "@ax/containers/PageEditor";
import { type ISetCurrentPageIDAction, pageStatus } from "@ax/containers/PageEditor/interfaces";
import {
	buildCategoryColumns,
	getHumanLastModifiedDate,
	getScheduleFormatDate,
	getTemplateDisplayName,
	slugify,
} from "@ax/helpers";
import { useModals, usePermissions } from "@ax/hooks";
import type {
	ICheck,
	IColumn,
	IDataPack,
	ILanguage,
	IPage,
	IPageLanguage,
	IRootState,
	ISavePageParams,
	ISchemaField,
	ISite,
} from "@ax/types";

import { config } from "components";

import { CopyModal, DeleteModal, DuplicatePageModal, RemovePageModal, UnpublishPageModal } from "../atoms";

import * as S from "./style";

const schemas = config.schemas.ui;

const PageItem = (props: IPageItemProps): JSX.Element => {
	const {
		functions,
		item,
		activatedTemplates,
		toggleToast,
		setRemovedPage,
		columns,
		categoryColumns,
		categoryColors,
		addCategoryColors,
		dataPacks,
		sites,
		skipReview,
		hoverCheck,
		createNewTranslation,
		setLanguage,
		isSaving,
	} = props;
	const { isSelected, siteLanguages, page, lang, isDuplicable } = item;
	const {
		onClick,
		onCheck,
		deletePage,
		getSiteContent,
		setHistoryPush,
		updatePageStatus,
		setCurrentPageID,
		duplicatePage,
		validatePage,
		getPage,
		removePageFromSite,
		deleteBulk,
		getDataPack,
		setTemplateInstanceError,
		toggleCopiedToast,
	} = functions;
	const { locale } = lang;
	const {
		pageLanguages,
		isHome,
		fullPath,
		canBeUnpublished,
		origin,
		manuallyImported,
		templateId,
		structuredDataContent,
		liveStatus,
		publicationScheduled,
		haveDraftPage,
		title,
	} = page;

	const displayName = getTemplateDisplayName(templateId);

	const initValue = { title: "", slug: "" };
	const [site, setSite] = useState(null);
	const [modalState, setModalState] = useState(initValue);
	const [deleteAllVersions, setDeleteAllVersions] = useState(false);
	const { toggleModal, isOpen } = useModals(["duplicate", "remove", "unpublish", "delete", "copy"]);

	const isAllowedTo = usePermissions({
		duplicatePages: "content.duplicatePages",
		publishUnpublishPages: "content.publishUnpublishPages",
		createPages: "content.createPages",
		copyPageInOtherSite: "content.copyPageInOtherSite",
		deletePages: "content.deletePages",
		deletePublishedPages: "content.deletePublishedPages",
		editContentPages: "content.editContentPages",
	});

	const currentTemplateDataPacks = schemas.templates[templateId].dataPacks;

	const isCopyable = !currentTemplateDataPacks;
	const isGlobal = origin === "GLOBAL";
	const isTranslated = pageLanguages.length > 1;
	const activeColumns = columns.filter((col) => col.show).map((col) => col.id);
	const API_URL = process.env.GRIDDO_API_URL || process.env.REACT_APP_API_ENDPOINT;
	const isPublished = liveStatus?.status === pageStatus.PUBLISHED || liveStatus?.status === pageStatus.UPLOAD_PENDING;
	const isAllowedToDelete =
		(isPublished && isAllowedTo.deletePublishedPages) || (!isPublished && isAllowedTo.deletePages);
	const isScheduledPub = !!publicationScheduled && (liveStatus?.status === pageStatus.SCHEDULED || haveDraftPage);

	const publishedTooltip: Record<string, string> = {
		active: "Live",
		"upload-pending": "Publication pending",
		offline: "Offline",
		"offline-pending": "Offline pending",
		modified: "Live & Modified",
		scheduled: `Scheduled publication: ${isScheduledPub ? getScheduleFormatDate(publicationScheduled) : ""}`,
	};

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

	const goToPage = async () => {
		const pageID = page.haveDraftPage ? page.haveDraftPage : page.id;
		setCurrentPageID(pageID);

		const { templateId } = item.page;
		const dataPack = dataPacks.find((pack) => pack.templates.some((template) => template.id === templateId));
		dataPack && (await getDataPack(dataPack.id));

		setRoute("pages/editor");
	};

	const editLivePage = () => {
		setCurrentPageID(page.id);
		setRoute("pages/editor");
	};

	const handleOnChange = (value: ICheck) => onCheck(value);

	const checkSeoDone = (value: string | boolean) => {
		if (typeof value === "string") {
			value = value.trim();
		}
		if (value) {
			return (
				<S.StyledDone>
					<Icon name="done" />
				</S.StyledDone>
			);
		}
		return (
			<S.StyledClose>
				<Icon name="close" />
			</S.StyledClose>
		);
	};

	const SeoItems = {
		Index: () => <S.StyledSeo>{checkSeoDone(page.isIndexed)}Indexed</S.StyledSeo>,
		Title: () => <S.StyledSeo>{checkSeoDone(page.metaTitle)}Title</S.StyledSeo>,
		Description: () => <S.StyledSeo>{checkSeoDone(page.metaDescription)}Description</S.StyledSeo>,
	};

	const SeoTitleMenu = () => {
		if (page.metaTitle) {
			return (
				<FloatingMenu Button={SeoItems.Title}>
					<S.FloatingSeo>{page.metaTitle}</S.FloatingSeo>
				</FloatingMenu>
			);
		}
		return SeoItems.Title();
	};

	const SeoDescriptionMenu = () => {
		if (page.metaDescription) {
			return (
				<FloatingMenu Button={SeoItems.Description}>
					<S.FloatingSeo>{page.metaDescription}</S.FloatingSeo>
				</FloatingMenu>
			);
		}
		return SeoItems.Description();
	};

	const checkWorkflowStatus = () => {
		if (page.workflowStatus) {
			return <Tag type="status" color={page.workflowStatus.color} text={page.workflowStatus.text} />;
		}
	};

	const handleDeleteItem = async () => {
		const allPageVersions = pageLanguages.map((lang: IPageLanguage) => lang.pageId);
		deleteAllVersions ? deleteBulk(allPageVersions) : deletePage();
		toggleModal("delete");
	};

	const handleRemoveItemFromSite = async () => {
		await removePageFromSite(page.id).then((removed: boolean) => {
			if (removed && page.originalGlobalPage) {
				setRemovedPage(page.originalGlobalPage);
				toggleToast();
			}
			toggleModal("remove");
		});
	};

	const publishPage = async () => {
		await getPage(page.id);
		const isValidated = skipReview ? true : await validatePage(true);

		if (isValidated) {
			await updatePageStatus([page.id], pageStatus.UPLOAD_PENDING, true);
			await getSiteContent();
		}
	};

	const unpublishPage = async () => {
		await updatePageStatus([page.id], pageStatus.OFFLINE_PENDING, true);
		await getSiteContent();
	};

	const cancelPublishPage = async () => {
		await updatePageStatus([page.id], pageStatus.OFFLINE, true);
		await getSiteContent();
	};

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

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

		setLanguage({
			locale,
			id,
		});

		const selectedPageLanguage = getSelectedPageLanguage(language);
		selectedPageLanguage ? setCurrentPageID(selectedPageLanguage.pageId) : createNewTranslation(true);
		setHistoryPush("pages/editor", true);
	};

	const getCurrentPageLanguages = () => {
		const languages: ILanguage[] = [];

		pageLanguages.forEach((pageLang) => {
			siteLanguages?.forEach((siteLang) => {
				if (siteLang.id === pageLang.languageId) {
					languages.push(siteLang);
				}
			});
		});

		return languages;
	};

	const handleDuplicatePage = async () => {
		setTemplateInstanceError({ error: false, templateName: "" });
		if (isDuplicable) {
			const isDuplicated = await duplicatePage(page.id, modalState);
			if (isDuplicated) {
				toggleModal("duplicate");
				setRoute("pages/editor");
			}
		} else {
			toggleModal("duplicate");
			setModalState({ title: "", slug: "" });
			setTemplateInstanceError({ error: true, templateName: displayName });
		}
	};

	const handleCloseDuplicate = () => {
		toggleModal("duplicate");
		setModalState({ title: "", slug: "" });
	};

	const currentLanguages = getCurrentPageLanguages();

	const isTemplateActivated = activatedTemplates.some((temp: any) => temp.id === templateId);

	let availableLanguages = siteLanguages;

	if (!isTemplateActivated || isGlobal || !isAllowedTo.createPages) {
		const pageLanguagesIDs = pageLanguages.map((language: IPageLanguage) => language.languageId);
		availableLanguages = siteLanguages?.filter((language) => pageLanguagesIDs.includes(language.id));
	}

	const languageMenu = () => (
		<LanguageMenu
			language={locale}
			availableLanguages={availableLanguages || []}
			setLanguage={handleLanguage}
			currentLanguages={currentLanguages}
		/>
	);

	const FlagsButton = () => (
		<S.FlagsWrapper onClick={onClick}>
			{currentLanguages.slice(0, 2).map((pageLanguage: ILanguage, i: number) => (
				<Flag key={`${pageLanguage.language}${i}`} name={pageLanguage.locale} size="15" />
			))}
			<span>({currentLanguages.length})</span>
		</S.FlagsWrapper>
	);

	const handleNameChange = (value: string) => {
		setModalState({ title: value, slug: slugify(value) });
	};

	const handleSlugChange = (value: string) => {
		setModalState({ ...modalState, slug: value });
	};

	const deleteDisabled = isGlobal && (!manuallyImported || canBeUnpublished === false);
	const deleteHelpText =
		isGlobal && !manuallyImported
			? "This page has been provided by subscription. You cannot remove it."
			: canBeUnpublished === false
				? "This is the canonical site of the page. You cannot remove it."
				: null;

	let menuOptions: IPageOption[] = [];

	if (isAllowedToDelete) {
		menuOptions.push({
			label: isGlobal ? "Remove" : "delete",
			icon: "delete",
			action: () => toggleModal(isGlobal ? "remove" : "delete"),
			disabled: deleteDisabled,
			helpText: deleteHelpText,
		});
	}

	if (isCopyable && isAllowedTo.copyPageInOtherSite) {
		menuOptions.unshift({
			label: "Copy page in another site",
			icon: "copy",
			action: () => toggleModal("copy"),
		});
	}

	if (!isGlobal && isAllowedTo.duplicatePages) {
		menuOptions.unshift({
			label: "duplicate",
			icon: "duplicate",
			action: () => toggleModal("duplicate"),
		});
	}

	const getPublishItem = (status: string, canBeUnpublished: boolean) => {
		const helpText =
			canBeUnpublished === false ? "This is the canonical site of the page. You cannot unpublish it." : null;
		const disabled = canBeUnpublished === false;

		switch (status) {
			case pageStatus.OFFLINE:
			case pageStatus.OFFLINE_PENDING:
				return {
					label: "publish",
					icon: "upload-pending",
					action: publishPage,
				};
			case pageStatus.PUBLISHED:
				return {
					label: "unpublish",
					icon: "offline",
					action: page.haveDraftPage ? () => toggleModal("unpublish") : unpublishPage,
					disabled,
					helpText,
				};
			case pageStatus.UPLOAD_PENDING:
				return {
					label: "unpublish",
					icon: "offline",
					action: page.haveDraftPage ? () => toggleModal("unpublish") : cancelPublishPage,
					disabled,
					helpText,
				};
			default:
				return null;
		}
	};

	const viewPage = () => window.open(page.fullUrl || `${API_URL}/page/go/${page.id}`, "_blank");

	const viewOption = {
		label: "View online",
		icon: "View",
		action: viewPage,
	};

	const publishAction = getPublishItem(page.liveStatus?.status, canBeUnpublished);

	menuOptions = publishAction && isAllowedTo.publishUnpublishPages ? [publishAction, ...menuOptions] : menuOptions;

	const editOptions = [
		{
			label: "View live",
			icon: "active",
			action: editLivePage,
			color: true,
		},
	];

	if (isAllowedTo.editContentPages) {
		editOptions.unshift({
			label: "Edit draft",
			icon: "modified",
			action: goToPage,
			color: true,
		});
	}

	menuOptions = page.haveDraftPage ? [...editOptions, ...menuOptions] : menuOptions;

	menuOptions = page.liveStatus?.status === pageStatus.PUBLISHED ? [viewOption, ...menuOptions] : menuOptions;

	const GlobalMark = () => (
		<Tooltip content="Global Page">
			<S.Mark>G</S.Mark>
		</Tooltip>
	);

	const copyToOtherSite = () => {
		if (site) {
			const siteID = parseInt(site);

			duplicatePage(page.id, null, siteID).then((successEvent: boolean) => {
				if (successEvent === true) {
					toggleCopiedToast();
				}
				toggleModal("copy");
			});
		}
	};

	const getLiveStatus = () => (isScheduledPub ? "scheduled" : haveDraftPage ? "modified" : liveStatus?.status);

	const CategoryColumns = buildCategoryColumns(
		categoryColumns,
		activeColumns,
		structuredDataContent,
		categoryColors,
		addCategoryColors,
		goToPage,
	);

	return (
		<>
			<S.PageRow role="rowgroup" selected={isSelected} global={isGlobal}>
				<S.CheckCell role="cell">
					<CheckField name="check" value={page.id} checked={isSelected || hoverCheck} onChange={handleOnChange} />
				</S.CheckCell>
				<S.NameCell role="cell" onClick={goToPage}>
					{isHome && (
						<S.Home>
							<Icon name="home" />
							Home
						</S.Home>
					)}
					<TruncatedTooltip content={title} expanded top={-5}>
						<S.Title>{title}</S.Title>
					</TruncatedTooltip>
					{!isHome && (
						<TruncatedTooltip content={fullPath.page} expanded top={5}>
							<S.Slug>{fullPath.page}</S.Slug>
						</TruncatedTooltip>
					)}
				</S.NameCell>
				{activeColumns.includes("type") && (
					<S.TypeCell role="cell" onClick={goToPage}>
						{displayName}
					</S.TypeCell>
				)}
				{activeColumns.includes("live") && (
					<S.LiveCell role="cell" onClick={goToPage}>
						<Tooltip content={publishedTooltip[getLiveStatus()]}>
							<Icon name={getLiveStatus()} />
						</Tooltip>
					</S.LiveCell>
				)}
				{CategoryColumns}
				{activeColumns.includes("status") && (
					<S.StatusCell role="cell" onClick={goToPage}>
						{checkWorkflowStatus()}
						<S.ModDate>{`Mod. ${getHumanLastModifiedDate(page.modified)}`}</S.ModDate>
					</S.StatusCell>
				)}
				{activeColumns.includes("translation") && (
					<S.TransCell role="cell">
						<FloatingMenu Button={FlagsButton}>{languageMenu()}</FloatingMenu>
					</S.TransCell>
				)}
				{activeColumns.includes("seo") && (
					<S.SeoCell role="cell">
						<SeoItems.Index />
						{SeoTitleMenu()}
						{SeoDescriptionMenu()}
					</S.SeoCell>
				)}
				<S.GlobalCell>{isGlobal && <GlobalMark />}</S.GlobalCell>
				<S.ActionsCell role="cell">
					<S.StyledActionMenu icon="more" options={menuOptions} tooltip="Page actions" />
				</S.ActionsCell>
			</S.PageRow>
			<CopyModal
				isOpen={isOpen("copy")}
				toggleModal={() => {
					setSite(null);
					toggleModal("copy");
				}}
				onCopy={copyToOtherSite}
				sites={sites}
				site={site}
				setSite={setSite}
			/>
			<DuplicatePageModal
				isOpen={isOpen("duplicate")}
				toggleModal={handleCloseDuplicate}
				modalState={modalState}
				onNameChange={handleNameChange}
				onSlugChange={handleSlugChange}
				onDuplicate={handleDuplicatePage}
				isSaving={isSaving}
			/>
			<RemovePageModal
				isOpen={isOpen("remove")}
				toggleModal={() => toggleModal("remove")}
				pageTitle={page.title}
				onRemove={handleRemoveItemFromSite}
			/>
			<UnpublishPageModal isOpen={isOpen("unpublish")} toggleModal={() => toggleModal("unpublish")} />
			<DeleteModal
				isOpen={isOpen("delete")}
				toggleModal={() => toggleModal("delete")}
				onDelete={handleDeleteItem}
				{...{ isTranslated, deleteAllVersions, setDeleteAllVersions, title: page.title }}
			/>
		</>
	);
};

interface IPageOption {
	label: string;
	icon: string;
	action: () => void;
	disabled?: boolean;
	helpText?: string | null;
	color?: boolean;
}

interface IPageItemProps {
	item: {
		isSelected: boolean;
		siteLanguages?: ILanguage[];
		page: IPage;
		site: ISite;
		lang: { locale: string; id: number };
		isDuplicable: boolean;
	};
	functions: {
		onClick: (e: any) => void;
		onCheck: (e: any) => void;
		deletePage(params?: ISavePageParams, currentLanguage?: string): void;
		getSiteContent(): any;
		setHistoryPush(path: string, isEditor: boolean): void;
		updatePageStatus(ids: number[], status: string, updatedFromList: boolean): Promise<boolean>;
		setCurrentPageID(currentPageID: number | null): ISetCurrentPageIDAction;
		duplicatePage(pageID: number, data: any, siteID?: number): Promise<boolean>;
		removePageFromSite(pageID: number): Promise<boolean>;
		deleteBulk(ids: number[]): void;
		setTemplateInstanceError(error: any): void;
		getDataPack: (id: string) => Promise<void>;
		toggleCopiedToast(): void;
		getPage(pageID?: number, global?: boolean): Promise<void>;
		validatePage(publish?: boolean, browserRef?: any, currentPage?: IPage): Promise<boolean>;
	};
	activatedTemplates: any[];
	toggleToast(): void;
	setRemovedPage(pageID: number): void;
	categoryColumns: ISchemaField[];
	columns: IColumn[];
	categoryColors: any;
	addCategoryColors(cats: string[]): void;
	dataPacks: IDataPack[];
	sites: ISite[];
	skipReview?: boolean;
	hoverCheck?: boolean;
	createNewTranslation(isNewTranslation: boolean): void;
	setLanguage(lang: { locale: string; id: number | null }): void;
	isSaving: boolean;
}

const mapStateToProps = (state: IRootState) => ({
	isSaving: state.app.isSaving,
});

const mapDispatchToProps = {
	createNewTranslation: pageEditorActions.createNewTranslation,
	setLanguage: appActions.setLanguage,
};

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