var recursivelyRecoverInvalidBlockList = blocks => {
	const _blocks = [ ...blocks ]
	let recoveryCalled = false
	const recursivelyRecoverBlocks = willRecoverBlocks => {
		willRecoverBlocks.forEach( _block => {
			if ( isInvalid( _block ) ) {
				recoveryCalled = true
				const newBlock = recoverBlock( _block )
				for ( const key in newBlock ) {
					_block[ key ] = newBlock[ key ]
				}
			}

			if ( _block.innerBlocks.length ) {
				recursivelyRecoverBlocks( _block.innerBlocks )
			}
		} )
	}

	recursivelyRecoverBlocks( _blocks )
	return [ _blocks, recoveryCalled ]
}

var recoverBlock = ( { name, attributes, innerBlocks } ) =>
	wp.blocks.createBlock( name, attributes, innerBlocks );

var recoverBlocks = blocks => {
	return blocks.map( _block => {
		const block = _block

		// If the block is a reusable block, recover the Stackable blocks inside it.
		if ( _block.name === 'core/block' ) {
			const { attributes: { ref } } = _block
			const parsedBlocks = wp.blocks.parse( wp.data.select( 'core' ).getEntityRecords( 'postType', 'wp_block', { include: [ ref ] } )?.[ 0 ]?.content?.raw ) || []

			const [ recoveredBlocks, recoveryCalled ] = recursivelyRecoverInvalidBlockList( parsedBlocks )

			if ( recoveryCalled ) {
				console.log( 'Stackable notice: block ' + block.name + ' (' + block.clientId + ') was auto-recovered, you should not see this after saving your page.' ) // eslint-disable-line no-console
				return {
					blocks: recoveredBlocks,
					isReusable: true,
					ref,
				}
			}
		}

		if ( block.innerBlocks && block.innerBlocks.length ) {
			const newInnerBlocks = recoverBlocks( block.innerBlocks )
			if ( newInnerBlocks.some( block => block.recovered ) ) {
				block.innerBlocks = newInnerBlocks
				block.replacedClientId = block.clientId
				block.recovered = true
			}
		}

		if ( ! block.isValid ) {
			const newBlock = recoverBlock( block )
			newBlock.replacedClientId = block.clientId
			newBlock.recovered = true
			console.log( 'Stackable notice: block ' + block.name + ' (' + block.clientId + ') was auto-recovered, you should not see this after saving your page.' ) // eslint-disable-line no-console

			return newBlock
		}

		return block
	} )
}

// Recover all the blocks that we can find.
var mainBlocks = recoverBlocks( wp.data.select( 'core/editor' ).getEditorBlocks() )
// Replace the recovered blocks with the new ones.
mainBlocks.forEach( block => {
    if ( block.isReusable && block.ref ) {
        // Update the reusable blocks.
        wp.data.dispatch( 'core' ).editEntityRecord( 'postType', 'wp_block', block.ref, { content: wp.blocks.serialize( block.blocks ) } ).then( () => {
            // But don't save them, let the user do the saving themselves. Our goal is to get rid of the block error visually.
            // dispatch( 'core' ).saveEditedEntityRecord( 'postType', 'wp_block', block.ref )
        } )
    }

    if ( block.recovered && block.replacedClientId ) {
        wp.data.dispatch( 'core/block-editor' ).replaceBlock( block.replacedClientId, block )
    }
} )