/**
 * @license MIT
 * author: Cube Dev Team
 * @cube-dev/ui-kit v0.0.0-canary-9f08182
 * Released under the MIT license.
 */

import { jsx as _jsx } from "react/jsx-runtime";
import { createContext, useCallback, useContext, useMemo, useRef, useState, useSyncExternalStore, } from 'react';
export const LayoutActionsContext = createContext(null);
export const LayoutStateContext = createContext(null);
/** @deprecated Use useLayoutActionsContext and useLayoutStateContext separately */
export const LayoutContext = createContext(null);
export function useLayoutActionsContext() {
    return useContext(LayoutActionsContext);
}
export function useLayoutStateContext() {
    return useContext(LayoutStateContext);
}
export function useLayoutContext() {
    return useContext(LayoutContext);
}
/**
 * Hook to get panel sizes without causing re-renders on every size change.
 * Uses useSyncExternalStore for efficient subscriptions.
 */
export function usePanelSizes() {
    const actions = useLayoutActionsContext();
    const defaultSizes = { left: 0, top: 0, right: 0, bottom: 0 };
    return useSyncExternalStore(actions?.subscribeToPanelSizes ?? (() => () => { }), actions?.getPanelSizes ?? (() => defaultSizes), () => defaultSizes);
}
export function LayoutProvider({ children, hasTransition = false, }) {
    const registeredPanels = useRef(new Set());
    const overlayPanelCallbacks = useRef(new Set());
    // Use ref for panel sizes to avoid re-renders in Panels when sizes change
    const panelSizesRef = useRef({
        left: 0,
        top: 0,
        right: 0,
        bottom: 0,
    });
    const panelSizesSubscribers = useRef(new Set());
    // State for values that need to trigger re-renders
    const [panelSizes, setPanelSizes] = useState({
        left: 0,
        top: 0,
        right: 0,
        bottom: 0,
    });
    const [isDragging, setIsDragging] = useState(false);
    const [isReady, setIsReady] = useState(false);
    const [hasOverlayPanels, setHasOverlayPanels] = useState(false);
    // Notify subscribers when panel sizes change
    const notifyPanelSizesSubscribers = useCallback(() => {
        panelSizesSubscribers.current.forEach((callback) => callback());
    }, []);
    const registerPanel = useCallback((side, size) => {
        if (registeredPanels.current.has(side)) {
            throw new Error(`Layout: Only one panel per side is allowed. ` +
                `A panel is already registered on the "${side}" side.`);
        }
        // Check for axis conflict
        const isHorizontal = side === 'left' || side === 'right';
        const conflictingSides = isHorizontal
            ? ['top', 'bottom']
            : ['left', 'right'];
        for (const conflictSide of conflictingSides) {
            if (registeredPanels.current.has(conflictSide)) {
                throw new Error(`Layout: Panels from different axes cannot be combined. ` +
                    `Cannot register "${side}" panel when "${conflictSide}" panel exists. ` +
                    `Use either horizontal (left/right) or vertical (top/bottom) panels.`);
            }
        }
        registeredPanels.current.add(side);
        // Update ref immediately for synchronous access
        if (panelSizesRef.current[side] !== size) {
            panelSizesRef.current = { ...panelSizesRef.current, [side]: size };
            notifyPanelSizesSubscribers();
        }
        // Also update state for Layout component re-renders
        setPanelSizes((prev) => {
            if (prev[side] === size)
                return prev;
            return { ...prev, [side]: size };
        });
    }, [notifyPanelSizesSubscribers]);
    const unregisterPanel = useCallback((side) => {
        registeredPanels.current.delete(side);
        // Update ref immediately
        if (panelSizesRef.current[side] !== 0) {
            panelSizesRef.current = { ...panelSizesRef.current, [side]: 0 };
            notifyPanelSizesSubscribers();
        }
        setPanelSizes((prev) => {
            if (prev[side] === 0)
                return prev;
            return { ...prev, [side]: 0 };
        });
    }, [notifyPanelSizesSubscribers]);
    const updatePanelSize = useCallback((side, size) => {
        // Update ref immediately
        if (panelSizesRef.current[side] !== size) {
            panelSizesRef.current = { ...panelSizesRef.current, [side]: size };
            notifyPanelSizesSubscribers();
        }
        setPanelSizes((prev) => {
            // Only update if the size actually changed
            if (prev[side] === size)
                return prev;
            return { ...prev, [side]: size };
        });
    }, [notifyPanelSizesSubscribers]);
    const setDragging = useCallback((dragging) => {
        setIsDragging(dragging);
    }, []);
    const markReady = useCallback(() => {
        setIsReady(true);
    }, []);
    // Register an overlay panel's dismiss callback
    const registerOverlayPanel = useCallback((dismiss) => {
        overlayPanelCallbacks.current.add(dismiss);
        setHasOverlayPanels(true);
        // Return unregister function
        return () => {
            overlayPanelCallbacks.current.delete(dismiss);
            setHasOverlayPanels(overlayPanelCallbacks.current.size > 0);
        };
    }, []);
    // Dismiss all overlay panels
    const dismissOverlayPanels = useCallback(() => {
        overlayPanelCallbacks.current.forEach((dismiss) => dismiss());
    }, []);
    // Subscribe to panel sizes changes (for useSyncExternalStore)
    const subscribeToPanelSizes = useCallback((callback) => {
        panelSizesSubscribers.current.add(callback);
        return () => {
            panelSizesSubscribers.current.delete(callback);
        };
    }, []);
    // Get current panel sizes snapshot
    const getPanelSizes = useCallback(() => panelSizesRef.current, []);
    // Actions context - stable, doesn't change
    const actionsValue = useMemo(() => ({
        registerPanel,
        unregisterPanel,
        updatePanelSize,
        setDragging,
        markReady,
        hasTransition,
        registerOverlayPanel,
        dismissOverlayPanels,
        subscribeToPanelSizes,
        getPanelSizes,
    }), [
        registerPanel,
        unregisterPanel,
        updatePanelSize,
        setDragging,
        markReady,
        hasTransition,
        registerOverlayPanel,
        dismissOverlayPanels,
        subscribeToPanelSizes,
        getPanelSizes,
    ]);
    // State context - changes when state updates
    const stateValue = useMemo(() => ({
        panelSizes,
        isDragging,
        isReady,
        hasOverlayPanels,
    }), [panelSizes, isDragging, isReady, hasOverlayPanels]);
    // Combined value for backwards compatibility
    const combinedValue = useMemo(() => ({
        ...actionsValue,
        ...stateValue,
    }), [actionsValue, stateValue]);
    return (_jsx(LayoutActionsContext.Provider, { value: actionsValue, children: _jsx(LayoutStateContext.Provider, { value: stateValue, children: _jsx(LayoutContext.Provider, { value: combinedValue, children: children }) }) }));
}
/**
 * Provider that resets the layout context for sub-components.
 * Used to prevent panels in nested Layouts from affecting parent layouts.
 */
export function LayoutContextReset({ children }) {
    return (_jsx(LayoutActionsContext.Provider, { value: null, children: _jsx(LayoutStateContext.Provider, { value: null, children: _jsx(LayoutContext.Provider, { value: null, children: children }) }) }));
}
export const LayoutPanelContext = createContext(null);
export function useLayoutPanelContext() {
    return useContext(LayoutPanelContext);
}

        