import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useCallback, useEffect, useState } from "react";
import { useEditContext } from "../client/editContext";
import { FieldActionsIndicators } from "./FieldActionIndicators";
import { PlaceholderDropZones } from "./PlaceholderDropZones";
import { DragInsertionOverlay } from "./DragInsertionOverlay";
import { PictureEditorOverlay } from "./PictureEditorOverlay";
import { EmptyImageFieldIndicators } from "./EmptyImageFieldIndicators";
import { LockedFieldIndicator } from "./LockedFieldIndicator";
import { FrameMenus } from "./FrameMenus";
import { FieldEditedIndicators } from "./FieldEditedIndicators";
import { CommentHighlightings } from "./CommentHighlightings";
import { SuggestionHighlightings } from "./SuggestionHighlightings";
import { VersionDiffHighlightings } from "./VersionDiffHighlightings";
import { useSlotContext } from "../views/editorSlotContext";
import { useOverlayMeasurement } from "./overlay/useOverlayMeasurement";
import { BridgeInlineFormatOverlay } from "./BridgeInlineFormatOverlay";
import { getAllPlaceholders, getComponentById } from "../componentTreeHelper";
import { measureBridgeComponentRect, measureElementRect, rectEquals, } from "./overlay/geometry";
import { ComponentOperationBubble } from "./ComponentOperationBubble";
import { layoutAwareIndex, measureBridgePlaceholderZones, } from "./overlay/placeholderZones";
// Keeps the "+" dots and the drag insertion line in sync: DragInsertionOverlay
// publishes the gap it is currently targeting, and PlaceholderDropZones lights
// up the matching dot. The state lives here (not in PageEditorChrome) so a gap
// change only re-renders these two siblings, not the whole chrome.
function PlaceholderInsertionLayer({ pageViewContext, openInsertMenuKey, onInsertMenuOpenChange, }) {
    const [activeTargetKey, setActiveTargetKey] = useState(null);
    return (_jsxs(_Fragment, { children: [_jsx(PlaceholderDropZones, { size: "large", pageViewContext: pageViewContext, activeTargetKey: activeTargetKey, openInsertMenuKey: openInsertMenuKey, onInsertMenuOpenChange: onInsertMenuOpenChange }), _jsx(DragInsertionOverlay, { pageViewContext: pageViewContext, onActiveTargetChange: setActiveTargetKey })] }));
}
export function PageEditorChrome(props) {
    const editContext = useEditContext();
    const hasBridgeChromeData = props.pageViewContext.bridgeReady ||
        !!props.pageViewContext.bridgeGeometry ||
        !!props.pageViewContext.bridgeStructure;
    if (!editContext || !hasBridgeChromeData) {
        return null;
    }
    return _jsx(PageEditorChromeContent, { ...props, editContext: editContext });
}
function PageEditorChromeContent({ compareView, pageViewContext, editContext, onBridgeRichTextCommand, }) {
    const slotContext = useSlotContext();
    const [openInsertMenuKey, setOpenInsertMenuKey] = useState(null);
    const handleInsertMenuOpenChange = useCallback((key, open) => {
        setOpenInsertMenuKey((currentKey) => {
            if (open)
                return key;
            return currentKey === key ? null : currentKey;
        });
    }, []);
    useEffect(() => {
        if (editContext.mode !== "edit" || editContext.dragObject) {
            setOpenInsertMenuKey(null);
        }
    }, [editContext.dragObject, editContext.mode]);
    return (_jsxs(_Fragment, { children: [_jsx(FrameMenus, { pageViewContext: pageViewContext, compareView: compareView, openInsertMenuKey: openInsertMenuKey, onInsertMenuOpenChange: handleInsertMenuOpenChange }), _jsx(BridgeInlineFormatOverlay, { onCommand: onBridgeRichTextCommand, pageViewContext: pageViewContext }), editContext.mode === "edit" && (_jsxs(_Fragment, { children: [_jsx(PlaceholderInsertionLayer, { pageViewContext: pageViewContext, openInsertMenuKey: openInsertMenuKey, onInsertMenuOpenChange: handleInsertMenuOpenChange }), slotContext?.isActive && (_jsxs(_Fragment, { children: [_jsx(InsertingIndicator, { pageViewContext: pageViewContext }), _jsx(RemovingIndicators, { pageViewContext: pageViewContext })] }))] })), editContext.showComments && (_jsx(CommentHighlightings, { pageViewContext: pageViewContext })), editContext.showSuggestedEdits && (_jsx(SuggestionHighlightings, { pageViewContext: pageViewContext })), _jsx(LockedFieldIndicator, { pageViewContext: pageViewContext }), editContext.mode === "edit" && (_jsxs(_Fragment, { children: [_jsx(EmptyImageFieldIndicators, { pageViewContext: pageViewContext }), _jsx(PictureEditorOverlay, { pageViewContext: pageViewContext })] })), editContext.showVersionDiffHighlighting && (_jsx(VersionDiffHighlightings, { pageViewContext: pageViewContext })), _jsx(FieldActionsIndicators, { pageViewContext: pageViewContext }), _jsx(FieldEditedIndicators, { pageViewContext: pageViewContext })] }));
}
function InsertingIndicator({ pageViewContext, }) {
    const editContext = useEditContext();
    const inserting = editContext?.inserting;
    const position = useOverlayMeasurement((metrics) => {
        if (!inserting)
            return null;
        if (inserting.position) {
            return clampInsertionPosition(inserting.position, metrics);
        }
        if (inserting.positionElement) {
            const rect = measureElementRect(inserting.positionElement, metrics);
            if (!rect)
                return null;
            let x = rect.x + rect.width / 2;
            let y = rect.y;
            if (inserting.positionAnchor === "bottom") {
                y = rect.y + rect.height;
            }
            else if (inserting.positionAnchor === "left") {
                x = rect.x;
                y = rect.y + rect.height / 2;
            }
            else if (inserting.positionAnchor === "right") {
                x = rect.x + rect.width;
                y = rect.y + rect.height / 2;
            }
            return clampInsertionPosition({ x, y }, metrics);
        }
        if (!inserting.placeholderKey || typeof inserting.index !== "number") {
            return null;
        }
        const placeholder = pageViewContext.page
            ? getAllPlaceholders(pageViewContext.page).find((candidate) => candidate.key === inserting.placeholderKey)
            : undefined;
        if (!placeholder || !pageViewContext.bridgeGeometry)
            return null;
        const zones = measureBridgePlaceholderZones(placeholder, pageViewContext.bridgeGeometry, metrics);
        const zone = zones.find((candidate) => candidate.index === inserting.index) ??
            zones.find((candidate) => layoutAwareIndex(placeholder.components, candidate.index) ===
                inserting.index);
        return zone ? clampInsertionPosition(zone.position, metrics) : null;
    }, [inserting, pageViewContext.bridgeGeometry, pageViewContext.page], {
        initialValue: null,
        equals: rectEquals,
        interests: ["viewport", "layout", "adornment-data"],
    });
    if (!position)
        return null;
    return (_jsx(ComponentOperationBubble, { color: inserting?.color ?? "default", testId: "component-inserting-indicator", style: { top: position.y - 16, left: position.x - 16, zIndex: 1000 } }));
}
function RemovingIndicators({ pageViewContext, }) {
    const editContext = useEditContext();
    const removingComponentIds = editContext?.removingComponentIds ?? [];
    const positions = useOverlayMeasurement((metrics) => {
        if (removingComponentIds.length === 0 ||
            !pageViewContext.page ||
            !pageViewContext.bridgeGeometry) {
            return [];
        }
        return removingComponentIds
            .map((componentId) => {
            const component = getComponentById(componentId, pageViewContext.page);
            if (!component)
                return null;
            const measurement = measureBridgeComponentRect(pageViewContext.bridgeGeometry, component, metrics);
            if (!measurement?.rect)
                return null;
            return {
                componentId,
                position: {
                    x: measurement.rect.x + measurement.rect.width / 2,
                    y: measurement.rect.y + measurement.rect.height / 2,
                },
            };
        })
            .filter((position) => position !== null);
    }, [
        removingComponentIds,
        pageViewContext.bridgeGeometry,
        pageViewContext.page,
    ], {
        initialValue: [],
        equals: componentOperationBubblePositionsEqual,
        interests: ["viewport", "layout", "adornment-data"],
    });
    if (positions.length === 0)
        return null;
    return (_jsx(_Fragment, { children: positions.map((position) => (_jsx(ComponentOperationBubble, { testId: "component-removing-indicator", style: {
                top: position.position.y - 16,
                left: position.position.x - 16,
                zIndex: 1000,
            } }, position.componentId))) }));
}
function componentOperationBubblePositionsEqual(previous, next) {
    if (previous.length !== next.length)
        return false;
    for (let i = 0; i < previous.length; i++) {
        const previousPosition = previous[i];
        const nextPosition = next[i];
        if (previousPosition.componentId !== nextPosition.componentId)
            return false;
        if (!rectEquals({ ...previousPosition.position, width: 0, height: 0 }, { ...nextPosition.position, width: 0, height: 0 })) {
            return false;
        }
    }
    return true;
}
function clampInsertionPosition(position, metrics) {
    const maxX = Math.max(20, metrics.scrollWidth * metrics.visualScale - 20);
    const maxY = Math.max(20, metrics.scrollHeight * metrics.visualScale - 20);
    return {
        x: Math.min(maxX, Math.max(20, position.x)),
        y: Math.min(maxY, Math.max(20, position.y)),
        width: 0,
        height: 0,
    };
}
//# sourceMappingURL=PageEditorChrome.js.map