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

import { BrowserContent, Loading, Toast } from "@ax/components";
import { formsActions } from "@ax/containers/Forms";
import { pageEditorActions } from "@ax/containers/PageEditor";
import { findByEditorID } from "@ax/forms";
import { getDefaultTheme } from "@ax/helpers";
import { useOnMessageReceivedFromOutside, useToast, useURLSearchParam } from "@ax/hooks";
import type { FormContent, ILanguage, IRootState, ISite, ISocialState } from "@ax/types";

import HeadingsOverlay from "./HeadingsOverlay";
import { observeAndAddIdsToHeadings, observeAndHighlightKeywords } from "./utils";

import * as S from "./style";

const FramePreview = (props: IProps) => {
	const {
		pageContent,
		formContent,
		socials,
		cloudinaryName,
		isLoading,
		currentSiteInfo,
		siteLangs,
		globalLangs,
		setSelectedPageContent,
		setSelectedFormContent,
		setEditorContent,
		setFormContent,
		deleteModule,
		duplicateModule,
		copyModule,
	} = props;

	const previewParam = useURLSearchParam("preview");
	const disabledParam = useURLSearchParam("disabled");
	const type = useURLSearchParam("type");
	const headingFilter = useURLSearchParam("headingFilter");
	const keywordFilter = useURLSearchParam("keywordFilter");

	const isPreviewMode = previewParam === "true";
	const isDisabled = disabledParam === "true";
	const isForm = type === "form";
	const isHeadingsEditor = type === "headings";
	const isKeywordsEditor = type === "keywords";
	const keywords: string[] = pageContent?.metaKeywords || [];
	const filteredKeywords = keywordFilter ? [keywordFilter] : keywords;
	const setSelectedContent = isForm ? setSelectedFormContent : setSelectedPageContent;
	const setContent = isForm ? setFormContent : setEditorContent;
	const content = isForm ? formContent : pageContent;
	const { canonicalSite, language, pageLanguages, header, footer } = content;

	const { isVisible, toggleToast, setIsVisible, state: toastState } = useToast();
	useOnMessageReceivedFromOutside(setContent, setSelectedContent);

	useEffect(() => {
		document.body.classList.add("preview");

		const handleMouseMove = (e: MouseEvent) => {
			window.parent.postMessage(
				{
					type: "iframe-mousemove",
					clientX: e.clientX,
				},
				"*",
			);
		};

		window.addEventListener("mousemove", handleMouseMove);
		return () => window.removeEventListener("mousemove", handleMouseMove);
	}, []);

	useEffect(() => {
		if (isDisabled) {
			localStorage.setItem("selectedID", "0");
		}
	}, [isDisabled]);

	useEffect(() => {
		if (isHeadingsEditor) {
			return observeAndAddIdsToHeadings(document.body, headingFilter);
		}
	}, [isHeadingsEditor, headingFilter]);

	useEffect(() => {
		if (isKeywordsEditor) {
			return observeAndHighlightKeywords(document.body, filteredKeywords);
		}
	}, [isKeywordsEditor, filteredKeywords]);

	const selectEditorID = (
		selectedComponent: { editorID: number; component: any; type: string; parentEditorID: number },
		// biome-ignore lint/correctness/noUnusedFunctionParameters: TODO: fix this
		parentComponent: string | undefined | null,
		e: React.SyntheticEvent,
	) => {
		const { element } = findByEditorID(content, selectedComponent.parentEditorID);
		element && e.stopPropagation();

		const { editorID: pageEditorID } = selectedComponent;

		const editorID = element.component === "FormPage" ? element.editorID : pageEditorID;

		const isNavigationModule = ["header", "footer"].includes(selectedComponent.type);

		if (!isPreviewMode && (!isDisabled || isNavigationModule)) {
			window.parent.postMessage({ type: "module-click", message: editorID }, "*");
			setSelectedContent?.(editorID);
		}
	};

	const selectHoverEditorID = (editorID: number, parentEditorID: number) => {
		const { parent } = findByEditorID(content, parentEditorID);
		if (parent && (parent.parentEditorID === null || parent.parentEditorID === 0)) {
			window.parent.postMessage({ type: "module-scroll", message: editorID }, "*");
		}
	};

	const globalTheme = getDefaultTheme();
	const theme = currentSiteInfo ? currentSiteInfo.theme : globalTheme;
	const langs = currentSiteInfo ? siteLangs : globalLangs;
	const siteID = currentSiteInfo ? currentSiteInfo.id : canonicalSite;
	const renderer = isForm ? "forms" : isPreviewMode ? "preview" : "editor";

	const deleteModuleSelected = (editorID: number) => {
		window.parent.postMessage({ type: "module-delete", message: editorID }, "*");
		setSelectedContent?.(0);
		deleteModule([editorID]);
	};

	const duplicateModuleSelected = (editorID: number) => {
		window.parent.postMessage({ type: "module-duplicate", message: editorID }, "*");
		duplicateModule([editorID]);
	};

	const copyModuleSelected = (editorID: number) => {
		window.parent.postMessage({ type: "module-copy", message: editorID }, "*");
		const isCopied = copyModule([editorID]);
		!!isCopied && toggleToast?.("1 module copied to clipboard");
	};

	const moduleActions = {
		deleteModuleAction: deleteModuleSelected,
		duplicateModuleAction: duplicateModuleSelected,
		copyModuleAction: copyModuleSelected,
	};

	if (isLoading) return <Loading />;

	return (
		<S.Wrapper>
			<S.GlobalScrollStyle />
			<BrowserContent
				cloudinaryName={cloudinaryName}
				theme={theme}
				socials={socials}
				siteLangs={langs}
				selectEditorID={selectEditorID}
				siteID={siteID}
				isPage={true}
				content={content}
				header={currentSiteInfo && header}
				footer={currentSiteInfo && footer}
				languageID={language}
				pageLanguages={pageLanguages}
				moduleActions={moduleActions}
				renderer={renderer}
				selectHoverEditorID={selectHoverEditorID}
			/>
			{isHeadingsEditor && <S.Velo />}
			{isHeadingsEditor && <HeadingsOverlay headingFilter={headingFilter} />}
			{isVisible && <Toast message={toastState} setIsVisible={setIsVisible} />}
		</S.Wrapper>
	);
};

interface IProps {
	pageContent: any;
	formContent: any;
	socials: ISocialState;
	cloudinaryName: string | null;
	currentSiteInfo: ISite | null;
	siteLangs: ILanguage[];
	globalLangs: ILanguage[];
	isLoading: boolean;
	setSelectedPageContent(editorID: number): void;
	setSelectedFormContent(editorID: number): void;
	setEditorContent(editorContent: Record<string, unknown>): void;
	setFormContent(formContent: FormContent | null): void;
	deleteModule(editorID: number[]): void;
	duplicateModule(editorID: number[]): number;
	copyModule(editorID: number[]): boolean | number;
}

const mapStateToProps = (state: IRootState) => ({
	pageContent: { ...state.pageEditor.editorContent },
	formContent: { ...state.forms.formContent },
	socials: state.social,
	cloudinaryName: state.app.globalSettings.cloudinaryName,
	currentSiteInfo: state.sites.currentSiteInfo,
	siteLangs: state.sites.currentSiteLanguages,
	globalLangs: state.app.globalLangs,
	isLoading: state.app.isLoading,
});

const mapDispatchToProps = {
	setSelectedPageContent: pageEditorActions.setSelectedContent,
	setSelectedFormContent: formsActions.setSelectedContent,
	setEditorContent: pageEditorActions.setEditorContent,
	setFormContent: formsActions.setFormContent,
	deleteModule: pageEditorActions.deleteModule,
	duplicateModule: pageEditorActions.duplicateModule,
	copyModule: pageEditorActions.copyModule,
};

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