/**
 * @license Copyright (c) 2017-2025, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md.
 */

/**
 * Creates a hover manager that tracks hover state across multiple elements.
 *
 * @param options - The options for the hover manager.
 * @param options.elements - The elements to track hover state for.
 * @param options.onEnter - Callback function to call when an element is hovered.
 * @param options.onLeave - Callback function to call when no elements are hovered.
 * @param [options.debounceDelay=0] - Delay in milliseconds before triggering onEnter callback.
 * @returns An object with destroy method to clean up event listeners
 */
export function createHoverManager( { elements, onEnter, onLeave, debounceDelay = 0 } ) {
	const hoveredElements = new Set();
	let leaveTimeoutId = null;
	let enterTimeoutId = null;
	const listenerPairs = [];

	function handleMouseEnter( element ) {
		clearTimeout( leaveTimeoutId );
		leaveTimeoutId = null;

		const isNewlyHovered = !hoveredElements.has( element );
		hoveredElements.add( element );

		if ( isNewlyHovered && onEnter ) {
			clearTimeout( enterTimeoutId );

			if ( debounceDelay > 0 ) {
				// Use debounced enter if delay is specified
				enterTimeoutId = setTimeout( () => {
					onEnter?.( element );
				}, debounceDelay );
			} else {
				// Call immediately if no debounce
				onEnter?.( element );
			}
		}
	}

	function handleMouseLeave( element ) {
		hoveredElements.delete( element );

		// Clear any existing timeouts
		clearTimeout( leaveTimeoutId );
		clearTimeout( enterTimeoutId );

		leaveTimeoutId = null;
		enterTimeoutId = null;

		if ( hoveredElements.size === 0 ) {
			leaveTimeoutId = setTimeout( () => {
				// Double check size, in case an element was entered again quickly
				if ( hoveredElements.size === 0 && onLeave ) {
					onLeave?.();
				}
			}, 50 );
		}
	}

	// Attach event listeners
	elements.forEach( element => {
		const enterHandler = () => handleMouseEnter( element );
		const leaveHandler = () => handleMouseLeave( element );

		element.addEventListener( 'mouseenter', enterHandler );
		element.addEventListener( 'mouseleave', leaveHandler );
		element.addEventListener( 'focus', enterHandler );
		element.addEventListener( 'blur', leaveHandler );

		listenerPairs.push(
			{ element, type: 'mouseenter', handler: enterHandler },
			{ element, type: 'mouseleave', handler: leaveHandler },
			{ element, type: 'focus', handler: enterHandler },
			{ element, type: 'blur', handler: leaveHandler }
		);
	} );

	// Return an object with a destroy method
	return {
		destroy() {
			clearTimeout( leaveTimeoutId );
			clearTimeout( enterTimeoutId );
			listenerPairs.forEach( pair => {
				pair.element.removeEventListener( pair.type, pair.handler );
			} );
			hoveredElements.clear();
		}
	};
}
