import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useState, useEffect, useRef } from 'react';
import { createPortal } from 'react-dom';
import Text from '../Text';
import { useConfiguration, useConsolidatedRef, useI18n, useLiveLog } from '../../hooks';
import Flex from '../Flex';
import Bar from './Bar';
import Ellipsis from './Ellipsis';
import Ring from './Ring';
import { StyledMessage, StyledProgress, StyledProgressBackdrop } from './Progress.styles';
const variantMap = {
    ring: Ring,
    bar: Bar,
    ellipsis: Ellipsis
};
const delayDuration = 100;
const minVisibleDuration = 1000;
const Progress = forwardRef(function Progress({ variant = 'ring', placement = 'global', visible: visibleProp = true, focusOnVisible = false, delay = false, onTransitionStartIn, onTransitionEndIn, onTransitionStartOut, onTransitionEndOut, value, message, liveConfig, ...restProps }, ref) {
    const t = useI18n();
    const { portalTarget } = useConfiguration();
    const { announcePolite } = useLiveLog();
    const progressEl = useConsolidatedRef(ref);
    // Rendering states. Both are needed due to Backdrop's transition phase where isVisibleState is false but nullRender is true until onAfterTransitionOut.
    const [isVisibleState, setIsVisibleState] = useState(delay ? false : visibleProp);
    const [nullRender, setNullRender] = useState(!isVisibleState);
    // Refs for timestamps and timeout ids.
    const timeBeforeVisibleRender = useRef();
    const timeAfterVisibleRender = useRef();
    const delayTimer = useRef();
    const minVisibleTimer = useRef();
    const hasBackdrop = placement === 'global' || placement === 'local';
    const valString = typeof value === 'number' ? `${value}%` : undefined;
    const label = message && valString ? `${message} - ${valString}` : message || valString;
    const renderVisible = () => {
        setIsVisibleState(true);
        setNullRender(false);
    };
    const renderNotVisible = () => {
        setIsVisibleState(false);
        // With a transition, setNullRender needs to be called in Backdrop's onAfterTransitionOut.
        if (!hasBackdrop) {
            setNullRender(true);
        }
    };
    // Handle render and visible state.
    useEffect(() => {
        if (visibleProp) {
            // Capture a timestamp for additional timers.
            timeBeforeVisibleRender.current = Date.now();
            if (delay) {
                delayTimer.current = window.setTimeout(renderVisible, delayDuration);
            }
            else {
                renderVisible();
            }
        }
        else if (
        // A timer was started to render visible either avoid it or render null.
        delayTimer.current !== undefined) {
            // If a timeout has started to render visible, clear it.
            clearTimeout(delayTimer.current);
            // If the indicator has already rendered visible.
            if (timeAfterVisibleRender.current !== undefined) {
                const timeElapsedSinceLastVisibleRender = Date.now() - timeAfterVisibleRender.current;
                // If the indicator has been visible for long enough we can remove it.
                if (timeElapsedSinceLastVisibleRender >= minVisibleDuration) {
                    renderNotVisible();
                }
                else {
                    // Hold off removing until we hit the minimum visible time.
                    minVisibleTimer.current = window.setTimeout(renderNotVisible, minVisibleDuration - timeElapsedSinceLastVisibleRender);
                }
            }
            else {
                renderNotVisible();
            }
        }
        else {
            renderNotVisible();
        }
    }, 
    // visibleProp is the only triggerable dependency. Others values will be captured.
    [visibleProp]);
    // Live announcement
    useEffect(() => {
        if (liveConfig?.contextualLabel && isVisibleState) {
            announcePolite({
                message: `${liveConfig.contextualLabel}, ${label ?? t('loading')}`,
                type: 'status'
            });
        }
    }, 
    // isVisibleState is the only triggerable dependency. Others values will be captured.
    [isVisibleState]);
    // Auto focusing and render timestamping.
    useEffect(() => {
        if (!nullRender && isVisibleState) {
            // After a visible render set a timestamp for timers above.
            timeAfterVisibleRender.current = Date.now();
            if (focusOnVisible)
                progressEl.current?.focus();
        }
    }, 
    // nullRender is the only triggerable dependency. Others values will be captured.
    [nullRender]);
    if (nullRender)
        return null;
    const CompVariant = variantMap[variant];
    let indicator = (_jsx(CompVariant, { "aria-label": typeof value !== 'number' ? label : t('loading'), as: placement === 'inline' ? 'span' : undefined, ...restProps, placement: placement, value: value, "aria-valuetext": typeof value === 'number' ? label : undefined, ref: progressEl, tabIndex: -1 }));
    if (placement !== 'inline') {
        indicator = (_jsxs(Flex, { container: { direction: 'column', alignItems: 'center', gap: 0.5 }, as: StyledProgress, placement: placement, children: [indicator, message && (_jsx(Text, { as: StyledMessage, variant: 'secondary', "aria-hidden": 'true', children: message }))] }));
    }
    const content = hasBackdrop ? (_jsx(StyledProgressBackdrop, { open: isVisibleState, container: { direction: 'column' }, position: placement === 'global' ? 'fixed' : 'absolute', variant: 'light', alpha: 0.8, onBeforeTransitionIn: onTransitionStartIn, onAfterTransitionIn: onTransitionEndIn, onBeforeTransitionOut: onTransitionStartOut, onAfterTransitionOut: () => {
            setNullRender(true);
            onTransitionEndOut?.();
        }, children: indicator })) : (indicator);
    return placement === 'global' && portalTarget ? createPortal(content, portalTarget) : content;
});
export default Progress;
//# sourceMappingURL=Progress.js.map