/**
 * A custom hook to add an event listener to a specified element.
 * Supports optional event delegation via an options.selector string.
 */
import { useCallback, useEffect, useRef } from '@wordpress/element';

export const useEventListener = (eventName, handler, element, options) => {
    const savedHandler = useRef(handler);

    useEffect(() => {
        savedHandler.current = handler;
    }, [handler]);

    const eventListener = useCallback(
        (event) => {
            /** Handle normal events without delegation */
            if (typeof options !== 'object' || !options.selector) {
                savedHandler.current(event);
                return;
            }

            /** Handle event delegation */
            const target = event.target;
            if (target && target.closest) {
                const delegateTarget = target.closest(options.selector);
                if (delegateTarget) {
                    savedHandler.current(event, delegateTarget);
                }
            }
        },
        [options],
    );

    useEffect(() => {
        const targetElement = element ?? window;
        if (!targetElement || !('addEventListener' in targetElement)) {
            return;
        }

        /** Extract standard addEventListener options by removing our custom properties */
        let eventOptions = options;
        if (typeof options === 'object') {
            /** Create a new object without the selector property */
            const { selector, ...standardOptions } = options;
            eventOptions = standardOptions;
        }

        targetElement.addEventListener(eventName, eventListener, eventOptions);

        return () => {
            targetElement.removeEventListener(
                eventName,
                eventListener,
                eventOptions,
            );
        };
    }, [eventName, element, eventListener, options]);
};
