/**
 * @function useDropdownControl
 * @description Adds the control handlers to props.
 *
 * @since 4.5.0
 *
 * @param {object}   props    The props to add handlers to.
 * @param {Function} useStore The useStore hook.
 *
 * @return {object} The modified props.
 */
const useDropdownControl = ( props = {}, useStore = () => {} ) => {
	const {
		ajaxSearch = false,
		hasSearch = false,
		multi = false,
		onClose = () => {},
		onAfterClose = () => {},
		onOpen = () => {},
		onAfterOpen = () => {},
		onChange = () => {},
		onSearch = () => {},
	} = props;

	const listItems = useStore( ( state ) => state.listItems );
	const selectedItem = useStore( ( state ) => state.selectedItem );
	const setActiveItem = useStore( ( state ) => state.setActiveItem );
	const setSelectedItem = useStore( ( state ) => state.setSelectedItem );
	const setSearchValue = useStore( ( state ) => state.setSearchValue );
	const setOpen = useStore( ( state ) => state.setOpen );
	const setHide = useStore( ( state ) => state.setHide );
	const setReveal = useStore( ( state ) => state.setReveal );
	const triggerRef = useStore( ( state ) => state.triggerRef );

	/**
	 * @function close
	 * @description Closes the dropdown.
	 *
	 * @since 4.5.0
	 *
	 * @param {Event} event The event object.
	 */
	const close = ( event ) => {
		onClose?.( event );
		setOpen( false );
		setHide( true );
		setTimeout( () => {
			setHide( false );
			setSearchValue( '' );
			if ( ajaxSearch ) {
				onSearch?.( '' );
			}
			onAfterClose?.( event );
		}, 150 );
	};
	/**
	 * @function open
	 * @description Opens the dropdown.
	 *
	 * @since 4.5.0
	 *
	 * @param {Event} event The event object.
	 */
	const open = ( event ) => {
		onOpen?.( event );
		setReveal( true );
		requestAnimationFrame( () => {
			setOpen( true );
			setTimeout( () => {
				setReveal( false );
				onAfterOpen?.( event );
			}, 150 );
		} );
	};
	/**
	 * @function resetAndClose
	 * @description Resets and closes the dropdown.
	 *
	 * @since 4.5.0
	 *
	 * @param {Event} event The event object.
	 */
	const resetAndClose = ( event ) => {
		setTimeout( () => {
			if ( multi ) {
				setActiveItem( listItems.flatItems[ 0 ] );
			} else {
				setActiveItem( selectedItem );
			}
		}, 150 );
		close( event );
	};
	/**
	 * @function selectItem
	 * @description Selects an item in the list.
	 *
	 * @since 4.5.0
	 *
	 * @param {Event}  event The event object.
	 * @param {object} item  The item to select.
	 */
	const selectItem = ( event, item ) => {
		if ( ! item || ( hasSearch && item?.type === 'search' ) ) {
			close( event );
			triggerRef?.current?.focus();
			return;
		}

		if ( multi ) {
			const selected = selectedItem.some( ( selItem ) => selItem.value === item.value );

			// Set new value. If already selected, remove it. Otherwise, add it to the selected items.
			const newValue = selected
				? selectedItem.filter( ( selItem ) => selItem.value !== item.value )
				: [ ...selectedItem, item ];

			onChange( event, newValue );
			setSelectedItem( newValue );
			return;
		}

		// Not multi, set selected item.
		onChange( event, item );
		setSelectedItem( item );
		requestAnimationFrame( () => {
			close( event );
			triggerRef?.current?.focus();
		} );
	};
	/**
	 * @function selectMultipleItems
	 * @description Selects multiple items.
	 *
	 * @since 4.5.0
	 *
	 * @param {Event} event The event object.
	 * @param {Array} items The items to select.
	 */
	const selectMultipleItems = ( event, items = [] ) => {
		const newSelectedItems = items.reduce( ( carry, item ) => {
			// Check if item is already selected.
			if ( selectedItem.some( ( selItem ) => selItem.value === item.value ) ) {
				return carry;
			}

			// Add item to selected items.
			carry.push( item );
			return carry;
		}, [ ...selectedItem ] );

		onChange( event, newSelectedItems );
		setSelectedItem( newSelectedItems );
	};

	return {
		...props,
		close,
		open,
		resetAndClose,
		selectItem,
		selectMultipleItems,
	};
};

export default useDropdownControl;
