import classnames from 'classnames/dedupe';
import { debounce } from 'throttle-debounce';

import { useCallback, useEffect, useRef, useState } from '@wordpress/element';

const { ResizeObserver, MutationObserver } = window;

function stepsWizard( props ) {
	const { step, children } = props;

	const $ref = useRef();
	const [ newStep, setNewStep ] = useState( step );
	const [ height, setHeight ] = useState( 0 );

	const maybeUpdateHeight = useCallback( () => {
		let newHeight = 0;

		if ( $ref.current.childNodes !== null ) {
			$ref.current.childNodes.forEach( ( $child ) => {
				const styles = window.getComputedStyle( $child );
				const margin =
					parseFloat( styles.marginTop ) +
					parseFloat( styles.marginBottom );

				newHeight += Math.ceil( $child.offsetHeight + margin );
			} );
		}

		setHeight( `${ newHeight }px` );
	}, [ $ref ] );

	useEffect( () => {
		if ( step !== newStep ) {
			setNewStep( step );
		}
	}, [ step, newStep ] );

	useEffect( () => {
		maybeUpdateHeight();
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [ newStep ] );

	useEffect( () => {
		const $element = $ref.current;

		const calculateHeight = debounce( 100, () => {
			maybeUpdateHeight();
		} );

		// Resize observer is used to properly set height
		// when selected images, saved post and reloaded page.
		const resizeObserver = new ResizeObserver( calculateHeight );
		const mutationObserver = new MutationObserver( calculateHeight );

		resizeObserver.observe( $element );
		mutationObserver.observe( $element, {
			attributes: true,
			characterData: true,
			childList: true,
			subtree: true,
			attributeOldValue: true,
			characterDataOldValue: true,
		} );

		return () => {
			resizeObserver.disconnect();
			mutationObserver.disconnect();
		};
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [ $ref.current ] );

	return typeof children[ newStep ] !== 'undefined' ? (
		<div
			ref={ $ref }
			className={ classnames(
				'vpf-component-steps-wizard',
				step !== newStep
					? `vpf-component-steps-wizard-animate-${
							newStep > step ? 'left' : 'right'
					  }`
					: false
			) }
			style={ height ? { height } : {} }
		>
			{ children[ newStep ] }
		</div>
	) : null;
}

stepsWizard.Step = function ( props ) {
	const { children } = props;
	return children;
};

export default stepsWizard;
