import { useContext, useEffect, useMemo } from 'react';
import { useFloating, autoUpdate, flip, shift, useClick, useDismiss, useRole, useInteractions, useHover, size, offset, autoPlacement, safePolygon, } from '@floating-ui/react';
import { APPEND_TO } from '../PopoverNext.constants';
import { ZIndex } from '../../common/ZIndex';
import { usePositioning } from './usePositioning';
import deprecationLog from '../../utils/deprecationLog';
import { useTransition } from './useTransition';
import { useArrow } from './useArrow';
import { WixDesignSystemContext } from '../../WixDesignSystemProvider/context';
const ANIMATED_DURATION = { open: 150, close: 100 };
const formatWidth = (value) => typeof value === 'number' ? `${value}px` : value;
export function usePopover({ dataHook, open = false, onOpenChange, focusManagerEnabled = true, appendTo = APPEND_TO.parent, dynamicWidth = false, zIndex = ZIndex.popover, width, minWidth, maxWidth, excludeClass, moveBy, flip: shouldFlip = true, placement = 'bottom', fixed = false, rootRef, showDelay, hideDelay, timeout: duration, skin, transitionSettings, onClickOutside, overlay = false, role, tabIndex, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, id, style, onClick, animate, showArrow = false, customArrow, contentClassName, onMouseEnter, onMouseLeave, }) {
    const { contextClassName } = useContext(WixDesignSystemContext);
    const isHoverMode = Boolean(onMouseEnter && onMouseLeave);
    const isHybridMode = Boolean(onMouseEnter) !== Boolean(onMouseLeave);
    useEffect(() => {
        if (showDelay) {
            deprecationLog('<PopoverNext /> - prop `showDelay` is deprecated. Use `transitionSettings` instead.');
        }
        if (hideDelay) {
            deprecationLog('<PopoverNext /> - prop `hideDelay` is deprecated. Use `transitionSettings` instead.');
        }
        if (duration) {
            deprecationLog('<PopoverNext /> - prop `timeout` is deprecated. Use `transitionSettings` instead.');
        }
        if (animate) {
            deprecationLog('<PopoverNext /> - prop `animate` is deprecated. Use `transitionSettings` instead.');
        }
    }, [showDelay, hideDelay, duration, animate]);
    const positioning = usePositioning({
        flip: shouldFlip,
        fixed,
        placement,
        appendTo,
        rootRef,
    });
    const { getArrowProps, arrowMiddleware, getContentWithArrowStyles } = useArrow(showArrow);
    const { context, middlewareData, floatingStyles, placement: floatingPlacement, } = useFloating({
        open,
        onOpenChange: (newOpen, event, reason) => {
            onOpenChange(newOpen, reason);
            if (reason === 'hover' || reason === 'safe-polygon') {
                if (newOpen && onMouseEnter && event) {
                    onMouseEnter(event);
                }
                else if (!newOpen && onMouseLeave && event) {
                    onMouseLeave(event);
                }
            }
        },
        whileElementsMounted: (referenceEl, floatingEl, update) => autoUpdate(referenceEl, floatingEl, update, {
            animationFrame: true,
        }),
        placement: positioning.placement,
        middleware: [
            size({
                apply({ rects, elements }) {
                    const styles = {
                        wordBreak: 'normal',
                        display: 'flex',
                        justifyContent: 'center',
                    };
                    if (width) {
                        styles.width = formatWidth(width);
                        if (minWidth) {
                            styles.minWidth = formatWidth(minWidth);
                        }
                        if (maxWidth) {
                            styles.maxWidth = formatWidth(maxWidth);
                        }
                    }
                    else if (dynamicWidth) {
                        styles.minWidth = formatWidth(rects.reference.width);
                        if (maxWidth) {
                            styles.maxWidth = formatWidth(maxWidth);
                        }
                    }
                    else {
                        if (minWidth) {
                            styles.minWidth = formatWidth(minWidth);
                        }
                        if (maxWidth) {
                            styles.maxWidth = formatWidth(maxWidth);
                        }
                    }
                    if (appendTo === 'window' || appendTo === 'scrollParent') {
                        styles.minWidth = !!minWidth
                            ? formatWidth(minWidth)
                            : 'fit-content';
                        styles.width = !!width
                            ? formatWidth(width)
                            : formatWidth(rects.reference.width);
                        if (maxWidth) {
                            styles.maxWidth = formatWidth(maxWidth);
                        }
                    }
                    Object.assign(elements.floating.style, styles);
                },
            }),
            !!positioning.flip ? flip(positioning.flip) : undefined,
            !!positioning.autoPlacement
                ? autoPlacement(positioning.autoPlacement)
                : undefined,
            shift(positioning.shift),
            moveBy
                ? offset({
                    mainAxis: moveBy?.y ?? 0,
                    crossAxis: moveBy?.x ?? 0,
                })
                : undefined,
            arrowMiddleware,
        ].filter(Boolean),
    });
    const hover = useHover(context, {
        enabled: Boolean(onMouseEnter) || Boolean(onMouseLeave),
        delay: {
            open: showDelay ?? transitionSettings?.openDelay ?? 0,
            close: hideDelay ?? transitionSettings?.closeDelay ?? 0,
        },
        handleClose: safePolygon({
            requireIntent: true,
        }),
    });
    const click = useClick(context, {
        enabled: !isHoverMode,
    });
    const dismiss = useDismiss(context, {
        outsidePress: event => {
            const target = event.target;
            const classes = target.classList;
            const referenceElement = context.refs.reference.current;
            const floatingElement = context.refs.floating.current;
            if (referenceElement instanceof Element &&
                referenceElement.contains(target)) {
                return false;
            }
            // Under React 16 the floating ref can be unset when Floating UI's
            // outside-press listener evaluates the click that just opened the
            // popover, causing it to fire onClickOutside on an inside click.
            if (floatingElement instanceof Element &&
                floatingElement.contains(target)) {
                return false;
            }
            if (excludeClass && classes.contains(excludeClass)) {
                return false;
            }
            onClickOutside?.(event);
            return true;
        },
        escapeKey: true,
    });
    const roleSetting = useRole(context, { role });
    const interactions = useInteractions([
        hover,
        click,
        dismiss,
        roleSetting,
        {
            reference: {
                onClick,
            },
            floating: {
                id,
                tabIndex: tabIndex ?? -1,
                'aria-label': ariaLabel,
                'aria-labelledby': ariaLabelledBy,
                'aria-describedby': ariaDescribedBy,
                ...(isHybridMode ? { onMouseEnter, onMouseLeave } : {}),
            },
        },
    ]);
    const convertToTransitionSettings = (duration) => {
        if (!duration || typeof duration === 'number') {
            return duration;
        }
        return { open: duration.enter, close: duration.exit };
    };
    const { isMounted, styles: transitionStyles } = useTransition({
        ...transitionSettings,
        duration: transitionSettings?.duration ??
            convertToTransitionSettings(duration) ??
            (animate ? ANIMATED_DURATION : undefined),
        closeDelay: transitionSettings?.closeDelay ?? hideDelay,
        openDelay: transitionSettings?.openDelay ?? showDelay,
        context,
    });
    return useMemo(() => ({
        dataHook,
        focusManagerEnabled,
        interactions,
        context,
        appendTo,
        zIndex,
        open: isMounted,
        popoverStyles: {
            ...context.floatingStyles,
            ...floatingStyles,
            ...getContentWithArrowStyles(floatingPlacement),
        },
        transitionStyles,
        portalRoot: positioning.portalRoot,
        contextClassName,
        skin,
        overlay,
        style,
        rootRef,
        middlewareData,
        placement,
        arrowProps: getArrowProps(context),
        showArrow,
        contentClassName,
        customArrow,
        onMouseEnter,
        onMouseLeave,
    }), [
        dataHook,
        focusManagerEnabled,
        interactions,
        floatingPlacement,
        context,
        onMouseEnter,
        onMouseLeave,
        isMounted,
        zIndex,
        appendTo,
        positioning,
        transitionStyles,
        contextClassName,
        skin,
        overlay,
        style,
        middlewareData,
        placement,
        showArrow,
        rootRef,
        floatingStyles,
        contentClassName,
        customArrow,
        getArrowProps,
        getContentWithArrowStyles,
    ]);
}
//# sourceMappingURL=usePopover.js.map