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

/**
 * External dependencies
 */
import { difference } from 'lodash';
import { AnimatedList } from '@nab/components';
import { createAlternative } from '@nab/utils';
import type { AlternativeId } from '@nab/types';

/**
 * Internal dependencies
 */
import './style.scss';
import { AiAlternativeAttributesModal } from '../ai-alternative-attributes-modal';
import { AlternativeContainer } from './alternative-container';
import { AlternativePreviewer } from '../alternative-previewer';
import { useCanAddAlternatives } from '../hooks';
import { store as NAB_EDITOR } from '../../store';

export const AlternativeSection = (): JSX.Element => {
	const [ control, ...alternativeIds ] = useAlternativeIds();
	const addAlternative = useAddAlternative();
	const isTestedElementInvalid = useIsTestedElementInvalid();
	const isReplacingAlternatives = useIsReplacingAlternatives();
	const canAddAlternatives = useCanAddAlternatives();

	return (
		<div className="nab-edit-experiment__alternative-section">
			<h2>
				{ createInterpolateElement(
					sprintf(
						/* translators: %s: Dashicon. */
						_x(
							'%s Control Version and Variants',
							'text',
							'nelio-ab-testing'
						),
						'<icon></icon>'
					),
					{
						icon: (
							<Dashicon
								className="nab-alternative-section__title-icon"
								icon="randomize"
							/>
						),
					}
				) }
			</h2>

			<div className="nab-alternative-list">
				{ !! control && (
					<AlternativeContainer
						key="control"
						index={ 0 }
						alternativeId="control"
						disabled={ isTestedElementInvalid }
					/>
				) }

				<AnimatedList
					disableAnimations={ isReplacingAlternatives }
					exit={ 500 }
				>
					{ alternativeIds.map( ( alternativeId, index ) => (
						<AlternativeContainer
							key={ alternativeId }
							index={ index + 1 }
							alternativeId={ alternativeId }
							disabled={ isTestedElementInvalid }
						/>
					) ) }
				</AnimatedList>
			</div>

			<div className="nab-edit-experiment-alternative-section__new-variant-container">
				{ canAddAlternatives && (
					<Button
						variant="secondary"
						key="new-variant"
						disabled={ isTestedElementInvalid }
						onClick={ () => addAlternative() }
					>
						{ _x( 'New Variant', 'command', 'nelio-ab-testing' ) }
					</Button>
				) }
			</div>

			<AlternativePreviewer />
			<AiAlternativeAttributesModal />
		</div>
	);
};

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

const useAlternativeIds = () =>
	useSelect( ( select ) => select( NAB_EDITOR ).getAlternativeIds(), [] );

const useAddAlternative = () => {
	const { addAlternatives } = useDispatch( NAB_EDITOR );
	return () => addAlternatives( createAlternative() );
};

const useIsTestedElementInvalid = () =>
	useSelect(
		( select ) => select( NAB_EDITOR ).isTestedElementInvalid(),
		[]
	);

const useIsReplacingAlternatives = () => {
	const altIds = useAlternativeIds();
	const [ prevAltIds, setPrevAltIds ] =
		useState< ReadonlyArray< AlternativeId > >( altIds );

	// Keep track of the previous alt IDs.
	useEffect( () => {
		if ( altIds !== prevAltIds ) {
			setPrevAltIds( altIds );
		}
	}, [ altIds, prevAltIds ] );

	// Disable animations if several changes at once.
	if ( altIds === prevAltIds ) {
		return false;
	}

	// This works under the assumption that, usually, there’s only one change
	// at a time (i.e. adding or removing a single alternative).
	const d1 = difference( altIds, prevAltIds );
	const d2 = difference( prevAltIds, altIds );
	return !! d1.length && !! d2.length;
};
