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

/**
 * External dependencies
 */
import { isEqual, zip } from 'lodash';
import { AlternativeDistributionSetting } from '@nab/components';
import { usePluginSetting } from '@nab/data';
import { transformAlternativeChancesToAllocatedSlots } from '@nab/utils';

/**
 * Internal dependencies
 */
import './style.scss';
import { useExperimentAttribute } from '../hooks';
import { store as NAB_EDITOR } from '../../store';

export const AlternativeDistributionSection = (): JSX.Element | null => {
	const visible = usePluginSetting( 'isAlternativeDistributionAllowed' );

	const alternatives = useAlternatives();
	const { setAlternative } = useDispatch( NAB_EDITOR );

	const maxCombinations = usePluginSetting( 'maxCombinations' );

	const [ status ] = useExperimentAttribute( 'status' );
	const isPaused = ( status || '' ).includes( 'paused' );
	const readonly = isPaused;

	const distributeEvenly = useCallback(
		() =>
			alternatives.some( ( a ) => a.attributes.chance ) &&
			alternatives.forEach(
				( a ) =>
					setAlternative?.( a.id, {
						...a,
						attributes: { ...a.attributes, chance: undefined },
					} )
			),

		[ alternatives, setAlternative ]
	);

	const updateCuts = useCallback(
		( newCuts: ReadonlyArray< number > ) => {
			const evenCuts = getEvenCutDistribution(
				newCuts.length,
				maxCombinations
			);
			if ( isEqual( newCuts, evenCuts ) ) {
				return distributeEvenly();
			}

			const chances = newCuts.map(
				( cut ) =>
					Math.round( ( cut / maxCombinations ) * 100_00 ) / 100
			);
			const pairs = zip( alternatives, chances );
			pairs.forEach( ( [ alternative, chance ] ) => {
				if ( ! alternative || ! chance ) {
					return;
				}
				void setAlternative( alternative.id, {
					...alternative,
					attributes: { ...alternative.attributes, chance },
				} );
			} );
		},
		[ alternatives, maxCombinations, distributeEvenly, setAlternative ]
	);

	useEffect( () => {
		if ( alternatives.length === maxCombinations ) {
			distributeEvenly();
		}
	}, [ alternatives, maxCombinations, distributeEvenly ] );

	if ( ! visible ) {
		return null;
	}

	return (
		<div className="nab-edit-experiment__alternative-distribution-section">
			<h2>
				{ _x( 'Variant Distribution', 'text', 'nelio-ab-testing' ) }{ ' ' }
				{ ! readonly &&
					alternatives.some( ( a ) => a.attributes.chance ) && (
						<Button
							className="nab-edit-experiment__alternative-distribution-section__even-distro-button"
							variant="link"
							onClick={ distributeEvenly }
						>
							{ _x(
								'Distribute evenly',
								'command',
								'nelio-ab-testing'
							) }
						</Button>
					) }
			</h2>

			<AlternativeDistributionSetting
				alternatives={ alternatives }
				updateCuts={ ! readonly ? updateCuts : undefined }
			/>
		</div>
	);
};

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

const useAlternatives = () =>
	useSelect( ( select ) => select( NAB_EDITOR ).getAlternatives(), [] );

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

function getEvenCutDistribution( size: number, slots: number ) {
	return transformAlternativeChancesToAllocatedSlots(
		new Array( size ).fill( 1 ),
		slots
	);
}
