/**
 * Shared focus / outside-click handling for color Dropdowns and mini panels.
 * ColorPicker / gradient stops / swatches are mostly non-focusable, so WP's
 * default closeIfFocusOutside treats clicks inside the panel as "outside".
 * With focusOnMount: false, focus never moves into the popover — so outside
 * clicks also never fire onFocusOutside. We close on document pointerdown.
 */
import { useEffect, useRef } from '@wordpress/element';

/** Toggle + panel + nested WP color UI (for onFocusOutside). */
export const COLOR_DROPDOWN_UI_SELECTOR = [
	'.bm-color-dropdown',
	'.bm-color-dropdown-host',
	'.bm-color-dropdown__panel',
	'.bm-color-dropdown__content',
	'.bm-fill-color-palette',
	'.bm-theme-color-palette',
	'.components-circular-option-picker',
	'.components-color-picker',
	'.components-custom-gradient-picker',
	'.react-colorful',
	'.components-color-palette__custom-color-dropdown-content',
].join( ', ' );

/**
 * Portaled popover / nested picker content only (for outside-click dismiss).
 * Do not include the toggle host — that is checked via anchorRef.
 */
export const COLOR_DROPDOWN_POPOVER_SELECTOR = [
	'.bm-color-dropdown__panel',
	'.bm-color-dropdown__content',
	'.bm-fill-color-palette',
	'.bm-theme-color-palette',
	'.components-circular-option-picker',
	'.components-color-picker',
	'.components-custom-gradient-picker',
	'.react-colorful',
	'.components-color-palette__custom-color-dropdown-content',
].join( ', ' );

/**
 * @param {Event|null|undefined} event
 * @param {string} [selector]
 * @return {boolean}
 */
export function eventInsideColorDropdown(
	event,
	selector = COLOR_DROPDOWN_UI_SELECTOR
) {
	const path =
		typeof event?.composedPath === 'function' ? event.composedPath() : [];
	const nodes = path.length
		? path
		: [ event?.target, event?.relatedTarget, document.activeElement ];
	for ( let i = 0; i < nodes.length; i++ ) {
		const node = nodes[ i ];
		if ( node?.nodeType === 1 && node.closest?.( selector ) ) {
			return true;
		}
	}
	return false;
}

/**
 * Close when the user pointerdowns outside the toggle host + keep-open UI.
 *
 * @param {boolean} open
 * @param {() => void} onClose
 * @param {string} [keepOpenSelector] Portaled content that must not dismiss
 * @return {import('react').RefObject<HTMLElement|null>} Attach to the toggle host
 */
export function usePopoverOutsideClose(
	open,
	onClose,
	keepOpenSelector = ''
) {
	const onCloseRef = useRef( onClose );
	onCloseRef.current = onClose;
	const anchorRef = useRef( null );

	useEffect( () => {
		if ( ! open ) {
			return undefined;
		}
		const onPointerDown = ( event ) => {
			const path =
				typeof event.composedPath === 'function'
					? event.composedPath()
					: [];
			const nodes = path.length ? path : [ event.target ];
			for ( let i = 0; i < nodes.length; i++ ) {
				const node = nodes[ i ];
				if ( node?.nodeType !== 1 ) {
					continue;
				}
				if ( anchorRef.current?.contains?.( node ) ) {
					return;
				}
				if (
					keepOpenSelector &&
					node.closest?.( keepOpenSelector )
				) {
					return;
				}
			}
			onCloseRef.current?.();
		};
		document.addEventListener( 'pointerdown', onPointerDown, true );
		return () => {
			document.removeEventListener( 'pointerdown', onPointerDown, true );
		};
	}, [ open, keepOpenSelector ] );

	return anchorRef;
}

/**
 * Close when the user pointerdowns outside this color dropdown's toggle + popover.
 *
 * @param {boolean} open
 * @param {() => void} onClose
 * @return {import('react').RefObject<HTMLElement|null>}
 */
export function useColorDropdownOutsideClose( open, onClose ) {
	return usePopoverOutsideClose(
		open,
		onClose,
		COLOR_DROPDOWN_POPOVER_SELECTOR
	);
}

/**
 * popoverProps fragment for a controlled color Dropdown.
 *
 * @param {() => void} close
 * @param {object} [extra]
 * @return {object}
 */
export function colorDropdownPopoverProps( close, extra = {} ) {
	return {
		placement: 'bottom-start',
		offset: 8,
		focusOnMount: false,
		...extra,
		onFocusOutside: ( event ) => {
			if ( eventInsideColorDropdown( event ) ) {
				return;
			}
			close?.();
		},
	};
}
