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

import { IAnalytics, IDimension, IDimensionsGroup, IRootState } from "@ax/types";
import { appActions } from "@ax/containers/App";
import { analyticsActions } from "@ax/containers/Analytics";
import { MainWrapper, ErrorToast, Loading, FieldsBehavior } from "@ax/components";
import { RouteLeavingGuard } from "@ax/guards";
import { useIsDirty } from "@ax/hooks";
import { useModal } from "@ax/hooks";

import DimensionItem from "./DimensionItem";
import DimensionPanel from "./DimensionPanel";
import GroupItem from "./GroupItem";
import GroupPanel from "./GroupPanel";
import * as S from "./style";

const Analytics = (props: IProps): JSX.Element => {
	const { isSaving, isLoading, analytics, getAnalytics, setHistoryPush, updateAnalytics } = props;

	const [analyticsState, setAnalyticsState] = useState(analytics);
	const { isDirty, resetDirty } = useIsDirty(analyticsState);
	const { isOpen: isDimensionOpen, toggleModal: toggleDimensionModal } = useModal();
	const { isOpen: isGroupOpen, toggleModal: toggleGroupModal } = useModal();

	const { dimensions, groups } = analyticsState;

	const changeScriptCode = (scriptCode: string) => setAnalyticsState((state) => ({ ...state, scriptCode }));
	const changeDimensions = (dimensions: IDimension[]) => setAnalyticsState((state) => ({ ...state, dimensions }));
	const changeGroups = (groups: IDimensionsGroup[]) => setAnalyticsState((state) => ({ ...state, groups }));

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		const handleGetAnalytics = async () => await getAnalytics();
		handleGetAnalytics();
	}, []);

	useEffect(() => {
		setAnalyticsState(analytics);
	}, [analytics]);

	const handleSave = async () => {
		const isSaved = await updateAnalytics(analyticsState);
		if (isSaved) resetDirty();
	};

	const rightButtonProps = {
		label: isSaving ? "Saving" : isDirty ? "Save" : "Saved",
		disabled: isSaving || !isDirty,
		action: () => handleSave(),
	};

	const mapDimensionList = (items: IDimension[]) =>
		Array.isArray(items) &&
		items.map((item: IDimension, i: number) => {
			const handleSetItem = (newContent: IDimension) => {
				const newItems = [...dimensions];
				newItems[i] = newContent;
				changeDimensions(newItems);
			};
			const handleRemoveDimension = () => {
				const newItems = [...dimensions];
				newItems.splice(i, 1);
				changeDimensions(newItems);
			};
			return (
				<DimensionItem
					key={`${item.id}${item.name}${i}`}
					item={item}
					setDimensionItem={handleSetItem}
					removeDimension={handleRemoveDimension}
				/>
			);
		});

	const mapGroupList = (items: IDimensionsGroup[]) =>
		Array.isArray(items) &&
		items.map((item: IDimensionsGroup, i: number) => {
			const handleSetItem = (newContent: IDimensionsGroup) => {
				const newItems = [...groups];
				newItems[i] = newContent;
				changeGroups(newItems);
			};
			const handleRemoveGroup = () => {
				const newItems = [...groups];
				newItems.splice(i, 1);
				changeGroups(newItems);
			};
			return (
				<GroupItem
					key={`${item.id}${item.name}${i}`}
					item={item}
					setGroupItem={handleSetItem}
					dimensions={dimensions}
					removeGroup={handleRemoveGroup}
				/>
			);
		});

	const handleAddDimension = (item: IDimension) => {
		const { dimensions } = analyticsState;
		const updatedDimensions = dimensions ? [...dimensions, item] : [item];
		changeDimensions(updatedDimensions);
	};

	const handleAddGroup = (item: IDimensionsGroup) => {
		const { groups } = analyticsState;
		const updatedGroups = groups ? [...groups, item] : [item];
		changeGroups(updatedGroups);
	};

	const setRoute = (path: string) => setHistoryPush(path);
	const modalText = (
		<>
			Some analytics <strong>are not saved</strong>.{" "}
		</>
	);

	const isGroupDisabled = dimensions?.length < 2;

	if (isLoading) return <Loading />;

	return (
		<>
			<RouteLeavingGuard when={isDirty} action={setRoute} text={modalText} />
			<MainWrapper backLink={false} title="Analytics Settings" rightButton={rightButtonProps}>
				<ErrorToast />
				<S.Wrapper>
					<S.FormWrapper>
						<S.ScriptCodeWrapper>
							<FieldsBehavior
								title="Analytics Tracking ID or Script Code"
								name="scriptCode"
								fieldType="TextArea"
								value={analytics.scriptCode}
								onChange={changeScriptCode}
								placeholder="Type the Google Analytics or Google Tag Manager code."
								rows={3}
							/>
						</S.ScriptCodeWrapper>
						<S.SettingsWrapper>
							<S.Heading>Data layer configuration</S.Heading>
							<S.SettingContent>
								<S.SettingText>
									You can configure Data Layer to measure dimensions and data values when loading a page.
								</S.SettingText>
								<S.StyledButton type="button" buttonStyle="text" icon="addCircle" onClick={toggleDimensionModal}>
									Add dimension
								</S.StyledButton>
								<S.Table>{dimensions && mapDimensionList(dimensions)}</S.Table>
							</S.SettingContent>
						</S.SettingsWrapper>
						<S.SettingsWrapper>
							<S.Heading>Dimensions group by content</S.Heading>
							<S.SettingContent>
								<S.SettingText>
									You can create groups with the dimensions to measure on a page based on its content..
								</S.SettingText>
								<S.StyledButton
									type="button"
									buttonStyle="text"
									icon="addCircle"
									onClick={toggleGroupModal}
									disabled={isGroupDisabled}
								>
									Define group
								</S.StyledButton>
								<S.Table>{groups && mapGroupList(groups)}</S.Table>
							</S.SettingContent>
						</S.SettingsWrapper>
					</S.FormWrapper>
				</S.Wrapper>
				<DimensionPanel
					isOpen={isDimensionOpen}
					toggleModal={toggleDimensionModal}
					setDimensionItem={handleAddDimension}
				/>
				<GroupPanel
					isOpen={isGroupOpen}
					toggleModal={toggleGroupModal}
					setGroupItem={handleAddGroup}
					dimensions={dimensions}
				/>
			</MainWrapper>
		</>
	);
};

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

const mapDispatchToProps = {
	setHistoryPush: appActions.setHistoryPush,
	getAnalytics: analyticsActions.getAnalytics,
	updateAnalytics: analyticsActions.updateAnalytics,
};

interface IAnalyticsProps {
	isSaving: boolean;
	isLoading: boolean;
	analytics: IAnalytics;
}

interface IDispatchProps {
	getAnalytics(siteId?: number | null): Promise<void>;
	setHistoryPush(path: string, isEditor?: boolean): void;
	updateAnalytics(analyticsState: IAnalytics, siteId?: number | null): Promise<boolean>;
}

type IProps = IAnalyticsProps & IDispatchProps;

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