import { extractItemIdFromItemUri } from "../utils";
const excludedComponentTypes = new Set(["StickyNote"]);
export function buildPageModelSkeleton(iframeDocument, editContextRef, pageViewContextRef) {
    const pageItemDescriptor = pageViewContextRef.current?.pageItemDescriptor;
    if (!iframeDocument || !editContextRef.current || !pageViewContextRef.current)
        return;
    // Function to ensure IDs are in UUID format
    const ensureUUIDFormat = (id) => {
        // If it's already in UUID format (with or without curly braces), return it
        if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)) {
            return id;
        }
        // If it's in curly braces format, remove them
        if (/^\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}$/i.test(id)) {
            return id.replace(/[{}]/g, "");
        }
        // If it's a GUID without hyphens, add them
        if (/^[0-9a-f]{32}$/i.test(id)) {
            return `${id.substring(0, 8)}-${id.substring(8, 12)}-${id.substring(12, 16)}-${id.substring(16, 20)}-${id.substring(20, 32)}`;
        }
        // If it's a shorter ID, pad it to make it a valid UUID
        if (id.length < 32) {
            const paddedId = id.padEnd(32, "0");
            return `${paddedId.substring(0, 8)}-${paddedId.substring(8, 12)}-${paddedId.substring(12, 16)}-${paddedId.substring(16, 20)}-${paddedId.substring(20, 32)}`;
        }
        // For any other format, return as is
        return id;
    };
    if (!pageItemDescriptor)
        return;
    const pageItem = {
        ...pageItemDescriptor,
        renderedFieldIds: [],
    };
    const treeWalker = iframeDocument.createTreeWalker(iframeDocument.documentElement, // Root node to start traversal
    NodeFilter.SHOW_ELEMENT, // Only show element nodes
    null);
    const root = {
        placeholders: [],
        id: "page",
        type: "Page",
        typeId: "",
        name: "Page",
        items: [pageItem],
        datasourceItem: pageItem,
        renderedDictionaryKeys: [],
        editorFields: {},
    };
    let currentComponent = root;
    let currentPlaceholder;
    const resolveComponentFirstElement = (componentStartId, element) => {
        if (element.tagName !== "SCRIPT") {
            return element;
        }
        const previousElement = element.previousElementSibling;
        const nextElement = element.nextElementSibling;
        const nextIsMatchingEndMarker = nextElement?.tagName === "SCRIPT" &&
            nextElement.getAttribute("data-component-end") === componentStartId;
        // Some Sitecore markers are emitted after the rendered component body, with
        // the matching end marker immediately after the start marker.
        if (nextIsMatchingEndMarker && previousElement) {
            return previousElement;
        }
        return nextElement ?? previousElement ?? element;
    };
    const moveContainedComponentsToPlaceholder = (sourcePlaceholder, targetPlaceholder, containerElement, currentComponentId) => {
        if (!sourcePlaceholder || sourcePlaceholder === targetPlaceholder) {
            return;
        }
        const containedComponents = sourcePlaceholder.components.filter((component) => {
            if (component.id === currentComponentId) {
                return false;
            }
            return (!!component.firstDOMElement &&
                containerElement.contains(component.firstDOMElement));
        });
        if (containedComponents.length === 0) {
            return;
        }
        sourcePlaceholder.components = sourcePlaceholder.components.filter((component) => !containedComponents.includes(component));
        for (const component of containedComponents) {
            component.parentPlaceholder = targetPlaceholder;
            targetPlaceholder.components.push(component);
        }
    };
    const ensurePlaceholder = (parentComponent, placeholderKey, element) => {
        let placeholder = parentComponent.placeholders.find((x) => x.key === placeholderKey);
        if (!placeholder) {
            placeholder = {
                key: placeholderKey,
                name: placeholderKey.indexOf(parentComponent.id + "_") === 0
                    ? placeholderKey.substring(parentComponent.id.length + 1)
                    : placeholderKey,
                description: element.getAttribute("data-description") || "",
                components: [],
                parentComponent,
                editable: element.getAttribute("data-editable") !== "false",
            };
            parentComponent.placeholders.push(placeholder);
        }
        return placeholder;
    };
    const normalizeExplicitPlaceholderKey = (placeholderKey) => {
        if (!placeholderKey) {
            return placeholderKey;
        }
        const parts = placeholderKey.split("/").filter(Boolean);
        return parts.at(-1) ?? placeholderKey;
    };
    const resolveComponentLastElement = (componentEndId, element, component) => {
        const previousElement = element.previousElementSibling;
        if (previousElement?.tagName === "SCRIPT" &&
            previousElement.getAttribute("data-component-start") === componentEndId &&
            component.firstDOMElement) {
            return component.firstDOMElement;
        }
        return previousElement ?? element;
    };
    const startComponent = (componentStartId, element, dataSourceItemId) => {
        if (!currentPlaceholder) {
            if (!currentComponent) {
                console.error("Component start without parent component:", componentStartId);
                return;
            }
            const explicitPlaceholderKey = element.getAttribute("data-placeholderkey");
            if (explicitPlaceholderKey) {
                currentPlaceholder = ensurePlaceholder(currentComponent, normalizeExplicitPlaceholderKey(explicitPlaceholderKey), element);
            }
            else {
                currentPlaceholder = currentComponent.placeholders.find((x) => x.key === "implicit_" + currentComponent?.datasourceItem?.id);
                if (!currentPlaceholder) {
                    currentPlaceholder = {
                        key: "implicit_" + currentComponent?.datasourceItem?.id,
                        name: "Implicit placeholder: " + currentComponent?.datasourceItem?.id,
                        description: "",
                        components: [],
                        parentComponent: currentComponent,
                        editable: element.getAttribute("data-editable") !== "false",
                    };
                    if (!currentComponent) {
                        console.error("Component start without placeholder or parent component");
                    }
                    else {
                        currentComponent.placeholders.push(currentPlaceholder);
                    }
                }
            }
        }
        if (currentPlaceholder) {
            const language = element.getAttribute("data-language") || pageItem.language;
            const version = element.hasAttribute("data-version")
                ? parseInt(element.getAttribute("data-version"))
                : pageItem.version;
            const itemId = dataSourceItemId || element.getAttribute("data-itemid");
            const datasourceItem = itemId
                ? {
                    id: itemId,
                    language,
                    version,
                    renderedFieldIds: [],
                }
                : undefined;
            const layoutId = element.getAttribute("data-layoutid");
            const parametersTemplateId = element.getAttribute("data-parameters-template-id");
            const parameters = element.getAttribute("data-parameters");
            const isSharedDatasource = element.getAttribute("data-shared-datasource") === "true";
            const hasPersonalization = element.getAttribute("data-has-personalization") === "true";
            const componentType = element.getAttribute("data-type") || "";
            if (excludedComponentTypes.has(componentType)) {
                element.setAttribute("data-skip-component", "true");
                return undefined;
            }
            // Store the parent component before we potentially change currentComponent
            const parentComponent = currentPlaceholder.parentComponent;
            const parentPlaceholder = currentPlaceholder;
            const componentFirstElement = resolveComponentFirstElement(componentStartId, element);
            currentComponent = currentPlaceholder.components.find((x) => x.id === componentStartId);
            // Check if we should skip this component because it has the same datasource as the parent
            if (datasourceItem &&
                datasourceItem.id === parentComponent?.datasourceItem?.id) {
                element.setAttribute("data-skip-component", "true");
                return undefined;
            }
            if (!currentComponent) {
                currentComponent = {
                    id: componentStartId,
                    name: "",
                    type: componentType,
                    typeId: element.getAttribute("data-typeid") || "",
                    parametersTemplateId: parametersTemplateId || undefined,
                    parameters: parameters || undefined,
                    items: datasourceItem ? [datasourceItem] : [],
                    placeholders: [],
                    parentPlaceholder: currentPlaceholder,
                    renderedDictionaryKeys: [],
                    datasourceItem,
                    layoutId: layoutId || undefined,
                    isShared: isSharedDatasource,
                    hasPersonalization,
                    isSharedLayout: element.getAttribute("data-shared-rendering") === "true",
                    editorFields: {},
                    firstDOMElement: componentFirstElement,
                    editable: element.getAttribute("data-editable") !== "false",
                };
                if (currentComponent) {
                    currentPlaceholder.components.push(currentComponent);
                }
            }
            else {
                currentComponent.isShared = isSharedDatasource;
                currentComponent.hasPersonalization =
                    hasPersonalization || currentComponent.hasPersonalization;
                currentComponent.layoutId = layoutId || currentComponent.layoutId;
                currentComponent.parametersTemplateId =
                    parametersTemplateId || currentComponent.parametersTemplateId;
                currentComponent.parameters = parameters || currentComponent.parameters;
                currentComponent.isSharedLayout =
                    element.getAttribute("data-shared-rendering") === "true" ||
                        currentComponent.isSharedLayout;
            }
            // Check if the new component should have an implicit placeholder
            const hasImplicitPlaceholder = element.getAttribute("data-has-implicit-placeholder") === "true";
            if (hasImplicitPlaceholder && currentComponent) {
                // Add an implicit placeholder to the newly created component
                const implicitPlaceholder = {
                    key: "implicit_" + currentComponent.datasourceItem?.id,
                    name: "Implicit placeholder: " + currentComponent.datasourceItem?.id,
                    description: "",
                    components: [],
                    parentComponent: currentComponent,
                    editable: element.getAttribute("data-editable") !== "false",
                };
                currentComponent.placeholders.push(implicitPlaceholder);
                moveContainedComponentsToPlaceholder(parentPlaceholder, implicitPlaceholder, componentFirstElement, currentComponent.id);
                currentPlaceholder = implicitPlaceholder;
            }
            else {
                currentPlaceholder = undefined;
            }
            return currentComponent;
        }
    };
    const endComponent = (componentEndId) => {
        if (!currentComponent || currentComponent.id !== componentEndId) {
            console.error("Component end does not match start", currentComponent, componentEndId);
            // Placeholder closed implicitly
            if (currentPlaceholder?.parentComponent.id === componentEndId) {
                currentComponent = currentPlaceholder.parentComponent;
                currentPlaceholder = undefined;
            }
        }
        currentPlaceholder = currentComponent?.parentPlaceholder;
        if (currentPlaceholder?.key.startsWith("implicit_")) {
            currentComponent = currentPlaceholder.parentComponent;
        }
        else
            currentComponent = undefined;
    };
    const componentStack = [];
    while (treeWalker.nextNode()) {
        const node = treeWalker.currentNode;
        if (node.nodeType !== Node.ELEMENT_NODE)
            continue;
        const element = node;
        if (componentStack.length > 0) {
            const component = componentStack[componentStack.length - 1];
            //if element is not a descendant of the component's firstDOMElement,   the component from the stack
            if (component && !component.element.contains(element)) {
                componentStack.pop();
                endComponent(component.component.id);
            }
        }
        if (currentComponent && element.getAttribute("chrometype") === "field") {
            const id = element.getAttribute("id");
            if (id) {
                //fld_C866BEE59CE340F18529EF72E1EC34A7_427EC0BD3BF245B9880FBDB0054E7925_en_1_f3327de03c4c4fb39dae57c139e6202d_913_edit
                const idComponents = id.split("_");
                if (idComponents.length > 2) {
                    let fieldId = idComponents[2]?.toLocaleLowerCase();
                    if (!fieldId)
                        continue;
                    fieldId = ensureUUIDFormat(fieldId);
                    let itemId = idComponents[1]?.toLocaleLowerCase();
                    if (!itemId)
                        continue;
                    itemId = ensureUUIDFormat(itemId);
                    let renderedItem = itemId == currentComponent.datasourceItem?.id
                        ? currentComponent.datasourceItem
                        : currentComponent.items.find((x) => x.id === itemId);
                    if (!renderedItem) {
                        renderedItem = {
                            id: itemId,
                            language: currentComponent.datasourceItem?.language || "",
                            version: currentComponent.datasourceItem?.version || 0,
                            renderedFieldIds: [],
                        };
                        currentComponent.items.push(renderedItem);
                    }
                    if (renderedItem &&
                        renderedItem.renderedFieldIds.indexOf(fieldId) === -1) {
                        renderedItem.renderedFieldIds.push(fieldId);
                    }
                    currentComponent.editorFields;
                }
            }
        }
        if (currentComponent && element.hasAttribute("data-fieldid")) {
            const fieldId = element.getAttribute("data-fieldid");
            const formattedFieldId = ensureUUIDFormat(fieldId);
            const language = element.getAttribute("data-language") ||
                currentComponent.datasourceItem?.language ||
                pageItem.language;
            const version = element.hasAttribute("data-version")
                ? parseInt(element.getAttribute("data-version"))
                : currentComponent.datasourceItem?.version || pageItem.version;
            const itemId = element.getAttribute("data-itemid") ||
                currentComponent.datasourceItem?.id;
            if (!itemId)
                continue;
            let renderedItem = currentComponent.items.find((x) => x.id === itemId && x.language === language && x.version === version);
            if (!renderedItem) {
                renderedItem = {
                    id: itemId,
                    language,
                    version,
                    renderedFieldIds: [],
                };
                currentComponent.items.push(renderedItem);
            }
            if (renderedItem.renderedFieldIds.indexOf(formattedFieldId) === -1) {
                renderedItem.renderedFieldIds.push(formattedFieldId);
            }
        }
        if (element.tagName == "DIV" && element.hasAttribute("sc_item")) {
            const componentId = extractItemIdFromItemUri(element.getAttribute("sc_item"));
            if (componentId && componentId != currentComponent?.datasourceItem?.id) {
                const component = startComponent(componentId, element, componentId);
                if (component) {
                    component.lastDOMElement = component.firstDOMElement;
                    componentStack.push({ component, element });
                }
            }
        }
        if (element.tagName === "SCRIPT") {
            const placeholderStartId = element.getAttribute("data-placeholder-start");
            const placeholderEndId = element.getAttribute("data-placeholder-end");
            const componentStartId = element.getAttribute("data-component-start");
            const componentEndId = element.getAttribute("data-component-end");
            const dictionaryKeyStart = element.getAttribute("data-dictionary-key-start");
            const editorGroup = element.getAttribute("data-editor-group");
            if (currentComponent && editorGroup) {
                let group = currentComponent.editorFields[editorGroup];
                if (!group) {
                    group = {
                        addFields: [],
                        removeFields: [],
                    };
                    currentComponent.editorFields[editorGroup] = group;
                }
                const addFields = element.getAttribute("data-add-fields")?.split(",");
                const removeFields = element
                    .getAttribute("data-remove-fields")
                    ?.split(",");
                group.addFields = [...group.addFields, ...(addFields || [])];
                group.removeFields = [...group.removeFields, ...(removeFields || [])];
            }
            if (dictionaryKeyStart) {
                if (!currentComponent) {
                    console.error("Dictionary key without component:", dictionaryKeyStart);
                }
                else {
                    currentComponent.renderedDictionaryKeys.push(dictionaryKeyStart);
                }
            }
            if (placeholderStartId) {
                if (!currentComponent) {
                    console.error("Placeholder start without component:", placeholderStartId, "Current placeholder", currentPlaceholder);
                    // Attach orphaned placeholder to root component as a fallback
                    if (!currentPlaceholder) {
                        const parentComponent = root;
                        currentPlaceholder = {
                            key: placeholderStartId,
                            name: placeholderStartId,
                            description: element.getAttribute("data-description") || "",
                            components: [],
                            parentComponent: parentComponent,
                            editable: element.getAttribute("data-editable") !== "false",
                        };
                        parentComponent.placeholders.push(currentPlaceholder);
                        console.warn("Orphaned placeholder attached to root component as fallback:", placeholderStartId);
                    }
                }
                else {
                    currentPlaceholder = ensurePlaceholder(currentComponent, placeholderStartId, element);
                    currentComponent = undefined;
                }
            }
            if (placeholderEndId) {
                currentComponent = currentPlaceholder?.parentComponent;
                if (currentPlaceholder?.key !== placeholderEndId) {
                    console.error("Placeholder end does not match start", currentPlaceholder, placeholderEndId);
                }
                currentPlaceholder = undefined;
            }
            if (componentStartId) {
                startComponent(componentStartId, element);
            }
            if (componentEndId) {
                if (currentComponent) {
                    currentComponent.lastDOMElement = resolveComponentLastElement(componentEndId, element, currentComponent);
                    endComponent(componentEndId);
                }
            }
        }
    }
    const page = {
        rootComponent: root,
        item: pageItem,
        editRevision: editContextRef.current?.revision ?? "",
    };
    pageViewContextRef.current?.setPageSkeleton(page);
}
//# sourceMappingURL=pageModelSkeletonBuilder.js.map