import { jsx as _jsx } from "react/jsx-runtime";
import { useEffect, useState } from "react";
import { useEditContext } from "../client/editContext";
import { useSlotContext } from "../views/editorSlotContext";
import { getVisibleInsertOptions } from "../insertMenuItems";
import { getAllPlaceholders } from "../componentTreeHelper";
import { PlaceholderDropZone } from "./PlaceholderDropZone";
import { measureComponentRect, measureElementRect, rectEquals, } from "./overlay/geometry";
import { useOverlayMeasurement } from "./overlay/useOverlayMeasurement";
export function PlaceholderDropZones({ iframe, size, pageViewContext, }) {
    const [placeholders, setPlaceholders] = useState([]);
    const editContext = useEditContext();
    const slotContext = useSlotContext();
    useEffect(() => {
        if (!pageViewContext?.page)
            return;
        setPlaceholders(getAllPlaceholders(pageViewContext.page));
    }, [pageViewContext?.page]);
    const zones = useOverlayMeasurement((metrics) => {
        if (!slotContext?.isActive ||
            !pageViewContext ||
            !iframe ||
            (!editContext?.dragObject &&
                !editContext?.selectedForInsertion &&
                !editContext?.insertMode)) {
            return [];
        }
        const showAllDueToInsertMode = !!editContext?.insertMode &&
            !editContext?.dragObject &&
            !editContext?.selectedForInsertion;
        const hasVisibleInsertOptions = (placeholder) => getVisibleInsertOptions(placeholder.insertOptions).length > 0;
        const matchingPlaceholders = placeholders
            .filter((x) => editContext?.showLayoutComponents === true ||
            !isInsideLayoutComponent(x.parentComponent))
            .filter((x) => {
            const visibleInsertOptions = getVisibleInsertOptions(x.insertOptions);
            return (x.editable &&
                hasVisibleInsertOptions(x) &&
                (showAllDueToInsertMode ||
                    x.parentComponent?.id === editContext.selectedForInsertion ||
                    visibleInsertOptions.find((y) => y.typeId === editContext.selectedForInsertion ||
                        y.typeId === editContext.dragObject?.typeId ||
                        y.typeId === editContext.dragObject?.templateId ||
                        y.compatibleTypeIds?.find((z) => z == editContext.dragObject?.typeId) !== undefined ||
                        y.typeId === editContext.dragObject?.templateId ||
                        y.compatibleTypeIds?.find((z) => z == editContext.dragObject?.templateId) !== undefined)));
        });
        const measuredZones = [];
        const scrollHeight = metrics.scrollHeight * metrics.visualScale;
        const scrollWidth = metrics.scrollWidth * metrics.visualScale;
        matchingPlaceholders.forEach((placeholder) => {
            const iframeBody = iframe?.contentWindow?.document?.body;
            if (!iframeBody)
                return;
            let placeholderElement = iframeBody.querySelector("[data-placeholder-start='" + placeholder.key + "']");
            let isUsingParentBounds = false;
            if (!placeholderElement && placeholder.components.length > 0) {
                const firstComponent = placeholder.components[0];
                placeholderElement =
                    iframeBody.querySelector("[data-component-start='" + firstComponent?.id + "']")?.nextElementSibling ||
                        firstComponent?.firstDOMElement ||
                        null;
            }
            if (!placeholderElement && placeholder.parentComponent) {
                placeholderElement =
                    iframeBody.querySelector("[data-component-start='" + placeholder.parentComponent.id + "']")?.nextElementSibling ||
                        placeholder.parentComponent.firstDOMElement ||
                        null;
                isUsingParentBounds = true;
            }
            if (!placeholderElement)
                return;
            let position;
            let anchor = "top";
            let index = 0;
            const description = placeholderElement.getAttribute("data-description");
            let referenceElement;
            let orientation = null;
            if (isUsingParentBounds) {
                const rect = measureElementRect(placeholderElement, metrics);
                if (!rect)
                    return;
                position = {
                    x: rect.x + rect.width / 2,
                    y: rect.y + rect.height / 2,
                };
                anchor = "top";
                referenceElement = placeholderElement;
                orientation = "vertical";
            }
            else {
                const prev = getPreviousElement(placeholderElement);
                const nextOrParent = getNextElement(placeholderElement) ||
                    placeholderElement.parentElement;
                if (!nextOrParent && !prev)
                    return;
                orientation = placeholderElement?.getAttribute("data-orientation");
                if (!orientation) {
                    orientation = detectOrientation(placeholderElement, placeholder.components);
                }
                const rect = measureElementRect((prev ?? nextOrParent), metrics);
                if (!rect)
                    return;
                position =
                    orientation === "horizontal"
                        ? {
                            x: prev ? rect.x + rect.width : rect.x,
                            y: rect.y + rect.height / 2,
                        }
                        : {
                            x: rect.x + rect.width / 2,
                            y: prev ? rect.y + rect.height : rect.y,
                        };
                if (prev && orientation === "horizontal")
                    anchor = "right";
                if (prev && orientation !== "horizontal")
                    anchor = "bottom";
                if (!prev && orientation === "horizontal")
                    anchor = "left";
                if (!prev && orientation !== "horizontal")
                    anchor = "top";
                referenceElement = prev ?? nextOrParent;
            }
            measuredZones.push({
                placeholder,
                position,
                index,
                element: referenceElement,
                anchor,
                description,
            });
            placeholder.components.forEach((component) => {
                const componentRect = measureComponentRect(iframe, component, metrics);
                if (!componentRect)
                    return;
                const position = getPositionFromRect(componentRect.rect, orientation);
                index++;
                measuredZones.push({
                    placeholder,
                    position,
                    index,
                    anchor: orientation === "horizontal" ? "right" : "bottom",
                    element: componentRect.elements[componentRect.elements.length - 1],
                });
            });
        });
        const zonesWithoutBeforeFirstLayout = measuredZones.filter((z) => {
            const components = z.placeholder.components;
            const firstLayoutIndex = components.findIndex((c) => !!c.layoutId);
            if (firstLayoutIndex >= 0 && z.index <= firstLayoutIndex) {
                return false;
            }
            return true;
        });
        const filteredZones = editContext?.showLayoutComponents === false
            ? zonesWithoutBeforeFirstLayout.filter((z) => {
                const components = z.placeholder.components;
                if (z.index >= 1 && z.index < components.length) {
                    const prev = components[z.index - 1];
                    const next = components[z.index];
                    if (prev?.layoutId && next?.layoutId)
                        return false;
                }
                return true;
            })
            : zonesWithoutBeforeFirstLayout;
        const usedPositions = new Map();
        const DROPZONE_SIZE = 32;
        const OVERLAP_THRESHOLD = DROPZONE_SIZE;
        return filteredZones.map((zone) => {
            let x = Math.min(scrollWidth - 20, Math.max(20, zone.position.x));
            let y = Math.min(scrollHeight - 20, Math.max(20, zone.position.y));
            const posKey = `${Math.round(x / OVERLAP_THRESHOLD)}_${Math.round(y / OVERLAP_THRESHOLD)}`;
            const overlapCount = usedPositions.get(posKey) || 0;
            if (overlapCount > 0) {
                x = x + overlapCount * (DROPZONE_SIZE + 8);
                if (x > scrollWidth - 20) {
                    x = 20 + ((overlapCount - 1) % 5) * (DROPZONE_SIZE + 8);
                    y = y + Math.floor((overlapCount - 1) / 5) * (DROPZONE_SIZE + 8);
                }
            }
            usedPositions.set(posKey, overlapCount + 1);
            return {
                ...zone,
                position: { x, y },
            };
        });
    }, [
        slotContext?.isActive,
        pageViewContext,
        iframe,
        editContext?.dragObject,
        editContext?.selectedForInsertion,
        editContext?.insertMode,
        editContext?.showLayoutComponents,
        placeholders,
    ], {
        initialValue: [],
        equals: placeholderZonesEqual,
        interests: ["viewport", "layout", "adornment-data"],
    });
    if (!zones.length || !editContext)
        return null;
    return zones.map((zone, index) => {
        const components = zone.placeholder.components;
        const prevComponent = zone.index >= 1 ? components[zone.index - 1] : null;
        const nextComponent = zone.index < components.length ? components[zone.index] : null;
        const isAdjacentToLayout = !!prevComponent?.layoutId || !!nextComponent?.layoutId;
        const isInsideLayout = isInsideLayoutComponent(zone.placeholder.parentComponent);
        const isLayoutZone = isInsideLayout || isAdjacentToLayout;
        const adjustedIndex = zone.placeholder.components
            .slice(0, zone.index)
            .filter((c) => !c.layoutId).length;
        return (_jsx(PlaceholderDropZone, { placeholder: zone.placeholder, spotPosition: {
                x: zone.position.x,
                y: zone.position.y,
            }, index: adjustedIndex, size: size, spotPositionElement: zone.element, spotPositionAnchor: zone.anchor, parentName: zone.placeholder.parentComponent?.name, description: zone.description || undefined, isLayoutZone: isLayoutZone }, index));
    });
}
function placeholderZonesEqual(previous, next) {
    if (previous.length !== next.length)
        return false;
    for (let i = 0; i < previous.length; i++) {
        const previousZone = previous[i];
        const nextZone = next[i];
        if (previousZone.placeholder.key !== nextZone.placeholder.key ||
            previousZone.index !== nextZone.index ||
            previousZone.element !== nextZone.element ||
            previousZone.anchor !== nextZone.anchor ||
            previousZone.description !== nextZone.description ||
            !rectEquals({ ...previousZone.position, width: 0, height: 0 }, { ...nextZone.position, width: 0, height: 0 })) {
            return false;
        }
    }
    return true;
}
function getPreviousElement(element) {
    let prev = element.previousElementSibling;
    while (prev && prev.tagName === "SCRIPT") {
        prev = prev.previousElementSibling;
    }
    return prev;
}
function getNextElement(element) {
    let next = element.nextElementSibling;
    while (next && next.tagName === "SCRIPT") {
        next = next.nextElementSibling;
    }
    return next;
}
function getPositionFromRect(rect, orientation) {
    const position = orientation === "horizontal"
        ? {
            x: rect.x + rect.width,
            y: rect.y + rect.height / 2,
        }
        : {
            x: rect.x + rect.width / 2,
            y: rect.y + rect.height,
        };
    return position;
}
function detectOrientation(placeholderElement, components) {
    // Check parent element for flex/grid direction
    const parentElement = placeholderElement.parentElement;
    if (parentElement) {
        const parentStyle = window.getComputedStyle(parentElement);
        const display = parentStyle.getPropertyValue("display");
        // Check for flex direction
        if (display === "flex" || display === "inline-flex") {
            const flexDirection = parentStyle.getPropertyValue("flex-direction");
            if (flexDirection === "row" || flexDirection === "row-reverse") {
                return "horizontal";
            }
            if (flexDirection === "column" || flexDirection === "column-reverse") {
                return "vertical";
            }
        }
        // Check for grid layout
        if (display === "grid" || display === "inline-grid") {
            const gridAutoFlow = parentStyle.getPropertyValue("grid-auto-flow");
            if (gridAutoFlow.includes("column")) {
                return "horizontal";
            }
            if (gridAutoFlow.includes("row")) {
                return "vertical";
            }
        }
    }
    // Analyze sibling positions if available
    if (components.length > 1) {
        const prevRect = components[0]?.firstDOMElement?.getBoundingClientRect();
        const nextRect = components[1]?.firstDOMElement?.getBoundingClientRect();
        if (!prevRect || !nextRect)
            return "horizontal";
        // Compare the position differences
        const horizontalDiff = Math.abs(nextRect.x - prevRect.x);
        const verticalDiff = Math.abs(nextRect.y - prevRect.y);
        // If horizontal difference is greater, it's likely a horizontal layout
        return horizontalDiff > verticalDiff ? "horizontal" : "vertical";
    }
    // Default to vertical if we can't determine
    return "vertical";
}
function isInsideLayoutComponent(component) {
    let current = component;
    while (current) {
        if (current.layoutId)
            return true;
        current = current.parentPlaceholder?.parentComponent;
    }
    return false;
}
//# sourceMappingURL=PlaceholderDropZones.js.map