import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import React, { useCallback, useMemo } from "react";
import { cn } from "../lib/utils";
import { useEditContext } from "./client/editContext";
import { SidebarStack } from "./sidebar/SidebarStack";
import { Splitter } from "./ui/Splitter";
import { GlobalMenuBar } from "./GlobalMenuBar";
import { ArrowLeftToLine, ArrowRightToLine, Layers } from "lucide-react";
import { MobileLayout } from "./MobileLayout";
import { WorkspaceRail } from "./sidebar/WorkspaceRail";
import { ContentTreePanel } from "./sidebar/ContentTreePanel";
import { CONTENT_TREE_PANEL_SURFACE_KEY, CONTENT_TREE_SIDEBAR_ID, } from "./sidebar/contentTreeConstants";
// Fallback only: closed sidebar stacks are normally unmounted when their
// collapse transition ends (event-driven, see handlePanelTransitionEnd). This
// guardrail ensures cleanup even if a transitionend is ever missed.
const SIDEBAR_COLLAPSE_SAFETY_MS = 400;
const CONTENT_TREE_PANEL_COLLAPSE_SAFETY_MS = 400;
const AGENTS_PANEL_SURFACE_KEY = "agents-panel";
const CONTENT_TREE_PANEL_NAME = "contentTree";
function getSidebarStackPanelName(stackIds) {
    return stackIds.length === 1
        ? `sidebar-${stackIds[0]}`
        : `sidebarStack-${stackIds.join("-")}`;
}
function hasSidebarDragData(e) {
    return (e.dataTransfer.types.includes("text/alpaca-sidebar") ||
        e.dataTransfer.types.includes("text/alpaca-sidebar-icon"));
}
function getSidebarStackKey(stackIds) {
    return stackIds.join("|");
}
function getSidebarStackKeySignature(stacks) {
    return stacks.map(getSidebarStackKey).join("\u001f");
}
function SidebarColumn({ stackIds, editContext, onDragOver, onDrop, }) {
    const [columnDropSide, setColumnDropSide] = React.useState(null);
    const containerRef = React.useRef(null);
    const targetSidebarId = stackIds[0];
    const clearColumnDropSide = React.useCallback(() => {
        setColumnDropSide(null);
    }, []);
    const handleColumnDragOver = React.useCallback((e) => {
        onDragOver(e);
        if (!hasSidebarDragData(e) || !targetSidebarId) {
            setColumnDropSide(null);
            return;
        }
        const rect = e.currentTarget.getBoundingClientRect();
        const ratio = rect.width > 0 ? (e.clientX - rect.left) / rect.width : 0.5;
        if (ratio < 0.22) {
            setColumnDropSide("before");
        }
        else if (ratio > 0.78) {
            setColumnDropSide("after");
        }
        else {
            setColumnDropSide(null);
        }
    }, [onDragOver, targetSidebarId]);
    const handleColumnDragLeave = React.useCallback((e) => {
        const relatedTarget = e.relatedTarget;
        const container = containerRef.current;
        const isStillInside = container && relatedTarget && container.contains(relatedTarget);
        if (!isStillInside) {
            setColumnDropSide(null);
        }
    }, []);
    const handleColumnSideDrop = React.useCallback((e, position) => {
        e.preventDefault();
        e.stopPropagation();
        const sourceSidebarId = e.dataTransfer.getData("text/alpaca-sidebar") ||
            e.dataTransfer.getData("text/alpaca-sidebar-icon");
        setColumnDropSide(null);
        if (!sourceSidebarId ||
            !targetSidebarId ||
            sourceSidebarId === targetSidebarId) {
            return;
        }
        editContext.moveSidebarToColumn(sourceSidebarId, targetSidebarId, position);
    }, [editContext, targetSidebarId]);
    if (!targetSidebarId) {
        return null;
    }
    return (_jsxs("div", { ref: containerRef, className: "relative h-full", onDragOver: handleColumnDragOver, onDragLeave: handleColumnDragLeave, onDrop: clearColumnDropSide, children: [_jsx(SidebarStack, { sidebarIds: stackIds, editContext: editContext, onDragOver: onDragOver, suppressStackDropZones: columnDropSide !== null, onDrop: (e, hoveredSidebarId) => {
                    clearColumnDropSide();
                    onDrop(e, hoveredSidebarId);
                } }), columnDropSide && (_jsx("div", { className: cn("absolute top-0 bottom-0 z-20 flex w-14 items-center justify-center", columnDropSide === "before" ? "left-0" : "right-0"), onDragOver: handleColumnDragOver, onDrop: (e) => handleColumnSideDrop(e, columnDropSide), children: _jsxs("div", { className: "bg-highlight-100/15 border-highlight-100 pointer-events-none flex h-[calc(100%-16px)] w-[calc(100%-8px)] flex-col items-center justify-center gap-2 border-2 border-dashed px-2 text-center", children: [columnDropSide === "before" ? (_jsx(ArrowLeftToLine, { className: "text-highlight-100 size-5" })) : (_jsx(ArrowRightToLine, { className: "text-highlight-100 size-5" })), _jsxs("span", { className: "text-highlight-100 text-[11px] leading-tight font-medium", children: ["Drop to place ", columnDropSide === "before" ? "left" : "right"] })] }) }))] }));
}
export default function MainLayout(props) {
    const editContext = useEditContext();
    if (!editContext)
        return null;
    if (editContext.isMobile) {
        return _jsx(MobileLayout, { ...props, workspace: props.workspace });
    }
    return _jsx(DesktopMainLayout, { ...props, editContext: editContext });
}
function DesktopMainLayout({ editContext, ...props }) {
    const panels = [];
    const workspace = props.workspace;
    const showMenuBar = !workspace.hideToolbar;
    const contentTreeResolvedSidebar = editContext.getResolvedSidebar(CONTENT_TREE_SIDEBAR_ID);
    const contentTreePanelOpen = workspace.supportsSidebars &&
        contentTreeResolvedSidebar?.position === "left" &&
        editContext.openSidebars.includes(CONTENT_TREE_SIDEBAR_ID);
    const contentTreePanelOpenRef = React.useRef(contentTreePanelOpen);
    contentTreePanelOpenRef.current = contentTreePanelOpen;
    const contentTreePanelWasOpenRef = React.useRef(contentTreePanelOpen);
    const [renderContentTreePanel, setRenderContentTreePanel] = React.useState(contentTreePanelOpen);
    const [contentTreePanelOpening, setContentTreePanelOpening] = React.useState(false);
    // Get all left sidebar stacks that should be rendered as panels
    // Note: pinnedSidebars only controls toolbar icon visibility, not panel rendering.
    // Stacking is defined by editContext.sidebarStacks; any open sidebars missing from stacks
    // are normalized in the EditorShell and appear as single-item stacks.
    const leftSidebarStacks = useMemo(() => {
        if (!workspace.supportsSidebars) {
            return [];
        }
        const stacks = editContext.sidebarStacks ?? editContext.openSidebars.map((id) => [id]);
        // Filter each stack to left-position sidebars only, and drop empty stacks.
        return stacks
            .map((stack) => stack.filter((id) => {
            if (id === CONTENT_TREE_SIDEBAR_ID)
                return false;
            const resolved = editContext.getResolvedSidebar(id);
            return resolved !== undefined && resolved.position === "left";
        }))
            .filter((stack) => stack.length > 0);
    }, [
        workspace.supportsSidebars,
        editContext,
    ]);
    const [renderedLeftSidebarStacks, setRenderedLeftSidebarStacks] = React.useState(leftSidebarStacks);
    const [openingLeftSidebarStackKeys, setOpeningLeftSidebarStackKeys] = React.useState(() => new Set());
    const renderedLeftSidebarStacksRef = React.useRef(renderedLeftSidebarStacks);
    const leftSidebarStackKeySignature = useMemo(() => getSidebarStackKeySignature(leftSidebarStacks), [leftSidebarStacks]);
    React.useEffect(() => {
        const wasOpen = contentTreePanelWasOpenRef.current;
        contentTreePanelWasOpenRef.current = contentTreePanelOpen;
        if (contentTreePanelOpen) {
            setRenderContentTreePanel(true);
            if (wasOpen) {
                setContentTreePanelOpening(false);
                return;
            }
            setContentTreePanelOpening(true);
            const frame = window.requestAnimationFrame(() => {
                setContentTreePanelOpening(false);
            });
            return () => {
                window.cancelAnimationFrame(frame);
            };
        }
        setContentTreePanelOpening(false);
        if (!wasOpen) {
            setRenderContentTreePanel(false);
            return;
        }
        const timeout = window.setTimeout(() => {
            setRenderContentTreePanel(false);
        }, CONTENT_TREE_PANEL_COLLAPSE_SAFETY_MS);
        return () => {
            window.clearTimeout(timeout);
        };
    }, [contentTreePanelOpen]);
    React.useEffect(() => {
        const openStackKeys = new Set(leftSidebarStacks.map(getSidebarStackKey));
        const previousKeys = new Set(renderedLeftSidebarStacksRef.current.map(getSidebarStackKey));
        const openingStackKeys = new Set(Array.from(openStackKeys).filter((key) => !previousKeys.has(key)));
        const nextByKey = new Map();
        leftSidebarStacks.forEach((stack) => {
            nextByKey.set(getSidebarStackKey(stack), stack);
        });
        renderedLeftSidebarStacksRef.current.forEach((stack) => {
            const key = getSidebarStackKey(stack);
            if (!nextByKey.has(key)) {
                nextByKey.set(key, stack);
            }
        });
        const nextRenderedStacks = Array.from(nextByKey.values());
        renderedLeftSidebarStacksRef.current = nextRenderedStacks;
        setRenderedLeftSidebarStacks(nextRenderedStacks);
        if (openingStackKeys.size > 0) {
            setOpeningLeftSidebarStackKeys((prev) => {
                const next = new Set(prev);
                openingStackKeys.forEach((key) => next.add(key));
                return next;
            });
        }
        window.requestAnimationFrame(() => {
            if (openingStackKeys.size === 0)
                return;
            setOpeningLeftSidebarStackKeys((prev) => {
                const next = new Set(prev);
                openingStackKeys.forEach((key) => next.delete(key));
                return next;
            });
        });
        // Primary unmount of closed stacks is event-driven (handlePanelTransitionEnd).
        // This timeout is only a guardrail in case a transitionend never arrives.
        const hasClosedStacks = renderedLeftSidebarStacksRef.current.some((stack) => !openStackKeys.has(getSidebarStackKey(stack)));
        if (!hasClosedStacks) {
            return;
        }
        const timeout = window.setTimeout(() => {
            setRenderedLeftSidebarStacks((prev) => {
                const filtered = prev.filter((stack) => openStackKeys.has(getSidebarStackKey(stack)));
                renderedLeftSidebarStacksRef.current = filtered;
                return filtered;
            });
        }, SIDEBAR_COLLAPSE_SAFETY_MS);
        return () => {
            window.clearTimeout(timeout);
        };
    }, [leftSidebarStackKeySignature, leftSidebarStacks]);
    const openLeftSidebarStackKeys = useMemo(() => new Set(leftSidebarStacks.map(getSidebarStackKey)), [leftSidebarStacks]);
    const openLeftSidebarStackKeysRef = React.useRef(openLeftSidebarStackKeys);
    openLeftSidebarStackKeysRef.current = openLeftSidebarStackKeys;
    // Map each splitter panel name to the settle surface key(s) it represents so
    // the transitionend handler can notify the registry without re-parsing names.
    const panelSurfaceKeysRef = React.useRef(new Map());
    const handlePanelTransitionEnd = useCallback((panelName) => {
        panelSurfaceKeysRef.current
            .get(panelName)
            ?.forEach((key) => editContext.notifySurfaceSettled?.(key));
        // Event-driven unmount: once a closed sidebar stack finishes collapsing,
        // drop it from the rendered set (replaces the old fixed-delay removal).
        if (panelName.startsWith("sidebar")) {
            setRenderedLeftSidebarStacks((prev) => {
                const next = prev.filter((stack) => {
                    if (getSidebarStackPanelName(stack) !== panelName)
                        return true;
                    return openLeftSidebarStackKeysRef.current.has(getSidebarStackKey(stack));
                });
                if (next.length === prev.length)
                    return prev;
                renderedLeftSidebarStacksRef.current = next;
                return next;
            });
        }
        if (panelName === CONTENT_TREE_PANEL_NAME &&
            !contentTreePanelOpenRef.current) {
            setRenderContentTreePanel(false);
        }
    }, [editContext]);
    // Drag and drop handlers for reordering pinned sidebars
    const handleDragOver = useCallback((e) => {
        e.preventDefault();
        e.dataTransfer.dropEffect = "move";
    }, []);
    const handleDrop = useCallback((e, targetSidebarId) => {
        e.preventDefault();
        const sourceSidebarId = e.dataTransfer.getData("text/alpaca-sidebar") ||
            e.dataTransfer.getData("text/alpaca-sidebar-icon");
        if (!sourceSidebarId || sourceSidebarId === targetSidebarId) {
            return;
        }
        // Check if source is in open sidebars
        const currentOpen = editContext.openSidebars;
        if (!currentOpen.includes(sourceSidebarId)) {
            return;
        }
        // Check if both source and target are pinned - if so, reorder pinned sidebars
        const currentPinned = editContext.pinnedSidebars;
        const sourceIsPinned = currentPinned.includes(sourceSidebarId);
        const targetIsPinned = currentPinned.includes(targetSidebarId);
        if (sourceIsPinned && targetIsPinned) {
            // Reorder pinned sidebars (toolbar icon order)
            const sourceIndex = currentPinned.indexOf(sourceSidebarId);
            const targetIndex = currentPinned.indexOf(targetSidebarId);
            let effectiveBefore;
            if (sourceIndex < targetIndex) {
                effectiveBefore = false;
            }
            else {
                effectiveBefore = true;
            }
            const newPinned = currentPinned.filter((n) => n !== sourceSidebarId);
            const newTargetIndex = newPinned.indexOf(targetSidebarId);
            const baseIndex = newTargetIndex >= 0 ? newTargetIndex : newPinned.length - 1;
            const insertIndex = effectiveBefore
                ? Math.max(0, baseIndex)
                : Math.max(0, baseIndex + 1);
            newPinned.splice(insertIndex, 0, sourceSidebarId);
            editContext.reorderPinnedSidebars(newPinned);
        }
        // Always reorder open sidebars (panel display order)
        const sourceIndex = currentOpen.indexOf(sourceSidebarId);
        const targetIndex = currentOpen.indexOf(targetSidebarId);
        let effectiveBefore;
        if (sourceIndex < targetIndex) {
            effectiveBefore = false;
        }
        else {
            effectiveBefore = true;
        }
        const newOpen = currentOpen.filter((n) => n !== sourceSidebarId);
        const newTargetIndex = newOpen.indexOf(targetSidebarId);
        const baseIndex = newTargetIndex >= 0 ? newTargetIndex : newOpen.length - 1;
        const insertIndex = effectiveBefore
            ? Math.max(0, baseIndex)
            : Math.max(0, baseIndex + 1);
        newOpen.splice(insertIndex, 0, sourceSidebarId);
        editContext.reorderOpenSidebars(newOpen);
    }, [editContext]);
    const panelSurfaceKeys = new Map();
    // Render each sidebar stack as its own splitter panel (one column per stack).
    renderedLeftSidebarStacks.forEach((stackIds) => {
        const firstId = stackIds[0];
        if (!firstId)
            return;
        const firstResolved = editContext.getResolvedSidebar(firstId);
        const stackKey = getSidebarStackKey(stackIds);
        const panelName = getSidebarStackPanelName(stackIds);
        panelSurfaceKeys.set(panelName, stackIds.map((id) => `sidebar:${id}`));
        panels.push({
            name: panelName,
            defaultSize: firstResolved?.defaultWidth ?? 350,
            collapsed: !openLeftSidebarStackKeys.has(stackKey) ||
                openingLeftSidebarStackKeys.has(stackKey),
            animatedCollapse: true,
            minSize: 220,
            content: (_jsx(SidebarColumn, { stackIds: stackIds, editContext: editContext, onDragOver: handleDragOver, onDrop: (e, targetSidebarId) => handleDrop(e, targetSidebarId) })),
        });
    });
    if (renderContentTreePanel) {
        panelSurfaceKeys.set(CONTENT_TREE_PANEL_NAME, [
            CONTENT_TREE_PANEL_SURFACE_KEY,
        ]);
        panels.push({
            name: CONTENT_TREE_PANEL_NAME,
            defaultSize: contentTreeResolvedSidebar?.defaultWidth ?? 400,
            collapsed: !contentTreePanelOpen || contentTreePanelOpening,
            animatedCollapse: true,
            preserveVisibilityOnCollapse: true,
            minSize: 280,
            content: _jsx(ContentTreePanel, { opening: contentTreePanelOpening }),
        });
    }
    panels.push({
        name: "center",
        defaultSize: "auto",
        content: props.centerPanelView,
    });
    if (props.rightSidebar) {
        panels.push({
            name: "rightSidebar",
            defaultSize: 250,
            content: props.rightSidebar,
            collapsible: false,
        });
    }
    if (props.farRightSidebar) {
        panelSurfaceKeys.set("farRightSidebar", [AGENTS_PANEL_SURFACE_KEY]);
        panels.push({
            name: "farRightSidebar",
            defaultSize: 600,
            content: props.farRightSidebar,
            collapsible: false,
            collapsed: props.farRightSidebarCollapsed,
            animatedCollapse: true,
            minSize: 320,
        });
    }
    if (props.helpTerminal) {
        panels.push({
            name: "helpTerminal",
            defaultSize: 500,
            content: props.helpTerminal,
            collapsible: false,
        });
    }
    panelSurfaceKeysRef.current = panelSurfaceKeys;
    let className = props.className;
    if (!editContext?.configuration.editor.embedded) {
        className = cn("absolute inset-0", props.className);
    }
    // Left sidebars exist only if workspace supports them AND there are available left sidebars
    const hasAvailableSidebars = useMemo(() => {
        if (!workspace.supportsSidebars)
            return false;
        const availableSidebars = editContext.availableSidebars ?? [];
        return availableSidebars.some((s) => s.position === "left" && !s.hidden);
    }, [workspace.supportsSidebars, editContext.availableSidebars]);
    const showWorkspaceRail = !workspace.hideWorkspaceRail;
    const showSidebarIcons = showWorkspaceRail && workspace.supportsSidebars && hasAvailableSidebars;
    return (_jsx("div", { className: cn("flex h-full w-full flex-col font-normal select-none", className), children: _jsxs("div", { className: "flex flex-1 overflow-hidden", children: [showWorkspaceRail && (_jsx(WorkspaceRail, { showSidebarIcons: showSidebarIcons })), _jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [workspace.menuBar !== undefined
                            ? workspace.menuBar
                            : showMenuBar && _jsx(GlobalMenuBar, {}), workspace?.toolbarFactory && (_jsx("div", { className: "w-full shrink-0", children: workspace.toolbarFactory(editContext) })), _jsx("div", { className: "bg-neutral-grey-5 flex-1 overflow-hidden", children: _jsx(Splitter, { splitterClassName: "bg-transparent -mr-1.5 md:w-[6px]", localStorageKey: "editor.panelSizes", expandLabel: _jsxs("div", { className: "flex items-center justify-center", children: [_jsx(Layers, { size: 14 }), _jsxs("div", { className: "mt-3", children: [props.rightSidebarTitle, " "] })] }), panels: panels, onPanelTransitionEnd: handlePanelTransitionEnd }) })] })] }) }));
}
//# sourceMappingURL=MainLayout.js.map