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

import {
	CancelScheduleModal,
	ErrorToast,
	Loading,
	MainWrapper,
	Notification,
	RestoreModal,
	ScheduleModal,
} from "@ax/components";
import { appActions } from "@ax/containers/App";
import { dataPacksActions } from "@ax/containers/Settings/DataPacks";
import { structuredDataActions } from "@ax/containers/StructuredData";
import { RouteLeavingGuard } from "@ax/guards";
import { dateToString, getActivatedDataPacksIds, getDefaultTheme } from "@ax/helpers";
import { useIsDirty, useModal } from "@ax/hooks";
import type {
	IDataLanguage,
	IDataPack,
	IErrorItem,
	ILanguage,
	INotification,
	IRootState,
	ISchemaField,
	ISite,
} from "@ax/types";

import ConnectedField from "./ConnectedField";

import * as S from "./style";

const Form = (props: IProps) => {
	const {
		schema,
		form,
		site,
		currentStructuredData,
		createStructuredDataContent,
		updateStructuredDataContent,
		isSaving,
		isLoading,
		siteLanguages,
		globalLangs,
		lang,
		setLanguage,
		getDataContent,
		setHistoryPush,
		activatedDataPacks,
		getSiteDataPack,
		setDataStatus,
		deleteStructuredDataContent,
		errors,
		validateForm,
		currentStructuredDataId,
		skipReviewOnPublish,
		setFormValues,
		setCurrentDataID,
		schemaVersion,
		restoreDataContent,
	} = props;

	const [isNewStructuredData, setIsNewStructuredData] = useState(!currentStructuredDataId);
	const [notification, setNotification] = useState<INotification | null>(null);
	const [scheduleDate, setScheduleDate] = useState({
		date: dateToString(new Date(), "yyy/MM/dd"),
		time: "12:00 am",
	});
	const { isOpen: isScheduleOpen, toggleModal: toggleScheduleModal } = useModal();
	const { isOpen: isCancelScheduleOpen, toggleModal: toggleCancelScheduleModal } = useModal();
	const { isOpen: isRestoreOpen, toggleModal: toggleRestoreModal } = useModal();
	const { isDirty, resetDirty, setIsDirty } = useIsDirty(form);
	const path = site ? "/sites/pages" : "/data";

	const { fields } = schema;
	const inversed = !site;
	const languages = site ? siteLanguages : globalLangs;

	const fieldsTranslate: ISchemaField[] = [
		{
			title: "",
			type: "TranslateButton",
			key: "translate",
			contentType: "data",
		},
		...fields,
	];

	const activatedDataPacksIds = getActivatedDataPacksIds(activatedDataPacks);
	const disabledDatapack =
		currentStructuredData.local &&
		!activatedDataPacksIds.some((pack: string) => currentStructuredData.dataPacks.includes(pack));
	const isDeleted = !!form?.deleted;
	const isDisabled = isDeleted || disabledDatapack;

	const isDataTranslatable = currentStructuredData?.translate;
	const isScheduled = !!form && !!form.publicationScheduled;
	const status = isScheduled
		? "scheduled"
		: !form || form.draft === true || form.draft === undefined
			? "offline"
			: "active";

	let title = "";

	const packNotificationText =
		"This content is part of disabled content type package. To edit it, you must first activate it.";

	const deletedNotificationText =
		"This content type has been deleted and can’t be edited. It will be permanently removed from the trash after 30 days.";

	const theme = getDefaultTheme();

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		if (!currentStructuredDataId) {
			setIsDirty(true);
		}
	}, []);

	const Fields = fieldsTranslate
		?.filter((field: ISchemaField) => !field.hidden)
		.map((field: ISchemaField, i: number) => {
			const { type, key } = field;
			if (key === "title") {
				title = form?.content?.[key] ? form.content[key] : "";
			}
			return (
				<ConnectedField
					fieldKey={key}
					field={field}
					key={`${type}${i}`}
					site={site}
					disabled={isDisabled}
					theme={site ? site.theme : theme}
					languages={languages}
				/>
			);
		});

	const handleSave = async (publish: boolean, scheduleDate?: string | null) => {
		const validated = publish && !skipReviewOnPublish ? await validateForm(true) : true;

		if (validated) {
			const status = isNewStructuredData ? true : form.draft;

			const payload: any = {
				...form,
				structuredData: currentStructuredData ? currentStructuredData.id : null,
				draft: publish === true ? false : status,
				relatedSite: site ? site.id : null,
				publicationScheduled: scheduleDate !== undefined ? scheduleDate : form.publicationScheduled,
			};

			let saved = false;
			if (isNewStructuredData) {
				saved = await createStructuredDataContent(payload);
				saved && setIsNewStructuredData(false);
			} else {
				saved = await updateStructuredDataContent(payload);
			}
			saved && resetDirty();
		}
	};

	const getSaveLabel = () => {
		if (isNewStructuredData) return "Save";
		return form?.draft ? "Save" : "Save & publish";
	};

	const handleSaveAndPublish = () => (isNewStructuredData || form.draft ? handleSave(false) : handleSave(true));

	const rightButtonProps = {
		label: isSaving ? "Saving" : !isDirty ? "Saved" : getSaveLabel(),
		disabled: isSaving || isDisabled || !isDirty,
		action: handleSaveAndPublish,
	};

	const getCurrentLanguages = () => {
		const availables: ILanguage[] = [];
		form?.dataLanguages?.forEach((dataLang: IDataLanguage) => {
			languages?.forEach((language) => {
				if (language.id === dataLang.language) {
					availables.push(language);
				}
			});
		});

		return availables;
	};

	const currentLanguages = getCurrentLanguages();

	const availableLanguages = isDisabled ? currentLanguages : languages;

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

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

	const handleClickNotification = () => {
		getSiteDataPack(currentStructuredData.id);
		setHistoryPush("/sites/settings/content-types", false);
	};

	const removeItem = () => {
		deleteStructuredDataContent(form.id).then((deleted: boolean) => {
			if (deleted) {
				setHistoryPush(path, true);
			}
		});
	};

	const publishItem = async () => {
		const validated = skipReviewOnPublish ? true : await validateForm(true);
		if (!validated) return;

		if (!isNewStructuredData) {
			setDataStatus(form.id, "undraft").then((updated: boolean) => {
				if (updated) {
					getDataContent(form.id);
				}
			});
		} else {
			handleSave(true);
		}
	};

	const unpublishItem = async () =>
		setDataStatus(form.id, "draft").then((updated: boolean) => {
			if (updated) {
				getDataContent(form.id);
			}
		});

	const getPublishButton = (draft: boolean) => {
		if (draft === true || draft === undefined) {
			return {
				label: "Publish",
				action: publishItem,
			};
		}
		return {
			label: "Unpublish",
			action: unpublishItem,
		};
	};

	const reviewForm = async () => {
		const { validateForm } = props;
		await validateForm();
	};

	const handleSchedulePublication = () => {
		const date = new Date(`${scheduleDate.date} ${scheduleDate.time}`);
		const dateString = dateToString(date, "dd/MM/yyyy HH:mm:ss");
		handleSave(false, dateString);
		toggleScheduleModal();
	};

	const handleCancelSchedulePublication = () => {
		handleSave(false, null);
		setScheduleDate({ date: "", time: "12:00 am" });
		toggleCancelScheduleModal();
	};

	const downArrowMenu = {
		displayed: !isDeleted,
		button: getPublishButton(form?.draft),
		options: [
			{
				label: "Review",
				icon: "question",
				action: reviewForm,
			},
			{
				label: "Delete",
				icon: "delete",
				action: removeItem,
			},
		],
	};

	if (status === "offline" && !isScheduled) {
		downArrowMenu.options.unshift({
			label: "Schedule",
			icon: "calendar",
			action: toggleScheduleModal,
		});
	}

	if (isScheduled) {
		downArrowMenu.options.unshift({
			label: "Cancel Schedule",
			icon: "cancelEvent",
			action: toggleCancelScheduleModal,
		});
	}

	const getSelectedDataLanguage = (language: ILanguage): IDataLanguage | undefined =>
		form.dataLanguages?.find((dataLang: IDataLanguage) => dataLang.language === language.id);

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

		const selectedDataLanguage = getSelectedDataLanguage(language);

		if (selectedDataLanguage) {
			setCurrentDataID(selectedDataLanguage.id);
			await getDataContent(selectedDataLanguage.id);
			resetDirty();
		} else {
			currentStructuredDataId && (await getDataContent(currentStructuredDataId));
			setFormValues({ ...form, canBeTranslated: true });
			setIsNewStructuredData(true);
		}
	};

	const handleRestorePage = async () => {
		if (!currentStructuredDataId) return;
		const isRestored = await restoreDataContent(currentStructuredDataId);
		if (isRestored) {
			isRestoreOpen && toggleRestoreModal();
			await getDataContent(currentStructuredDataId);
		}
	};

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

	const secondaryScheduleModalAction = {
		title: "Cancel",
		onClick: toggleScheduleModal,
	};

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

	const secondaryCancelScheduleModalAction = {
		title: "Back",
		onClick: toggleCancelScheduleModal,
	};

	return isLoading ? (
		<Loading />
	) : (
		<>
			<RouteLeavingGuard when={isDirty} action={setRoute} text={modalText} />
			<MainWrapper
				backLink={path}
				title={title}
				subtitle={currentStructuredData ? currentStructuredData.title : ""}
				rightButton={rightButtonProps}
				language={isDataTranslatable ? lang : null}
				availableLanguages={availableLanguages}
				languageAction={handleLanguage}
				inversed={inversed}
				currentLanguages={currentLanguages}
				pageStatus={status}
				downArrowMenu={downArrowMenu}
				isFromEditor={true}
				currentPageID={form?.id}
				errors={errors}
				scheduledPublication={form?.publicationScheduled}
				isSaving={isSaving}
			>
				{disabledDatapack && (
					<S.NotificationWrapper>
						<Notification
							type="error"
							text={packNotificationText}
							btnText="Activate package"
							onClick={handleClickNotification}
						/>
					</S.NotificationWrapper>
				)}
				{isDeleted && (
					<S.NotificationWrapper>
						<Notification
							type="error"
							text={deletedNotificationText}
							btnText="Restore content"
							onClick={toggleRestoreModal}
						/>
					</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" />
				<S.Wrapper>{Fields}</S.Wrapper>
			</MainWrapper>
			<ScheduleModal
				isOpen={isScheduleOpen}
				toggleModal={toggleScheduleModal}
				mainModalAction={mainScheduleModalAction}
				secondaryModalAction={secondaryScheduleModalAction}
				scheduleDate={scheduleDate}
				setScheduleDate={setScheduleDate}
			/>
			<CancelScheduleModal
				isOpen={isCancelScheduleOpen}
				toggleModal={toggleCancelScheduleModal}
				mainModalAction={mainCancelScheduleModalAction}
				secondaryModalAction={secondaryCancelScheduleModalAction}
			/>
			<RestoreModal
				isOpen={isRestoreOpen}
				toggleModal={toggleRestoreModal}
				{...{
					isChild: false,
					hasIssues: schemaVersion !== form?.schemaVersionTimestamp,
					restorePage: handleRestorePage,
				}}
			/>
		</>
	);
};

interface IProps {
	schema: any;
	form: any | null;
	site: ISite | null;
	currentStructuredData: any;
	isSaving: boolean;
	isLoading: boolean;
	siteLanguages: ILanguage[];
	globalLangs: ILanguage[];
	lang: { locale: string; id: number | null };
	activatedDataPacks: IDataPack[];
	errors: IErrorItem[];
	currentStructuredDataId: number | null;
	skipReviewOnPublish?: boolean;
	schemaVersion: string;
	createStructuredDataContent: (payload: any) => Promise<boolean>;
	updateStructuredDataContent: (payload: any) => Promise<boolean>;
	setLanguage(lang: { locale: string; id: number | null }): void;
	getDataContent(id: number): Promise<void>;
	setHistoryPush(path: string, isEditor?: boolean): void;
	getSiteDataPack(packID: string): void;
	setDataStatus(id: number, status: string): Promise<boolean>;
	deleteStructuredDataContent(id: number): Promise<boolean>;
	validateForm(publish?: boolean): Promise<boolean>;
	setFormValues(form: any): Promise<void>;
	setCurrentDataID(currentStructuredDataId: number | null): void;
	restoreDataContent(dataID: number | number[]): Promise<boolean>;
}

const mapStateToProps = (state: IRootState) => ({
	schema: state.structuredData.schema,
	form: state.structuredData.form,
	site: state.sites.currentSiteInfo,
	currentStructuredData: state.structuredData.currentStructuredData,
	currentStructuredDataId: state.structuredData.currentStructuredDataId,
	isSaving: state.app.isSaving,
	isLoading: state.app.isLoading,
	lang: state.app.lang,
	siteLanguages: state.sites.currentSiteLanguages,
	globalLangs: state.app.globalLangs,
	activatedDataPacks: state.dataPacks.activated,
	errors: state.structuredData.errors,
	skipReviewOnPublish: state.app.globalSettings.skipReviewOnPublish,
	schemaVersion: state.structuredData.schemaVersion,
});

const mapDispatchToProps = {
	createStructuredDataContent: structuredDataActions.createStructuredDataContent,
	updateStructuredDataContent: structuredDataActions.updateStructuredDataContent,
	getDataContent: structuredDataActions.getDataContent,
	setLanguage: appActions.setLanguage,
	setHistoryPush: appActions.setHistoryPush,
	getSiteDataPack: dataPacksActions.getSiteDataPack,
	setDataStatus: structuredDataActions.setStatusStructuredDataContent,
	deleteStructuredDataContent: structuredDataActions.deleteStructuredDataContent,
	validateForm: structuredDataActions.validateForm,
	setFormValues: structuredDataActions.setFormValues,
	setCurrentDataID: structuredDataActions.setCurrentDataID,
	restoreDataContent: structuredDataActions.restoreStructuredDataContent,
};

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