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

import {
	CategoryCell,
	CheckField,
	Flag,
	FloatingMenu,
	Icon,
	LanguageMenu,
	Tooltip,
	TruncatedTooltip,
} from "@ax/components";
import { appActions } from "@ax/containers/App";
import { formsActions } from "@ax/containers/Forms";
import { findFieldsErrors } from "@ax/forms";
import { findObjectValue, getHumanLastModifiedDate } from "@ax/helpers";
import { useModals, usePermissions } from "@ax/hooks";
import type {
	FormContent,
	FormLanguage,
	FormState,
	ICheck,
	ILanguage,
	INotification,
	IRootState,
	ISite,
} from "@ax/types";

import { CopyModal, DeleteModal, DuplicateModal, UnPublishModal } from "../../atoms";
import FormUseModal from "../../FormUseModal";

import * as S from "./style";

const FormItem = (props: IFormItemProps): JSX.Element => {
	const {
		form,
		isSelected,
		languages,
		lang,
		featuredCategory,
		categoryColors,
		currentSiteInfo,
		hoverCheck,
		skipReviewOnPublish,
		addCategoryColors,
		onChange,
		onClick,
		deleteForm,
		toggleToast,
		updateFormState,
		createNewTranslation,
		setLanguage,
		duplicateForm,
		copyForm,
		goToEditor,
		setNotification,
	} = props;

	const { id, title, modified, state, dataLanguages, template, formInUse, language } = form;

	const categoryObject: { value: number; title: string }[] | undefined = featuredCategory
		? findObjectValue(template, featuredCategory.value)
		: undefined;

	const categories = categoryObject?.map((cat) => cat.title) || [];
	const isTranslated = dataLanguages.length > 1;
	const isSiteView = !!currentSiteInfo;
	const errorNotificationText = "There are some errors on the form so you can not publish yet. Please review them.";

	const [deleteAllVersions, setDeleteAllVersions] = useState(false);
	const [duplicateTitle, setDuplicateTitle] = useState("");
	const [site, setSite] = useState<number | null>(null);
	const { isOpen, toggleModal } = useModals(["delete", "unpublish", "duplicate", "copy", "use"]);

	const isAllowedTo = usePermissions({
		createForms: isSiteView ? "forms.createForms" : "global.forms.createForms",
		editForms: isSiteView ? "forms.editForms" : "global.forms.editForms",
		deleteForms: isSiteView ? "forms.deleteForms" : "global.forms.deleteForms",
		publishUnpublishForms: isSiteView ? "forms.publishUnpublishForms" : "global.forms.publishUnpublishForms",
	});

	const handleClick = () => {
		if (isAllowedTo.editForms) {
			onClick(form.id);
		}
	};

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

	const handleCheckClick = (e: React.MouseEvent<HTMLDivElement>) => e.stopPropagation();

	const removeItem = async () => {
		if (formInUse) {
			setNotification({
				text: "This form is currently used on multiple pages. Please remove it from those pages before deleting.",
				type: "error",
				btnText: "Show pages",
				onClick: () => toggleModal("use"),
			});
		} else {
			const formIds = deleteAllVersions ? dataLanguages.map((lang: FormLanguage) => lang.id) : id;
			const isDeleted = await deleteForm(formIds);
			if (isDeleted) {
				toggleToast("1 form deleted");
			}
		}
		toggleModal("delete");
	};

	const getSelectedFormLanguage = (language: ILanguage) =>
		dataLanguages.find((formLang) => formLang.language === language.id);

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

		const selectedFormLanguage = getSelectedFormLanguage(language);

		if (selectedFormLanguage) {
			isAllowedTo.editForms && onClick(selectedFormLanguage.id);
		} else {
			createNewTranslation(true);
			onClick(form.id);
		}
	};

	const getCurrentLanguages = (): ILanguage[] => {
		const dataLanguageIds = new Set(dataLanguages.map((lang) => lang.language));
		return languages?.filter((lang) => dataLanguageIds.has(lang.id)) || [];
	};

	const currentLanguages = getCurrentLanguages();
	const availableLanguages = isAllowedTo.createForms ? languages : currentLanguages;

	const languageMenu = () => (
		<LanguageMenu
			language={lang.locale}
			availableLanguages={availableLanguages}
			setLanguage={handleLanguage}
			currentLanguages={currentLanguages}
		/>
	);

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

	const handleDuplicateForm = async () => {
		const duplicated = await duplicateForm(form.id, duplicateTitle);
		if (duplicated) {
			goToEditor();
			toggleModal("duplicate");
		}
	};

	const handleCopyForm = async () => {
		const copied = site ? await copyForm(form.id, site) : false;
		if (copied) {
			toggleToast("1 form copied to another site");
			handleCloseCopyModal();
		}
	};

	const handleCloseCopyModal = () => {
		setSite(null);
		toggleModal("copy");
	};

	const unpublishForm = async () => {
		if (formInUse) {
			setNotification({
				text: "This form is currently used on multiple pages. Please remove it from those pages before unpublishing.",
				type: "error",
				btnText: "Show pages",
				onClick: () => toggleModal("use"),
			});
		} else {
			const isUpdated = await updateFormState(id, "inactive");
			if (isUpdated) {
				toggleToast("1 form unpublished");
				toggleModal("unpublish");
			}
		}
	};

	const publishForm = async () => {
		const fieldErrors = !skipReviewOnPublish ? findFieldsErrors(form, true) : [];

		if (fieldErrors.length) {
			setNotification({ text: errorNotificationText, type: "error" });
		} else {
			const isUpdated = await updateFormState(id, "active");
			if (isUpdated) {
				toggleToast("1 form published");
			}
		}
	};

	const isActive = state === "active";
	const statusIcon = isActive ? "active" : "offline";
	const statusTooltip = isActive ? "Live" : "Offline";

	const publishButton = isActive
		? {
				label: "unpublish",
				icon: "offline",
				action: () => toggleModal("unpublish"),
			}
		: {
				label: "publish",
				icon: "upload-pending",
				action: publishForm,
			};

	const menuOptions = [];

	if (formInUse) {
		menuOptions.push({
			label: "Show pages where it is used",
			icon: "view",
			action: () => toggleModal("use"),
		});
	}

	if (isAllowedTo.createForms) {
		menuOptions.push({
			label: "duplicate",
			icon: "duplicate",
			action: () => toggleModal("duplicate"),
		});
	}

	if (isAllowedTo.createForms && isSiteView) {
		menuOptions.push({
			label: "Copy form in another site",
			icon: "copy",
			action: () => toggleModal("copy"),
		});
	}

	if (isAllowedTo.publishUnpublishForms) {
		menuOptions.push(publishButton);
	}

	if (isAllowedTo.deleteForms) {
		menuOptions.push({
			label: "delete",
			icon: "delete",
			action: () => toggleModal("delete"),
		});
	}

	return (
		<>
			<S.FormRow role="rowgroup" selected={isSelected} onClick={handleClick} clickable={isAllowedTo.editForms}>
				<S.CheckCell role="cell" onClick={handleCheckClick}>
					<CheckField name={`form-${id}`} value={id} checked={isSelected || hoverCheck} onChange={handleOnChange} />
				</S.CheckCell>
				<S.NameCell role="cell">
					<TruncatedTooltip content={title} expanded top={-5}>
						<S.Title>{title}</S.Title>
					</TruncatedTooltip>
				</S.NameCell>
				{featuredCategory && (
					<CategoryCell categories={categories} categoryColors={categoryColors} addCategoryColors={addCategoryColors} />
				)}
				<S.UpdateCell role="cell">{getHumanLastModifiedDate(modified)}</S.UpdateCell>
				<S.StateCell role="cell">
					<Tooltip content={statusTooltip}>
						<Icon name={statusIcon} />
					</Tooltip>
				</S.StateCell>
				<S.LangCell role="cell">
					<FloatingMenu Button={FlagsButton}>{languageMenu()}</FloatingMenu>
				</S.LangCell>
				<S.ActionsCell role="cell">
					<S.StyledActionMenu icon="more" options={menuOptions} tooltip="Actions" />
				</S.ActionsCell>
			</S.FormRow>
			<DeleteModal
				isOpen={isOpen("delete")}
				toggleModal={() => toggleModal("delete")}
				onDelete={removeItem}
				{...{ title, isTranslated, deleteAllVersions, setDeleteAllVersions }}
			/>
			<UnPublishModal
				isOpen={isOpen("unpublish")}
				toggleModal={() => toggleModal("unpublish")}
				onUnpublish={unpublishForm}
				title={title}
			/>
			<DuplicateModal
				isOpen={isOpen("duplicate")}
				toggleModal={() => toggleModal("duplicate")}
				onDuplicate={handleDuplicateForm}
				title={duplicateTitle}
				handleChange={setDuplicateTitle}
			/>
			<CopyModal
				isOpen={isOpen("copy")}
				toggleModal={handleCloseCopyModal}
				onCopy={handleCopyForm}
				site={site}
				setSite={setSite}
				lang={language}
				currentSite={currentSiteInfo?.id || null}
			/>
			{isOpen("use") && (
				<FormUseModal
					isOpen={isOpen("use")}
					toggleModal={() => toggleModal("use")}
					isSiteView={!!currentSiteInfo?.id}
					formInUse={formInUse}
				/>
			)}
		</>
	);
};

interface IFormItemProps {
	form: FormContent;
	isSelected: boolean;
	languages: ILanguage[];
	lang: { locale: string; id: number };
	featuredCategory?: { label: string; value: string };
	categoryColors: Record<string, string>;
	currentSiteInfo: ISite | null;
	hoverCheck?: boolean;
	skipReviewOnPublish?: boolean;
	addCategoryColors(cats: string[]): void;
	onChange: (value: ICheck) => void;
	onClick: (id: number) => void;
	deleteForm: (formID: number | number[]) => Promise<boolean>;
	toggleToast(message: string): void;
	updateFormState(formID: number | number[], state: FormState): Promise<boolean>;
	createNewTranslation(isNewTranslation: boolean): void;
	setLanguage(lang: { locale: string; id: number | null }): void;
	duplicateForm(formID: number, title: string): Promise<boolean>;
	copyForm(formID: number, siteID: number): Promise<boolean>;
	goToEditor(): void;
	setNotification(notification: INotification): void;
}

const mapStateToProps = (state: IRootState) => ({
	currentSiteInfo: state.sites.currentSiteInfo,
	skipReviewOnPublish: state.app.globalSettings.skipReviewOnPublish,
});

const mapDispatchToProps = {
	deleteForm: formsActions.deleteForm,
	updateFormState: formsActions.updateFormState,
	createNewTranslation: formsActions.createNewTranslation,
	setLanguage: appActions.setLanguage,
	duplicateForm: formsActions.duplicateForm,
	copyForm: formsActions.copyForm,
};

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