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

import { EmptyState, ErrorToast, Loading, MainWrapper, Modal, Toast } from "@ax/components";
import { appActions } from "@ax/containers/App";
import { dataPacksActions } from "@ax/containers/Settings";
import { RouteLeavingGuard } from "@ax/guards";
import { useModal, useToast } from "@ax/hooks";
import type { IDataPack, IRootState } from "@ax/types";

import AddModal from "./AddModal";
import Config from "./Config";
import { useShouldBeSaved } from "./hooks";
import List from "./List";
import Nav from "./Nav";

import * as S from "./style";

const DataPacks = (props: IProps): JSX.Element => {
	const {
		isLoading,
		isSaving,
		selected,
		setSelected,
		updateDataPack,
		form,
		setHistoryPush,
		getSiteDataPacks,
		getDataPacksCategories,
		addDataPacks,
		deleteSiteDataPack,
		activatedDataPacks,
		routerAction,
	} = props;

	const isFromPage = selected?.templates && selected.templates.length > 0;

	const { isDirty, setIsDirty } = useShouldBeSaved(selected, form);
	const { isOpen, toggleModal } = useModal();
	const { isVisible, toggleToast, setIsVisible } = useToast();
	const errorRef = React.useRef<HTMLDivElement>(null);

	const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
	const [deactivatedPack, setDeactivatedPack] = useState("");

	const toggleDeleteModal = () => setIsDeleteModalOpen(!isDeleteModalOpen);

	const saveConfig = async () => {
		const saved = await updateDataPack(selected.id);
		if (!saved && errorRef.current) {
			errorRef.current.scrollIntoView();
		} else {
			setIsDirty(false);
		}
	};

	const getActivatedPacks = useCallback((): void => {
		const queryParams = "?status=activated";
		getSiteDataPacks(queryParams);
		getDataPacksCategories();
	}, [getSiteDataPacks, getDataPacksCategories]);

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		if (routerAction !== "POP") setSelected(null);
		getActivatedPacks();
	}, [getActivatedPacks, setSelected]);

	const deactivateDataPack = (force = false) => {
		const dataPackID = selected.id;
		setDeactivatedPack(dataPackID);
		deleteSiteDataPack(dataPackID, toggleDeleteModal, force).then((deactivated: boolean) => {
			if (deactivated) {
				isDeleteModalOpen && toggleDeleteModal();
				toggleToast();
				setSelected(null);
			}
		});
	};

	const forceDeleteAction = () => {
		const force = true;
		deactivateDataPack(force);
	};

	const mainAction = {
		title: "Deactivate",
		onClick: forceDeleteAction,
	};

	const secondaryAction = {
		title: "Cancel",
		onClick: toggleDeleteModal,
	};

	const deleteModalProps = {
		isOpen: isDeleteModalOpen,
		hide: toggleDeleteModal,
		title: "Deactivate package",
		mainAction,
		secondaryAction,
	};

	const deleteModalText = (
		<>
			You are deactivating a <strong>{selected?.title}</strong> package. Some of its content is being used in existing
			pages. By deactivating it, you won&apos;t be able to edit the content nor add new modules tied to it. You will
			only be able to delete it.
		</>
	);

	const DeleteModal = () => (
		<Modal {...deleteModalProps}>
			<S.ModalContent>{deleteModalText}</S.ModalContent>
		</Modal>
	);

	const saveLabel = isSaving ? "Saving" : isDirty ? "Save" : "Saved";

	const saveButtonProps = {
		label: saveLabel,
		disabled: isSaving || !isDirty,
		action: saveConfig,
	};

	const addNewAction = () => {
		setIsVisible(false);
		toggleModal();
	};

	const addNewButtonProps = {
		label: "Add new",
		action: addNewAction,
	};

	const rightLineButtonAction = () => {
		setIsVisible(false);
		const force = false;
		return selected.activated ? deactivateDataPack(force) : addDataPacks(selected.id, true);
	};

	const rightLineButtonProps = selected
		? {
				label: selected.activated ? "Deactivate" : "Activate",
				action: rightLineButtonAction,
			}
		: undefined;

	const saveButton = isFromPage ? saveButtonProps : undefined;

	const mainWrapperProps = {
		backLink: false,
		title: "Content types",
		rightButton: selected ? saveButton : addNewButtonProps,
		rightLineButton: rightLineButtonProps,
	};

	const undoAction = () => {
		addDataPacks(deactivatedPack);
		setIsVisible(false);
	};

	const toastProps = {
		action: () => undoAction(),
		setIsVisible,
		message: "Package deactivated",
	};

	const routeLeavingGuardProps = {
		when: isDirty,
		action: (path: string) => setHistoryPush(path),
		text: (
			<>
				Some changes <strong>are not saved</strong>.
			</>
		),
		allowedRoutes: ["/sites/settings/content-types"],
	};

	const Section = () =>
		selected ? <Config /> : <List toggleToast={toggleToast} setDeactivatedPack={setDeactivatedPack} />;

	const isEmpty = !activatedDataPacks || activatedDataPacks.length === 0;
	const emptyStateProps = {
		message: "To start using content types in your site, add as many packages as you need.",
		button: "Add New Package",
		action: addNewAction,
	};

	const Content = () => (!isEmpty ? <Section /> : <EmptyState {...emptyStateProps} />);

	return (
		<MainWrapper {...mainWrapperProps}>
			<DeleteModal />
			<RouteLeavingGuard {...routeLeavingGuardProps} />
			<S.ListWrapper>
				{isVisible && <Toast {...toastProps} />}
				<Nav isDirty={isDirty} />
				<S.ContentWrapper>
					<ErrorToast ref={errorRef} />
					{isLoading ? (
						<S.LoadingWrapper>
							<Loading />
						</S.LoadingWrapper>
					) : (
						<Content />
					)}
				</S.ContentWrapper>
			</S.ListWrapper>
			<Modal isOpen={isOpen} hide={toggleModal} size="XL" title="Available packages">
				{isOpen ? <AddModal toggleModal={toggleModal} /> : null}
			</Modal>
		</MainWrapper>
	);
};

interface IProps {
	isSaving: boolean;
	isLoading: boolean;
	selected: any;
	form: any;
	activatedDataPacks: IDataPack[];
	routerAction: string;
	getSiteDataPacks: (queryParams?: string) => void;
	setSelected: (dataPack?: any) => void;
	updateDataPack: (dataPack?: any) => Promise<boolean>;
	setHistoryPush(path: string): any;
	getDataPacksCategories: () => void;
	addDataPacks: (dataPack?: any, fromConfig?: boolean) => void;
	deleteSiteDataPack: (dataPackID: string, errorAction: any, force?: boolean) => Promise<boolean>;
}

const mapDispatchToProps = {
	setSelected: dataPacksActions.setSelected,
	getSiteDataPacks: dataPacksActions.getSiteDataPacks,
	updateDataPack: dataPacksActions.updateDataPack,
	setHistoryPush: appActions.setHistoryPush,
	getDataPacksCategories: dataPacksActions.getDataPacksCategories,
	addDataPacks: dataPacksActions.addSiteDataPack,
	deleteSiteDataPack: dataPacksActions.deleteSiteDataPack,
};

const mapStateToProps = (state: IRootState) => ({
	isSaving: state.app.isSaving,
	isLoading: state.app.isLoading,
	selected: state.dataPacks.selected,
	form: state.dataPacks.configFormData,
	activatedDataPacks: state.dataPacks.activated,
	routerAction: state.router.action,
});

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