import { useEffect } from '@wordpress/element';
import getEditorBlocks from '../utils/get-editor-blocks';
import { useDispatch } from '@wordpress/data';
import { store as blockEditorStore } from '@wordpress/block-editor';

/**
 * Search all blocks for uniqueIds
 *
 * @param {Array} blocks The blocks array
 * @return {Array} The array of uniqueIds
 */
export const getUniqueIdFromBlocks = ( blocks ) => blocks
	.reduce( ( result, block ) => {
		if (
			( block.name && block.name.includes( 'generateblocks' ) ) &&
			( block.attributes && block.attributes.uniqueId )
		) {
			result.uniqueIds.push( block.attributes.uniqueId );
			result.clientIds.push( block.clientId );
		}

		if ( block.innerBlocks ) {
			const { uniqueIds, clientIds } = getUniqueIdFromBlocks( block.innerBlocks );
			result.uniqueIds = result.uniqueIds.concat( uniqueIds );
			result.clientIds = result.clientIds.concat( clientIds );
		}

		return result;
	}, { uniqueIds: [], clientIds: [] } );

/**
 * Generates a unique id based on the clientId
 *
 * @param {string} clientId The block clientId
 * @return {string} The uniqueId
 */
export const generateUniqueId = ( clientId ) => clientId.substr( 2, 9 ).replace( '-', '' );

/**
 * Checks if the array contains duplicates of the value
 *
 * @param {Array}  arr          The array to check the values
 * @param {any}    value        The value to check if has duplicates
 * @param {number} currentIndex The current index
 * @return {boolean} If the array has duplicates
 */
export const hasDuplicates = ( arr, value, currentIndex ) => (
	arr.filter( ( el ) => ( el === value ) ).length > 1 &&
	currentIndex === arr.lastIndexOf( value )
);

/**
 * It will enhance a block component with the attributes.uniqueId property
 *
 * @param {any} WrappedComponent The component to add the uniqueId
 * @return {Function} The wrapped component
 */
export default ( WrappedComponent ) => ( ( props ) => {
	const { clientId, attributes } = props;
	const { updateBlockAttributes } = useDispatch( blockEditorStore );

	useEffect( () => {
		const { uniqueIds, clientIds } = getUniqueIdFromBlocks( getEditorBlocks() );

		if (
			! attributes.uniqueId ||
			hasDuplicates( uniqueIds, attributes.uniqueId, clientIds.indexOf( clientId ) )
		) {
			const uniqueId = generateUniqueId( clientId );

			updateBlockAttributes( clientId, { uniqueId } );
		}
	}, [ clientId ] );

	return ( <WrappedComponent { ...props } /> );
} );
