/**
 * WordPress dependencies
 */
import { Dashicon } from '@safe-wordpress/components';
import { useDispatch, useSelect } from '@safe-wordpress/data';
import { createInterpolateElement, useEffect } from '@safe-wordpress/element';
import { _x, sprintf } from '@safe-wordpress/i18n';

/**
 * External dependencies
 */
import { findIndex } from 'lodash';
import { v4 as uuid } from 'uuid';
import { store as NAB_EXPERIMENTS } from '@nab/experiments';
import { createGoal } from '@nab/utils';
import type { Goal as RealGoal, GoalId, Maybe } from '@nab/types';
type Goal = Omit< RealGoal, 'conversionActions' >;

/**
 * Internal dependencies
 */
import './style.scss';
import { Goal as GoalView } from '../goal';
import { GoalList } from '../goal-list';
import { useExperimentAttribute } from '../hooks';
import { ReusableGoalDialog } from '../reusable-goal-dialog';
import { store as NAB_EDITOR } from '../../store';

export const GoalSection = (): JSX.Element => {
	useAutoConversionActionsEffect();

	const goal = useActiveGoal();
	const goals = useGoals();
	const isExperimentPaused = useIsExperimentPaused();
	const numberOfGoals = goals.length;
	const isAutomatic = useIsActiveGoalAutomatic();
	const {
		addGoals,
		removeGoals,
		setActiveGoal,
		updateGoal,
		addConversionActionsIntoGoal,
	} = useDispatch( NAB_EDITOR );

	const canGoalBeRemoved = 1 < numberOfGoals && ! isExperimentPaused;
	const canGoalBeDuplicated = ! isExperimentPaused;

	const removeActiveGoal = () => {
		if ( ! goal ) {
			return;
		}
		const nextGoal = getAdjacentGoal( goals, goal.id );
		if ( ! nextGoal ) {
			return;
		}
		void setActiveGoal( nextGoal.id );
		void removeGoals( goal.id );
	};

	const updateActiveGoal = ( attributes: Partial< Goal[ 'attributes' ] > ) =>
		goal && updateGoal( goal.id, { ...goal.attributes, ...attributes } );

	const actions = useConversionActions( goal?.id );
	const duplicateGoal = () => {
		if ( ! goal ) {
			return;
		}
		const newGoal = {
			...createGoal(),
			attributes: {
				...goal.attributes,
				name: goal.attributes.name
					? sprintf(
							/* translators: %s: Name of an item being duplicated. */
							_x( 'Copy of %s', 'text', 'nelio-ab-testing' ),
							goal.attributes.name
					  )
					: '',
			},
		};
		const newActions = actions.map( ( a ) => ( { ...a, id: uuid() } ) );
		void addGoals( newGoal );
		void addConversionActionsIntoGoal( newGoal.id, newActions );
	};

	return (
		<div className="nab-edit-experiment__goal-section">
			<h2>
				{ createInterpolateElement(
					sprintf(
						/* translators: %s: Dashicon. */
						_x(
							'%s Conversion Goals and Actions',
							'text',
							'nelio-ab-testing'
						),
						'<icon></icon>'
					),
					{
						icon: (
							<Dashicon
								className="nab-goal-section__title-icon"
								icon="flag"
							/>
						),
					}
				) }
			</h2>

			<div className="nab-edit-experiment-goal-section__content">
				<GoalList />
				<GoalView
					name={ goal?.attributes.name ?? '' }
					setName={ ( name ) => updateActiveGoal( { name } ) }
					duplicateGoal={
						goal && canGoalBeDuplicated ? duplicateGoal : undefined
					}
					removeGoal={
						canGoalBeRemoved ? removeActiveGoal : undefined
					}
					isAutomatic={ isAutomatic }
				/>
			</div>

			<ReusableGoalDialog />
		</div>
	);
};

// =====
// HOOKS
// =====

const useActiveGoal = () =>
	useSelect( ( select ) => select( NAB_EDITOR ).getActiveGoal(), [] );

const useGoals = () =>
	useSelect( ( select ) => select( NAB_EDITOR ).getGoals(), [] );

const useIsExperimentPaused = () => {
	const [ status ] = useExperimentAttribute( 'status' );
	return ( status || '' ).includes( 'paused' );
};

const useIsActiveGoalAutomatic = () => {
	const goal = useActiveGoal();
	const goals = useGoals();
	const firstGoal = goals[ 0 ];
	return useSelect(
		( select ): boolean => {
			const { getExperimentType } = select( NAB_EDITOR );
			const { hasExperimentSupport } = select( NAB_EXPERIMENTS );
			return (
				goal?.id === firstGoal?.id &&
				hasExperimentSupport(
					getExperimentType(),
					'automaticGoalSetup'
				)
			);
		},
		[ goal, firstGoal ]
	);
};

const useAutoConversionActionsEffect = () => {
	const { replaceConversionActionsInGoal } = useDispatch( NAB_EDITOR );

	const goalId = useGoals()[ 0 ]?.id;
	const control = useSelect(
		( select ) => select( NAB_EDITOR ).getAlternative( 'control' ),
		[]
	);
	const automaticGoalSetup = useSelect( ( select ) => {
		const { getExperimentType } = select( NAB_EDITOR );
		const { getExperimentSupport } = select( NAB_EXPERIMENTS );
		return getExperimentSupport(
			getExperimentType(),
			'automaticGoalSetup'
		);
	}, [] );

	useEffect( () => {
		if ( ! control || ! goalId || ! automaticGoalSetup ) {
			return;
		}

		const auto = automaticGoalSetup( control.attributes );
		void replaceConversionActionsInGoal( goalId, auto );
	}, [
		control,
		goalId,
		automaticGoalSetup,
		replaceConversionActionsInGoal,
	] );
};

const useConversionActions = ( id: GoalId | undefined ) =>
	useSelect(
		( select ) =>
			id ? select( NAB_EDITOR ).getConversionActions( id ) : [],
		[ id ]
	);

// =======
// HELPERS
// =======

function getAdjacentGoal(
	goals: ReadonlyArray< Goal >,
	goalId: GoalId
): Maybe< Goal > {
	const index = findIndex( goals, { id: goalId } );
	if ( index === goals.length - 1 ) {
		return goals[ index - 1 ];
	}
	return goals[ index + 1 ];
}
