import React, { forwardRef, useCallback, useEffect, useState, useRef } from "react";
import { createPortal } from "react-dom";
import { useFloating, offset, flip, shift, autoUpdate, arrow, FloatingArrow } from "@floating-ui/react";
import { canUseDOM, safeUseId } from "../../utils";
import { ARROW_HEIGHT, ARROW_PADDING, ARROW_POLYGON, ARROW_WIDTH } from "../_beta/Popover/Popover";
import { getHTMLElement } from "./utils";
import { MaskContainer, Mask, Highlight, TourPortal } from "./Tour.styles";
import { base as viewCSS } from "./variatoins/_view/base";
import { base as sizeCSS } from "./variatoins/_size/base";
import { classes, tokens } from "./Tour.tokens";
export const tourRoot = (Root)=>/*#__PURE__*/ forwardRef(({ steps, current, defaultCurrent = 0, open, defaultOpen = false, withOverlay = true, overlayColor, zIndex = 9000, view, size, offset: offsetProp = [
        12,
        12
    ], highlightOffset = 4, highlightBorderRadius, hasTail = false, tailColor, tailWidth = ARROW_WIDTH, tailHeight = ARROW_HEIGHT, renderStep, renderHighlight, onChange, onClose, ...rest }, outerRef)=>{
        const portalId = safeUseId();
        const isCurrentControlled = typeof current === 'number';
        const isOpenControlled = typeof open === 'boolean';
        const [innerCurrent, setInnerCurrent] = useState(defaultCurrent);
        const [innerOpen, setInnerOpen] = useState(defaultOpen);
        const [highlightRect, setHighlightRect] = useState(null);
        const [targetElement, setTargetElement] = useState(null);
        const portalRef = useRef(null);
        const dialogRef = useRef(null);
        const arrowRef = useRef(null);
        const hasHighlightedRef = useRef(false);
        const active = isCurrentControlled ? current : innerCurrent;
        const isOpen = isOpenControlled ? open : innerOpen;
        const isFirstHighlight = !hasHighlightedRef.current && highlightRect !== null;
        if (isFirstHighlight) {
            hasHighlightedRef.current = true;
        }
        const currentStep = steps[active];
        const placement = currentStep?.placement || 'bottom';
        const middleware = [
            offset((hasTail ? tailHeight : 0) + offsetProp[0] + highlightOffset),
            flip(),
            shift({
                padding: offsetProp[1]
            }),
            hasTail && arrow({
                element: arrowRef,
                padding: ARROW_PADDING
            })
        ];
        const { refs, floatingStyles, placement: calculatedPlacement, context } = useFloating({
            placement,
            middleware,
            whileElementsMounted: autoUpdate
        });
        const setFloatingRef = (el)=>{
            dialogRef.current = el;
            refs.setFloating(el);
        };
        const handleSetOpen = (value)=>{
            if (!isOpenControlled) {
                setInnerOpen(value);
            }
            if (!value) {
                onClose?.();
                setInnerCurrent(0);
                setHighlightRect(null);
                setTargetElement(null);
            }
        };
        const handleSetCurrent = (index)=>{
            if (!isCurrentControlled) {
                setInnerCurrent(index);
            }
            onChange?.(index);
        };
        const handleClose = ()=>{
            handleSetOpen(false);
        };
        const updateHighlight = useCallback(()=>{
            if (!isOpen || !currentStep) {
                return;
            }
            const highlightElement = getHTMLElement(currentStep.target);
            if (!highlightElement) {
                setHighlightRect(null);
                setTargetElement(null);
                return;
            }
            const rect = highlightElement.getBoundingClientRect();
            setHighlightRect(rect);
            setTargetElement(highlightElement);
        }, [
            isOpen,
            currentStep
        ]);
        useEffect(()=>{
            refs.setReference(targetElement);
        }, [
            refs,
            targetElement
        ]);
        useEffect(()=>{
            if (isOpen) {
                if (targetElement) {
                    const rect = targetElement.getBoundingClientRect();
                    const isInViewport = rect.top >= 0 && rect.left >= 0 && rect.bottom <= window.innerHeight && rect.right <= window.innerWidth;
                    if (!isInViewport) {
                        targetElement.scrollIntoView({
                            block: 'center',
                            inline: 'center',
                            behavior: 'smooth'
                        });
                    }
                }
                if (dialogRef.current) {
                    dialogRef.current.focus({
                        preventScroll: true
                    });
                }
            }
        }, [
            isOpen,
            targetElement
        ]);
        useEffect(()=>{
            if (!canUseDOM) {
                return;
            }
            let portal = document.getElementById(portalId);
            if (!portal) {
                portal = document.createElement('div');
                portal.setAttribute('id', portalId);
                document.body.appendChild(portal);
            }
            portalRef.current = portal;
            return ()=>{
                portal?.remove();
            };
        }, []);
        useEffect(()=>{
            if (!isOpen) {
                return;
            }
            updateHighlight();
            window.addEventListener('resize', updateHighlight);
            window.addEventListener('scroll', updateHighlight, true);
            return ()=>{
                window.removeEventListener('resize', updateHighlight);
                window.removeEventListener('scroll', updateHighlight, true);
            };
        }, [
            isOpen,
            updateHighlight
        ]);
        useEffect(()=>{
            if (!isOpen) {
                return;
            }
            const handleKeyDown = (e)=>{
                if (e.key === 'Escape') {
                    handleClose();
                }
            };
            window.addEventListener('keydown', handleKeyDown);
            return ()=>{
                window.removeEventListener('keydown', handleKeyDown);
            };
        }, [
            isOpen,
            handleClose
        ]);
        useEffect(()=>{
            if (!isOpen) {
                hasHighlightedRef.current = false;
                setHighlightRect(null);
            }
        }, [
            isOpen
        ]);
        if (!currentStep || !canUseDOM || !portalRef.current) {
            return null;
        }
        const arrowFill = tailColor || `var(${tokens.tailColor})`;
        const preparedHighlightBorderRadius = currentStep?.highlightBorderRadius ?? highlightBorderRadius ?? undefined;
        const preparedHighlightOffset = currentStep?.highlightOffset || highlightOffset;
        const highlightProps = highlightRect ? {
            left: highlightRect.left - preparedHighlightOffset,
            top: highlightRect.top - preparedHighlightOffset,
            width: highlightRect.width + preparedHighlightOffset * 2,
            height: highlightRect.height + preparedHighlightOffset * 2,
            borderRadius: preparedHighlightBorderRadius,
            highlightOffset: preparedHighlightOffset
        } : null;
        const highlightNode = highlightProps && (renderHighlight ? renderHighlight(highlightProps) : /*#__PURE__*/ React.createElement(Highlight, {
            withOverlay: withOverlay,
            overlayColor: overlayColor,
            borderRadius: preparedHighlightBorderRadius,
            disableTransition: isFirstHighlight,
            style: {
                left: highlightProps.left,
                top: highlightProps.top,
                width: highlightProps.width,
                height: highlightProps.height
            }
        }));
        const tourContent = /*#__PURE__*/ React.createElement(Root, {
            ref: outerRef,
            view: view,
            size: size,
            ...rest
        }, isOpen && Boolean(targetElement) && /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement(MaskContainer, {
            className: classes.mask,
            zIndex: zIndex
        }, withOverlay ? /*#__PURE__*/ React.createElement(Mask, null) : null, highlightNode), /*#__PURE__*/ React.createElement(TourPortal, {
            ref: setFloatingRef,
            role: "dialog",
            "aria-modal": "true",
            tabIndex: -1,
            style: {
                ...floatingStyles,
                zIndex: Number(zIndex)
            },
            "data-placement": calculatedPlacement
        }, renderStep(active, steps.length, active === steps.length - 1, steps[active], handleSetCurrent), hasTail && /*#__PURE__*/ React.createElement(FloatingArrow, {
            ref: arrowRef,
            context: context,
            width: tailWidth,
            height: tailHeight,
            fill: arrowFill,
            d: ARROW_POLYGON
        }))));
        return /*#__PURE__*/ createPortal(tourContent, portalRef.current);
    });
export const tourConfig = {
    name: 'Tour',
    tag: 'div',
    layout: tourRoot,
    base: '',
    variations: {
        view: {
            css: viewCSS
        },
        size: {
            css: sizeCSS
        }
    },
    defaults: {
        view: 'default',
        size: 'm'
    }
};
