import React, { useCallback, useEffect, useRef } from 'react';
import * as Dialog from '@radix-ui/react-dialog';
import { classes, st } from './Drawer.st.css.js';
import { DATA_HOOKS } from './Drawer.constants';
import { ZIndex } from '../common/ZIndex';
const Drawer = ({ open, backdrop = true, renderBackdrop = true, resizable = true, margin = true, onClose, role = 'dialog', ariaLabelledBy, snapPoints = [1], children, dismissible = true, dataHook, zIndex = ZIndex.popover, scrollable = true, repositionInputs = true, }) => {
    const contentRef = useRef(null);
    const restingY = useRef(0);
    const dragState = useRef({
        isDragging: false,
        startY: 0,
        startTranslateY: 0,
        currentDelta: 0,
    });
    useEffect(() => {
        if (!open ||
            !repositionInputs ||
            typeof window === 'undefined' ||
            !window.visualViewport) {
            return;
        }
        const viewport = window.visualViewport;
        const el = contentRef.current;
        const onViewportResize = () => {
            if (!el)
                return;
            const keyboardHeight = Math.max(0, window.innerHeight - viewport.height - viewport.offsetTop);
            el.style.bottom = keyboardHeight > 0 ? `${keyboardHeight}px` : '';
        };
        viewport.addEventListener('resize', onViewportResize);
        return () => {
            viewport.removeEventListener('resize', onViewportResize);
            if (el) {
                el.style.bottom = '';
            }
        };
    }, [open, repositionInputs]);
    const resolveSnapPoint = (snap) => {
        const value = typeof snap === 'string' ? parseFloat(snap.replace('px', '')) : snap;
        if (value <= 1) {
            return value * (contentRef.current?.clientHeight ?? window.innerHeight);
        }
        return value;
    };
    const animateToY = (fromY, toY, onDone) => {
        const el = contentRef.current;
        if (!el)
            return;
        el.style.animation = 'none';
        // Check needed for JSDOM environment, since animation api isn't implemented
        if (typeof el.animate !== 'function') {
            el.style.transform = toY === 0 ? '' : `translateY(${toY}px)`;
            el.style.animation = '';
            restingY.current = toY;
            onDone?.();
            return;
        }
        const anim = el.animate([
            { transform: `translateY(${fromY}px)` },
            { transform: `translateY(${toY}px)` },
        ], { duration: 300, easing: 'ease' });
        anim.onfinish = () => {
            el.style.transform = toY === 0 ? '' : `translateY(${toY}px)`;
            if (onDone) {
                onDone();
            }
            else {
                el.style.animation = '';
                restingY.current = toY;
            }
        };
    };
    const onHandlePointerDown = (e) => {
        e.currentTarget.setPointerCapture(e.pointerId);
        dragState.current = {
            isDragging: true,
            startY: e.clientY,
            startTranslateY: restingY.current,
            currentDelta: 0,
        };
        if (contentRef.current) {
            contentRef.current.style.animation = 'none';
            contentRef.current.style.transition = 'none';
        }
    };
    const onHandlePointerMove = (e) => {
        if (!dragState.current.isDragging)
            return;
        const delta = e.clientY - dragState.current.startY;
        dragState.current.currentDelta = delta;
        const newY = Math.max(0, dragState.current.startTranslateY + delta);
        if (contentRef.current) {
            contentRef.current.style.transform = `translateY(${newY}px)`;
        }
    };
    const onHandlePointerUp = () => {
        if (!dragState.current.isDragging)
            return;
        dragState.current.isDragging = false;
        const el = contentRef.current;
        if (!el)
            return;
        const contentHeight = el.offsetHeight;
        const currentY = Math.max(0, dragState.current.startTranslateY + dragState.current.currentDelta);
        const resolvedSnaps = snapPoints
            .map(resolveSnapPoint)
            .sort((a, b) => a - b);
        const visibleHeight = contentHeight - currentY;
        const lowestSnap = resolvedSnaps[0];
        if (dismissible && visibleHeight < lowestSnap * 0.5) {
            animateToY(currentY, contentHeight, () => onClose(false));
            return;
        }
        let nearest = resolvedSnaps[0];
        let minDist = Infinity;
        for (const snap of resolvedSnaps) {
            const dist = Math.abs(visibleHeight - snap);
            if (dist < minDist) {
                minDist = dist;
                nearest = snap;
            }
        }
        animateToY(currentY, Math.max(0, contentHeight - nearest));
    };
    const handleDismiss = (e) => {
        e.preventDefault();
        if (!dismissible)
            return;
        const el = contentRef.current;
        if (!el) {
            onClose(false);
            return;
        }
        animateToY(restingY.current, el.offsetHeight, () => onClose(false));
    };
    const lastAnimatedElRef = useRef(null);
    const handleContentRef = useCallback((el) => {
        if (el && el !== lastAnimatedElRef.current) {
            contentRef.current = el;
            lastAnimatedElRef.current = el;
            if (!contentRef.current)
                return;
            const snapPx = resolveSnapPoint(snapPoints[0]);
            const targetY = Math.max(0, el.offsetHeight - snapPx);
            animateToY(contentRef.current.clientHeight, targetY);
        }
    }, [snapPoints]);
    return (React.createElement("div", { "data-hook": dataHook },
        React.createElement(Dialog.Root, { open: open, onOpenChange: onClose },
            React.createElement(Dialog.Portal, null,
                renderBackdrop && (React.createElement(Dialog.Overlay, { "data-hook": DATA_HOOKS.OVERLAY, className: st(classes.overlay, { backdrop }), style: { zIndex } })),
                React.createElement(Dialog.Content, { ref: handleContentRef, "data-hook": DATA_HOOKS.CONTENT, "aria-modal": "true", "aria-labelledby": ariaLabelledBy, role: role, className: st(classes.content, { margin }), onInteractOutside: handleDismiss, onEscapeKeyDown: handleDismiss, style: {
                        zIndex,
                    } },
                    React.createElement(Dialog.Title, { className: classes.title }),
                    resizable && (React.createElement("div", { className: classes.handle, "data-hook": DATA_HOOKS.HANDLE, onPointerDown: onHandlePointerDown, onPointerMove: onHandlePointerMove, onPointerUp: onHandlePointerUp })),
                    scrollable ? (React.createElement("div", { className: st(classes.contentWrapper, { margin }) }, children)) : (children))))));
};
Drawer.displayName = 'Drawer';
export default Drawer;
//# sourceMappingURL=Drawer.js.map