import React, { forwardRef, useCallback, useEffect, useId, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { useForwardedRef } from "@bedrock-layout/use-forwarded-ref";
import { fnWithProps } from "../../../types/fnWithProps.js";
import { HandleEsc } from "../../utils/HandleEsc.js";
import { ContainerStyled, NEGATIVE_PADDING, OverlayStyled, RemovePadding, TitleStyled } from "./Modal.styled.js";
const FOCUSABLE_SELECTOR = [
    "a[href]",
    "button:not([disabled])",
    "input:not([disabled])",
    "select:not([disabled])",
    "textarea:not([disabled])",
    "[tabindex]:not([tabindex=\"-1\"])",
].join(",");
const prefersReducedMotion = () => {
    if (typeof window === "undefined") {
        return false;
    }
    return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
};
const ModalBase = forwardRef(({ children, onClose, isOpen, title, className, onOverlayClick = "close", closeOnEsc = true, portal = true, position, full, ...rest }, ref) => {
    const [isClosing, setIsClosing] = useState(false);
    const [isRendered, setIsRendered] = useState(false);
    const overlayRef = useRef(null);
    const containerRef = useForwardedRef(ref);
    const previouslyFocusedRef = useRef(null);
    const titleId = useId();
    useEffect(() => {
        if (isOpen) {
            setIsRendered(true);
            setIsClosing(false);
            return;
        }
        if (prefersReducedMotion()) {
            setIsRendered(false);
            setIsClosing(false);
            return;
        }
        setIsClosing(true);
    }, [isOpen]);
    useEffect(() => {
        if (!isClosing) {
            return;
        }
        const overlay = overlayRef.current;
        const container = containerRef.current;
        if (!overlay || !container) {
            return;
        }
        overlay.style.animation = "none";
        container.style.animation = "none";
        overlay.offsetHeight;
        overlay.style.removeProperty("animation");
        container.style.removeProperty("animation");
    }, [isClosing, containerRef]);
    useEffect(() => {
        var _a;
        if (!isOpen || !isRendered) {
            return;
        }
        const container = containerRef.current;
        const overlay = overlayRef.current;
        if (!container || !overlay) {
            return;
        }
        previouslyFocusedRef.current = document.activeElement instanceof HTMLElement
            ? document.activeElement
            : null;
        const focusables = container.querySelectorAll(FOCUSABLE_SELECTOR);
        ((_a = focusables[0]) !== null && _a !== void 0 ? _a : container).focus();
        const inerted = [];
        let cursor = overlay;
        while (cursor !== document.body) {
            const parentEl = cursor.parentElement;
            if (!parentEl) {
                break;
            }
            for (const child of Array.from(parentEl.children)) {
                if (child === cursor || !(child instanceof HTMLElement)) {
                    continue;
                }
                if (!child.hasAttribute("inert")) {
                    child.setAttribute("inert", "");
                    inerted.push(child);
                }
            }
            cursor = parentEl;
        }
        return () => {
            var _a;
            inerted.forEach((el) => {
                el.removeAttribute("inert");
            });
            (_a = previouslyFocusedRef.current) === null || _a === void 0 ? void 0 : _a.focus();
        };
    }, [isOpen, isRendered, containerRef]);
    const titleElem = title ? React.createElement(TitleStyled, { id: titleId }, title) : null;
    const handleOverlayClick = useCallback((e) => {
        if (e.target !== e.currentTarget) {
            return;
        }
        if (onOverlayClick === "close") {
            onClose();
        }
        else if (typeof onOverlayClick === "function") {
            onOverlayClick();
        }
    }, [onOverlayClick, onClose]);
    const handleAnimationEnd = useCallback((e) => {
        if (e.target !== e.currentTarget) {
            return;
        }
        if (isOpen) {
            return;
        }
        setIsRendered(false);
    }, [isOpen]);
    if (!isRendered) {
        return null;
    }
    const overlayVariants = {};
    if (isClosing) {
        overlayVariants.isClosing = true;
    }
    if (position != null) {
        overlayVariants.position = position;
    }
    const containerVariants = {};
    if (isClosing) {
        containerVariants.isClosing = true;
    }
    if (full != null) {
        containerVariants.full = full;
    }
    const childrenCount = React.Children.count(children);
    const chld = React.Children.map(children, (child, index) => {
        var _a;
        if (React.isValidElement(child) && child.type === RemovePadding) {
            const css = { ...((_a = child.props.css) !== null && _a !== void 0 ? _a : {}) };
            if (index === 0 && titleElem == null) {
                css.marginTop = NEGATIVE_PADDING;
            }
            if (index === childrenCount - 1) {
                css.marginBottom = NEGATIVE_PADDING;
            }
            return React.cloneElement(child, { css });
        }
        return child;
    });
    const tree = (React.createElement(OverlayStyled, { ...overlayVariants, onClick: handleOverlayClick, ref: overlayRef, onAnimationEnd: handleAnimationEnd },
        closeOnEsc ? React.createElement(HandleEsc, { onPress: onClose }) : null,
        React.createElement(ContainerStyled, { role: "dialog", "aria-modal": true, "aria-labelledby": titleElem ? titleId : undefined, tabIndex: -1, className: className, ...containerVariants, ref: containerRef, ...rest },
            titleElem,
            chld)));
    if (portal) {
        const root = typeof portal === "boolean" ? document.body : portal;
        return createPortal(tree, root);
    }
    return tree;
});
ModalBase.displayName = "Modal";
const Modal = fnWithProps(ModalBase, {
    RemovePadding,
});
Modal.toString = () => OverlayStyled.toString();
const ModalContainerSelector = ContainerStyled.toString();
const ModalTitleSelector = TitleStyled.toString();
const ModalRemovePaddingSelector = RemovePadding.toString();
export { Modal, ModalContainerSelector, ModalTitleSelector, ModalRemovePaddingSelector };
//# sourceMappingURL=Modal.js.map