import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
// (C) 2020-2026 GoodData Corporation
import { memo, useCallback, useMemo, useState } from "react";
import cx from "classnames";
import { cloneDeep, result } from "lodash-es";
import isReactEqual from "react-fast-compare";
import { ZoomAwareOverlay } from "../Overlay/ZoomAwareOverlay.js";
const ARROW_DIRECTIONS = {
    ".. cc": "none",
    ".r .l|.. cl": "left",
    ".l .r|.. cr": "right",
    ".. t.": "top",
    ".. b.": "bottom",
    ".. .l": "left",
    ".. .r": "right",
};
// FIXME: hardcoded offsets for Indigo style
export const X_SHIFT = 7;
export const Y_SHIFT = 11;
// FIXME: constants are bad, we know
const ARROW_OFFSETS = {
    ".. cc": [0, 0],
    ".. tc": [0, X_SHIFT],
    ".. bc": [0, -X_SHIFT],
    ".. cl": [X_SHIFT, 0],
    ".. cr": [-X_SHIFT, 0],
    ".r tl": [X_SHIFT, -Y_SHIFT],
    ".l tr": [-X_SHIFT, -Y_SHIFT],
    ".r bl": [X_SHIFT, Y_SHIFT],
    ".l br": [-X_SHIFT, Y_SHIFT],
    ".. tl": [-Y_SHIFT, X_SHIFT],
    ".. tr": [Y_SHIFT, X_SHIFT],
    ".. bl": [-Y_SHIFT, -X_SHIFT],
    ".. br": [Y_SHIFT, -X_SHIFT],
};
const defaultProps = {
    alignPoints: [
        {
            align: "bl tl",
        },
    ],
    alignTo: "body",
    arrowOffsets: {},
    arrowDirections: {},
    arrowStyle: {},
    className: "bubble-primary",
    closeOnOutsideClick: false,
    closeOnParentScroll: true,
    closeOnEscape: false,
    onClose: () => { },
    onMouseEnter: () => { },
    onMouseLeave: () => { },
    overlayClassName: "",
};
/**
 * @internal
 */
export const Bubble = memo(function Bubble(props) {
    const { id, alignPoints: alignPointsProp, alignTo, arrowOffsets: arrowOffsetsProp, arrowDirections: arrowDirectionsProp, arrowStyle: arrowStyleProp, className, closeOnOutsideClick, closeOnParentScroll, closeOnEscape, ignoreClicksOn, ignoreClicksOnByClass, onClose, onMouseEnter, onMouseLeave, onKeyDown, overlayClassName, children, overlayPositionType, ensureVisibility, accessibilityConfig, } = { ...defaultProps, ...props };
    const { role, ariaLabelledBy } = accessibilityConfig ?? {};
    const arrowOffsets = useMemo(() => ({
        ...arrowOffsetsProp,
        ...ARROW_OFFSETS,
    }), [arrowOffsetsProp]);
    const arrowDirections = useMemo(() => ({
        ...arrowDirectionsProp,
        ...ARROW_DIRECTIONS,
    }), [arrowDirectionsProp]);
    const addOffsetToAlignPoints = useCallback((alignPoints) => {
        const arrowOffsetsKeys = Object.keys(arrowOffsets);
        const getKey = (align, re) => {
            return align.match(re) !== null;
        };
        return alignPoints.map((item) => {
            const key = arrowOffsetsKeys.find(getKey.bind(null, item.align));
            const existingOffset = item.offset || { x: 0, y: 0 };
            const arrowOffset = key ? arrowOffsets[key] : [0, 0];
            return {
                ...item,
                offset: {
                    x: (existingOffset.x ?? 0) + arrowOffset[0],
                    y: (existingOffset.y ?? 0) + arrowOffset[1],
                },
            };
        });
    }, [arrowOffsets]);
    const initialAlignPoints = useMemo(() => addOffsetToAlignPoints(cloneDeep(alignPointsProp)), [addOffsetToAlignPoints, alignPointsProp]);
    const [alignPoints] = useState(initialAlignPoints);
    const [optimalAlignPoints, setOptimalAlignPoints] = useState(alignPointsProp[0].align);
    const onAlign = useCallback((alignment) => {
        setOptimalAlignPoints(alignment.align);
    }, []);
    const getArrowDirection = useCallback((alignPoints) => {
        const key = Object.keys(arrowDirections).find((arrowDirection) => alignPoints.match(arrowDirection));
        return (key ? arrowDirections[key] : undefined) || "none";
    }, [arrowDirections]);
    const getArrowsClassname = useCallback((alignPoints) => {
        const myAlignPoint = alignPoints.split(" ")[1];
        const direction = getArrowDirection(alignPoints);
        return `arrow-${direction}-direction arrow-${myAlignPoint}`;
    }, [getArrowDirection]);
    const classNames = useMemo(() => {
        return cx({
            [className]: !!className,
            [getArrowsClassname(optimalAlignPoints)]: true,
            "gd-bubble": true,
            bubble: true,
        });
    }, [className, getArrowsClassname, optimalAlignPoints]);
    const arrowStyle = useMemo(() => result({ arrowStyle: arrowStyleProp }, "arrowStyle", {}), [arrowStyleProp]);
    return (_jsx(ZoomAwareOverlay, { id: id, className: overlayClassName, alignTo: alignTo, onAlign: onAlign, alignPoints: alignPoints, closeOnParentScroll: closeOnParentScroll, closeOnMouseDrag: true, closeOnOutsideClick: closeOnOutsideClick, ignoreClicksOn: ignoreClicksOn, ignoreClicksOnByClass: ignoreClicksOnByClass, onClose: onClose, closeOnEscape: closeOnEscape, positionType: overlayPositionType, ensureVisibility: ensureVisibility, children: _jsx("div", { onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onKeyDown: onKeyDown, className: classNames, role: role, "aria-labelledby": ariaLabelledBy, children: _jsxs("div", { className: "bubble-content", children: [
                    _jsx("div", { className: "helper" }), _jsxs("div", { className: "arrow-position", style: arrowStyle, children: [
                            _jsx("div", { className: "arrow-border" }), _jsx("div", { className: "arrow" })
                        ] }), _jsx("div", { className: "content", children: children })
                ] }) }) }));
}, (prevProps, nextProps) => {
    return isReactEqual(prevProps, nextProps);
});
// identifier for BubbleTrigger
Bubble.identifier = "Bubble";
