import { jsx as _jsx } from "react/jsx-runtime";
import { forwardRef, useCallback, useEffect, useRef, useState } from 'react';
import styled, { css } from 'styled-components';
import { defaultThemeProp } from '../../theme';
import Popover from '../Popover';
import { useConsolidatedRef, useTestIds, useTheme, useUID } from '../../hooks';
import { calculateFontSize, readableHue } from '../../styles';
import { getActiveElement, mouseState, testElForOverflow, withTestIds } from '../../utils';
import { ThemeOverride } from '../Configuration';
import { getTooltipTestIds } from './Tooltip.test-ids';
export const StyledTooltip = styled.div(({ theme }) => {
    const fontSize = calculateFontSize(theme.base['font-size'], theme.base['font-scale']);
    return css `
    background-color: ${theme.components.tooltip['background-color']};
    color: ${theme.components.tooltip['foreground-color']};
    font-size: ${fontSize.xxs};
    max-width: 40ch;
    padding: ${theme.base.spacing};
    white-space: pre-line;
    word-break: break-word;
  `;
});
StyledTooltip.defaultProps = defaultThemeProp;
const Tooltip = forwardRef(function Tooltip({ testId, children, target, ignoredElements = [], showDelay = 'short', hideDelay = 'long', placement = 'top', describeTarget = true, smart, groupId = 'tooltip', ...restProps }, ref) {
    const id = useUID();
    const [show, setShow] = useState(false);
    const [ignoreDelay, setIgnoreDelay] = useState(false);
    const tooltipRef = useConsolidatedRef(ref);
    const lastClickedRef = useRef(null);
    const testIds = useTestIds(testId, getTooltipTestIds);
    const stringContentOnly = typeof children === 'string' ||
        (Array.isArray(children) && children.every(child => typeof child === 'string'));
    const onMouseDown = useCallback(({ target: eTarget }) => {
        lastClickedRef.current = eTarget;
        if (eTarget === tooltipRef.current || eTarget === target)
            return;
        setShow(false);
    }, [target]);
    useEffect(() => {
        if (!target)
            return;
        const showTooltip = () => {
            // This approach may result in a tooltip NOT appearing 1px before it should due to browser specifics. Enhance as needed.
            // https://stackoverflow.com/a/64747288
            const checkTruncation = (element) => {
                if (testElForOverflow(element).some(Boolean) &&
                    !['absolute', 'fixed'].includes(window.getComputedStyle(element).position))
                    return true;
                for (const child of element.children) {
                    if (checkTruncation(child))
                        return true;
                }
                return false;
            };
            setShow(smart ? checkTruncation(target) : true);
        };
        const onFocusIn = () => {
            showTooltip();
        };
        const onFocusOut = () => {
            if (!lastClickedRef.current || lastClickedRef.current !== tooltipRef.current) {
                setShow(false);
            }
            lastClickedRef.current = null;
        };
        const onMouseEnter = () => {
            if (ignoredElements.some(exclusion => exclusion?.matches(':hover')) || mouseState.primary) {
                return;
            }
            showTooltip();
        };
        const onMouseLeave = () => {
            if (getActiveElement() !== target) {
                setShow(false);
            }
        };
        const onKeyDown = ({ key }) => {
            if (key === 'Escape' && show) {
                setIgnoreDelay(true);
                setShow(false);
            }
        };
        document.addEventListener('keydown', onKeyDown);
        document.addEventListener('mousedown', onMouseDown);
        target.addEventListener('focusin', onFocusIn);
        target.addEventListener('focusout', onFocusOut);
        target.addEventListener('mouseenter', onMouseEnter);
        target.addEventListener('mouseleave', onMouseLeave);
        return () => {
            document.removeEventListener('keydown', onKeyDown);
            document.removeEventListener('mousedown', onMouseDown);
            target.removeEventListener('focusin', onFocusIn);
            target.removeEventListener('focusout', onFocusOut);
            target.removeEventListener('mouseenter', onMouseEnter);
            target.removeEventListener('mouseleave', onMouseLeave);
        };
    }, [target, onMouseDown, smart, show]);
    useEffect(() => {
        if (target && describeTarget && show) {
            const describedBy = target.getAttribute('aria-describedby');
            // Set the attribute to the old attribute plus the id
            target.setAttribute('aria-describedby', describedBy ? `${describedBy} ${id}` : id);
        }
        else if (target) {
            // Get the old attribute
            const describedBy = target.getAttribute('aria-describedby');
            if (describedBy) {
                // If the old attribute matches the id just remove it entirely
                if (describedBy === id) {
                    target.removeAttribute('aria-describedby');
                }
                else {
                    // Otherwise we want to just remove the id that was added and reset the attribute to what it was before
                    const oldDescribedBy = describedBy.replace(new RegExp(`(?:^|\\s+)${id}`), '');
                    target.setAttribute('aria-describedby', oldDescribedBy);
                }
            }
        }
    }, [describeTarget, target, show]);
    useEffect(() => {
        if (!show && ignoreDelay) {
            setIgnoreDelay(false);
        }
    }, [show, ignoreDelay]);
    const theme = useTheme();
    const tooltipTheme = {
        base: {
            palette: {
                'primary-background': theme.components.tooltip['background-color'],
                'foreground-color': theme.components.tooltip['foreground-color'],
                interactive: readableHue(theme.base.palette.interactive, theme.components.tooltip['background-color'])
            }
        }
    };
    return (_jsx(ThemeOverride, { theme: tooltipTheme, children: _jsx(Popover, { "data-testid": testIds.root, id: id, groupId: groupId, ...restProps, show: show, showDelay: ignoreDelay ? 'none' : showDelay, hideDelay: ignoreDelay ? 'none' : hideDelay, onMouseOver: () => {
                setShow(true);
            }, onMouseOut: () => {
                setShow(false);
            }, strategy: 'fixed', as: StyledTooltip, role: stringContentOnly ? 'tooltip' : 'dialog', target: target, arrow: true, placement: placement, onMouseDown: onMouseDown, hideOnTargetHidden: true, ref: tooltipRef, children: children }) }));
});
export default withTestIds(Tooltip, getTooltipTestIds);
//# sourceMappingURL=Tooltip.js.map