import { Element as SlateElement } from "slate";
import { SLATE_MARKS, SLATE_BLOCKS, } from "../types";
import { normalizeUrl } from "../../../utils/urlUtils";
import { generateSitecoreDynamicLinkHref } from "./plugins";
// Elements that should be completely preserved as raw HTML
const PRESERVE_AS_RAW_ELEMENTS = new Set([
    "table",
    "tbody",
    "thead",
    "tfoot",
    "tr",
    "td",
    "th",
    "svg",
    "canvas",
    "iframe",
    "object",
    "embed",
    "form",
    "input",
    "textarea",
    "select",
    "button",
    "video",
    "audio",
    "source",
    "track",
    "script",
    "style",
    "noscript",
]);
// Shared utility: Get default block type from profile with strict typing
const getDefaultBlockType = (blocks) => {
    return blocks.length > 0 && blocks[0] ? blocks[0] : "paragraph";
};
// Shared utility: Unescape HTML entities
const unescapeHtmlEntities = (text) => {
    return text
        .replace(/&lt;/g, "<")
        .replace(/&gt;/g, ">")
        .replace(/&quot;/g, '"')
        .replace(/&#39;/g, "'")
        .replace(/&amp;/g, "&"); // This should be last to avoid double-unescaping
};
// Escape a value for use inside a double-quoted HTML attribute
const escapeHtmlAttribute = (value) => value.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
// Parse an editor-local "/items/{guid}[?querystring]" href (the display URL
// format generated by generateInternalLinkUrl). Values saved by older editor
// versions can contain these instead of Sitecore dynamic links.
const parseItemsHref = (href) => {
    const match = href
        .replace(/&amp;/g, "&")
        .match(/^\/items\/([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[0-9a-fA-F]{32})(?:\?(.*))?$/);
    if (!match || !match[1])
        return null;
    const itemId = match[1]
        .replace(/-/g, "")
        .replace(/(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/, "$1-$2-$3-$4-$5")
        .toLowerCase();
    return { itemId, queryString: match[2] || "" };
};
// Build a Slate link element from an <a> tag. Single implementation shared by
// every traversal path so internal-link detection cannot drift between them.
// Also exported for the WYSIWYG canvas toolbar, which hydrates the link dialog
// from the selected anchor's attributes using the same detection rules.
export const createLinkElementFromAnchor = (anchorElement, linkChildren) => {
    const href = anchorElement.getAttribute("href") || "";
    const target = anchorElement.getAttribute("target") || "_self";
    const itemsLink = parseItemsHref(href);
    const isInternal = anchorElement.hasAttribute("data-internal") ||
        href.includes("~/link.aspx?_id=") ||
        href.includes("/sitecore/service/notfound.aspx?item=") ||
        !!itemsLink;
    let itemId = anchorElement.getAttribute("data-item-id") || "";
    let targetItemLongId = anchorElement.getAttribute("data-item-longid") || "";
    let queryString = anchorElement.getAttribute("data-querystring") || "";
    const linkTitle = anchorElement.getAttribute("title") || "";
    const nofollow = (anchorElement.getAttribute("rel") || "")
        .split(/\s+/)
        .includes("nofollow");
    // Parse editor-local display format: /items/{guid}
    if (itemsLink && !itemId) {
        itemId = itemsLink.itemId;
        targetItemLongId = itemId;
        if (!queryString) {
            queryString = itemsLink.queryString;
        }
    }
    // Parse standard Sitecore RTE format: ~/link.aspx?_id=GUID&_z=z
    if (href.includes("~/link.aspx?_id=") && !itemId) {
        // Decode HTML entities (e.g. &amp; to &) before parsing
        const decodedHref = href.replace(/&amp;/g, "&");
        const rawQueryString = decodedHref.split("?")[1];
        const urlParams = new URLSearchParams(rawQueryString);
        const id = urlParams.get("_id");
        if (id) {
            // Convert GUID format back to standard format with dashes
            itemId = id
                .replace(/(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/, "$1-$2-$3-$4-$5")
                .toLowerCase();
            targetItemLongId = itemId;
            // Extract other query parameters (excluding _id and _z)
            queryString = Array.from(urlParams.entries())
                .filter(([key]) => key !== "_id" && key !== "_z")
                .map(([key, value]) => `${key}=${value}`)
                .join("&");
        }
    }
    // Parse Sitecore error page format: /sitecore/service/notfound.aspx?item=core:{GUID}@en
    if (href.includes("/sitecore/service/notfound.aspx?item=") && !itemId) {
        const urlParams = new URLSearchParams(href.split("?")[1]);
        const itemParam = urlParams.get("item");
        if (itemParam) {
            const decodedItem = decodeURIComponent(itemParam);
            const guidMatch = decodedItem.match(/\{([A-F0-9-]{36})\}/i);
            if (guidMatch && guidMatch[1]) {
                itemId = guidMatch[1].toLowerCase();
                targetItemLongId = itemId;
            }
        }
    }
    return {
        type: "link",
        url: href,
        link: {
            type: isInternal ? "internal" : "external",
            url: href,
            target,
            itemId,
            targetItemLongId,
            queryString,
            title: linkTitle,
            nofollow,
            originalHref: href.includes("~/link.aspx?_id=") &&
                !href.includes("/sitecore/service/notfound.aspx")
                ? href
                : undefined, // Preserve original Sitecore href, but not error pages
        },
        children: linkChildren.length
            ? linkChildren
            : [{ text: anchorElement.textContent || "Link" }],
    };
};
// Simplified preservation check
const shouldPreserveAsRaw = (element) => {
    const tagName = element.tagName.toLowerCase();
    // Check if it's in the preserve list
    if (PRESERVE_AS_RAW_ELEMENTS.has(tagName)) {
        return true;
    }
    // Check if this element contains any elements that should be preserved
    const containsPreserveElements = element.querySelector(Array.from(PRESERVE_AS_RAW_ELEMENTS).join(","));
    if (containsPreserveElements) {
        return true;
    }
    // Check for complex styling that would be hard to preserve
    const style = element.getAttribute("style") || "";
    const hasComplexStyling = style.includes("background-color") ||
        style.includes("font-family") ||
        style.includes("font-size") ||
        style.includes("color:");
    return hasComplexStyling && element.children.length > 0;
};
// Shared utility: Process marks from element with strict typing
const getMarksFromElement = (element, configuredMarks) => {
    const marks = {};
    // Map common tag names (including execCommand outputs) to mark IDs
    const TAG_TO_MARK = {
        b: "bold",
        strong: "bold",
        i: "italic",
        em: "italic",
        u: "underline",
        s: "strikethrough",
        strike: "strikethrough",
        sub: "subscript",
        sup: "superscript",
        // span handled via class check below (e.g., extrabold)
    };
    // Check for HTML tag-based marks (supports both semantic and legacy tags)
    const tagName = element.tagName.toLowerCase();
    const mapped = TAG_TO_MARK[tagName];
    if (mapped) {
        marks[mapped] = true;
    }
    // Also support the original config lookup (e.g., for custom tags)
    else {
        const markConfig = configuredMarks.find((markId) => {
            const config = SLATE_MARKS[markId];
            return config && config.htmlTag === tagName;
        });
        if (markConfig) {
            marks[markConfig] = true;
        }
    }
    // Class-based detection (e.g., extrabold span)
    if (element.classList?.contains("extrabold")) {
        marks["extrabold"] = true;
    }
    // Check for inline style-based marks
    const style = element.getAttribute("style");
    if (style) {
        if (style.includes("font-weight: bold") ||
            style.includes("font-weight:bold")) {
            marks["bold"] = true;
        }
        if (style.includes("font-style: italic") ||
            style.includes("font-style:italic")) {
            marks["italic"] = true;
        }
        if (style.includes("text-decoration: underline") ||
            style.includes("text-decoration:underline")) {
            marks["underline"] = true;
        }
        if (style.includes("text-decoration: line-through") ||
            style.includes("text-decoration:line-through")) {
            marks["strikethrough"] = true;
        }
    }
    return marks;
};
// Enhanced htmlToSlate with better error handling and strict typing
export const htmlToSlate = (html, profile) => {
    try {
        return htmlToSlateInternal(html, profile);
    }
    catch (error) {
        console.warn("HTML to Slate conversion failed:", error);
        const defaultBlockType = getDefaultBlockType(profile.blocks);
        return [{ type: defaultBlockType, children: [{ text: "" }] }];
    }
};
const htmlToSlateInternal = (html, profile) => {
    const defaultBlockType = getDefaultBlockType(profile.blocks);
    // Treat common empty HTML representations as empty Slate content
    if (!html || html === "<p><br></p>" || html === "<br>") {
        return [{ type: defaultBlockType, children: [{ text: "" }] }];
    }
    const div = document.createElement("div");
    div.innerHTML = html;
    const nodes = [];
    // Determine block type for element with strict typing
    const getBlockTypeForElement = (element) => {
        const tagName = element.tagName.toLowerCase();
        // Check if we have a configured block for this element
        const matchingBlockId = profile.blocks.find((blockId) => {
            const blockConfig = SLATE_BLOCKS[blockId];
            return blockConfig && blockConfig.htmlTag === tagName;
        });
        return matchingBlockId || defaultBlockType;
    };
    // Process list elements
    const processListElement = (element, currentIndent = 0) => {
        const tagName = element.tagName.toLowerCase();
        const listType = tagName === "ul" ? "unordered" : "ordered";
        Array.from(element.children).forEach((child) => {
            if (child.tagName.toLowerCase() === "li") {
                const liElement = child;
                const style = liElement.getAttribute("style") || "";
                const alignMatch = style.match(/text-align:\s*([^;]+)/);
                const align = alignMatch ? alignMatch[1] : undefined;
                // Process text content and inline elements (excluding nested lists)
                const children = processNodeWithInlinesExcludingNestedLists(liElement, profile.marks);
                nodes.push({
                    type: "list-item",
                    listType: listType,
                    indent: currentIndent,
                    align,
                    children: children.length > 0 ? children : [{ text: "" }],
                });
                // Process nested lists separately
                Array.from(liElement.children).forEach((childEl) => {
                    const childTagName = childEl.tagName.toLowerCase();
                    if (childTagName === "ul" || childTagName === "ol") {
                        processListElement(childEl, currentIndent + 1);
                    }
                });
            }
        });
    };
    // Process inline elements and text, excluding nested lists - with strict typing
    const processNodeWithInlinesExcludingNestedLists = (element, configuredMarks) => {
        const results = [];
        const currentElementMarks = getMarksFromElement(element, configuredMarks);
        Array.from(element.childNodes).forEach((child) => {
            if (child.nodeType === Node.TEXT_NODE) {
                if (child.textContent) {
                    results.push({
                        text: child.textContent,
                        ...currentElementMarks,
                    });
                }
            }
            else if (child.nodeType === Node.ELEMENT_NODE) {
                const childElement = child;
                const tagName = childElement.tagName.toLowerCase();
                // Skip nested lists - they're processed separately
                if (tagName === "ul" || tagName === "ol") {
                    return;
                }
                if (tagName === "br") {
                    // Handle inline br elements as line-break elements
                    results.push({
                        type: "line-break",
                        children: [{ text: "" }],
                    });
                }
                else if (tagName === "a") {
                    const linkChildren = processNodeWithInlines(childElement, configuredMarks);
                    results.push(createLinkElementFromAnchor(childElement, linkChildren));
                }
                else if (tagName === "link") {
                    // Handle Sitecore XML link tags
                    const linktype = childElement.getAttribute("linktype") || "";
                    const itemId = childElement.getAttribute("id") || "";
                    const target = childElement.getAttribute("target") || "_self";
                    const queryString = childElement.getAttribute("querystring") || "";
                    const url = childElement.getAttribute("url") || "";
                    const linkTitle = childElement.getAttribute("title") || "";
                    const linkChildren = processNodeWithInlines(childElement, configuredMarks);
                    results.push({
                        type: "link",
                        url: linktype === "internal" ? "" : url,
                        link: {
                            type: linktype === "internal" ? "internal" : "external",
                            url: linktype === "internal" ? "" : url,
                            target,
                            itemId: linktype === "internal" ? itemId : "",
                            targetItemLongId: linktype === "internal" ? itemId : "",
                            queryString,
                            title: linkTitle,
                        },
                        children: linkChildren.length
                            ? linkChildren
                            : [{ text: childElement.textContent || "Link" }],
                    });
                }
                else if (shouldPreserveAsRaw(childElement)) {
                    // Preserve complex elements as raw HTML
                    results.push({
                        text: childElement.outerHTML,
                        isRawHtml: true,
                    });
                }
                else {
                    // Process as regular inline element with marks
                    const childMarks = getMarksFromElement(childElement, configuredMarks);
                    const combinedMarks = { ...currentElementMarks, ...childMarks };
                    const childContent = processNodeWithInlines(childElement, configuredMarks);
                    childContent.forEach((node) => {
                        if ("text" in node) {
                            Object.assign(node, combinedMarks);
                        }
                        results.push(node);
                    });
                }
            }
        });
        return results;
    };
    // Process inline elements and text - with strict typing
    const processNodeWithInlines = (element, configuredMarks) => {
        const results = [];
        const currentElementMarks = getMarksFromElement(element, configuredMarks);
        Array.from(element.childNodes).forEach((child) => {
            if (child.nodeType === Node.TEXT_NODE) {
                if (child.textContent) {
                    results.push({
                        text: child.textContent,
                        ...currentElementMarks,
                    });
                }
            }
            else if (child.nodeType === Node.ELEMENT_NODE) {
                const childElement = child;
                const tagName = childElement.tagName.toLowerCase();
                if (tagName === "br") {
                    // Handle inline br elements as line-break elements
                    results.push({
                        type: "line-break",
                        children: [{ text: "" }],
                    });
                }
                else if (tagName === "a") {
                    const linkChildren = processNodeWithInlines(childElement, configuredMarks);
                    results.push(createLinkElementFromAnchor(childElement, linkChildren));
                }
                else if (tagName === "link") {
                    // Handle Sitecore XML link tags
                    const linktype = childElement.getAttribute("linktype") || "";
                    const itemId = childElement.getAttribute("id") || "";
                    const target = childElement.getAttribute("target") || "_self";
                    const queryString = childElement.getAttribute("querystring") || "";
                    const url = childElement.getAttribute("url") || "";
                    const linkTitle = childElement.getAttribute("title") || "";
                    const linkChildren = processNodeWithInlines(childElement, configuredMarks);
                    results.push({
                        type: "link",
                        url: linktype === "internal" ? "" : url,
                        link: {
                            type: linktype === "internal" ? "internal" : "external",
                            url: linktype === "internal" ? "" : url,
                            target,
                            itemId: linktype === "internal" ? itemId : "",
                            targetItemLongId: linktype === "internal" ? itemId : "",
                            queryString,
                            title: linkTitle,
                        },
                        children: linkChildren.length
                            ? linkChildren
                            : [{ text: childElement.textContent || "Link" }],
                    });
                }
                else if (tagName === "ul" ||
                    tagName === "ol" ||
                    shouldPreserveAsRaw(childElement)) {
                    // Preserve nested lists and complex elements as raw HTML
                    results.push({
                        text: childElement.outerHTML,
                        isRawHtml: true,
                    });
                }
                else {
                    // Process as regular inline element with marks
                    const childMarks = getMarksFromElement(childElement, configuredMarks);
                    const combinedMarks = { ...currentElementMarks, ...childMarks };
                    const childContent = processNodeWithInlines(childElement, configuredMarks);
                    childContent.forEach((node) => {
                        if ("text" in node) {
                            Object.assign(node, combinedMarks);
                        }
                        results.push(node);
                    });
                }
            }
        });
        return results;
    };
    // Process top-level nodes
    // Bare text or inline anchors at the top level mean the value is an HTML
    // fragment without block wrappers; combine it into a single block. Top-level
    // anchors must take this path even when they are the only content — the
    // block path would flatten them to their text and silently drop the links.
    const topLevelNodes = Array.from(div.childNodes);
    const INLINE_TOP_LEVEL_TAGS = new Set(["a", "link"]);
    const hasMixedContent = topLevelNodes.some((node) => (node.nodeType === Node.TEXT_NODE && node.textContent?.trim()) ||
        (node.nodeType === Node.ELEMENT_NODE &&
            INLINE_TOP_LEVEL_TAGS.has(node.tagName.toLowerCase())));
    if (hasMixedContent) {
        // Combine mixed top-level text and inline elements into a single block.
        // processNodeWithInlines handles the container's child nodes directly, so
        // top-level anchors become link elements instead of being flattened to
        // their text content (which would silently drop the links on save).
        const combinedChildren = processNodeWithInlines(div, profile.marks);
        if (combinedChildren.length > 0) {
            nodes.push({
                type: defaultBlockType,
                children: combinedChildren,
            });
        }
    }
    else {
        // Process normally for single elements or non-mixed content
        Array.from(div.childNodes).forEach((node) => {
            if (node.nodeType === Node.ELEMENT_NODE) {
                const element = node;
                const tagName = element.tagName.toLowerCase();
                // Extract alignment if present
                const style = element.getAttribute("style") || "";
                const alignMatch = style.match(/text-align:\s*([^;]+)/);
                const align = alignMatch ? alignMatch[1] : undefined;
                if (tagName === "br") {
                    // Handle standalone br elements as line-break elements
                    nodes.push({
                        type: "line-break",
                        children: [{ text: "" }],
                    });
                }
                else if (tagName === "hr") {
                    // Handle horizontal rule elements
                    nodes.push({
                        type: "horizontal-rule",
                        children: [{ text: "" }],
                    });
                }
                else if (tagName === "ul" || tagName === "ol") {
                    processListElement(element);
                }
                else if (tagName === "li") {
                    // Handle standalone li elements
                    const parentTagName = element.parentElement?.tagName.toLowerCase();
                    const listType = parentTagName === "ul"
                        ? "unordered"
                        : parentTagName === "ol"
                            ? "ordered"
                            : "unordered";
                    const children = processNodeWithInlines(element, profile.marks);
                    nodes.push({
                        type: "list-item",
                        listType: listType,
                        indent: 0,
                        align,
                        children: children.length > 0 ? children : [{ text: "" }],
                    });
                }
                else if (shouldPreserveAsRaw(element)) {
                    // Preserve complex elements as raw HTML
                    nodes.push({
                        type: defaultBlockType,
                        children: [{ text: element.outerHTML, isRawHtml: true }],
                    });
                }
                else {
                    const children = processNodeWithInlines(element, profile.marks);
                    const blockType = getBlockTypeForElement(element);
                    nodes.push({
                        type: blockType,
                        align,
                        children: children.length > 0 ? children : [{ text: "" }],
                    });
                }
            }
            else if (node.nodeType === Node.TEXT_NODE && node.textContent?.trim()) {
                nodes.push({
                    type: defaultBlockType,
                    children: [{ text: node.textContent }],
                });
            }
        });
    }
    return nodes.length > 0
        ? nodes
        : [{ type: defaultBlockType, children: [{ text: "" }] }];
};
// Enhanced formatTextWithMarks with strict typing
export const formatTextWithMarks = (child, configuredMarks) => {
    // If this is raw HTML, return it as-is with unescaping
    if (child.isRawHtml) {
        return unescapeHtmlEntities(child.text);
    }
    let text = child.text;
    // Line breaks are now handled as elements, not text nodes
    // Apply marks using Slate's built-in mark system with strict typing
    configuredMarks.forEach((markId) => {
        const markConfig = SLATE_MARKS[markId];
        if (markConfig && child[markId]) {
            text = markConfig.renderHtml(text);
        }
    });
    return text;
};
// Enhanced slateToHtml with better error handling
export const slateToHtml = (value, profile) => {
    try {
        return slateToHtmlInternal(value, profile);
    }
    catch (error) {
        console.warn("Slate to HTML conversion failed:", error);
        return "";
    }
};
const slateToHtmlInternal = (value, profile) => {
    let html = "";
    let i = 0;
    const defaultBlockType = getDefaultBlockType(profile.blocks);
    // Build nested list HTML
    const buildNestedListHtml = (startIndex, targetIndent = 0) => {
        let listHtml = "";
        let currentIndex = startIndex;
        // Find first element at target level to determine list type
        let firstListType = "unordered";
        while (currentIndex < value.length) {
            const element = value[currentIndex];
            if (element.type !== "list-item")
                break;
            const elementIndent = element.indent || 0;
            if (elementIndent === targetIndent) {
                firstListType = element.listType || "unordered";
                break;
            }
            else if (elementIndent < targetIndent) {
                break;
            }
            currentIndex++;
        }
        const listTag = firstListType === "ordered" ? "ol" : "ul";
        listHtml += `<${listTag}>`;
        currentIndex = startIndex;
        while (currentIndex < value.length) {
            const element = value[currentIndex];
            if (element.type !== "list-item")
                break;
            const elementIndent = element.indent || 0;
            const elementListType = element.listType || "unordered";
            if (elementIndent < targetIndent)
                break;
            if (elementIndent === targetIndent && elementListType === firstListType) {
                const processedChildren = processChildrenWithInlines(element.children, profile.marks);
                listHtml += `<li>${processedChildren}`;
                // Check for nested lists
                if (currentIndex + 1 < value.length) {
                    const nextElement = value[currentIndex + 1];
                    if (nextElement.type === "list-item" &&
                        (nextElement.indent || 0) > elementIndent) {
                        const nestedResult = buildNestedListHtml(currentIndex + 1, elementIndent + 1);
                        listHtml += nestedResult.html;
                        currentIndex = nestedResult.nextIndex - 1;
                    }
                }
                listHtml += `</li>`;
                currentIndex++;
            }
            else if (elementIndent > targetIndent) {
                const nestedResult = buildNestedListHtml(currentIndex, elementIndent);
                listHtml += nestedResult.html;
                currentIndex = nestedResult.nextIndex;
            }
            else {
                break;
            }
        }
        listHtml += `</${listTag}>`;
        return { html: listHtml, nextIndex: currentIndex };
    };
    // Process children with inline elements - with strict typing
    const processChildrenWithInlines = (children, configuredMarks) => {
        let result = "";
        children.forEach((child) => {
            if (SlateElement.isElement(child)) {
                if (child.type === "line-break") {
                    // Handle inline line break elements
                    result += "<br>";
                }
                else if (child.type === "link") {
                    const linkElement = child;
                    const isInternal = linkElement.link?.type === "internal";
                    const linkText = linkElement.children
                        ?.map((c) => {
                        if (SlateElement.isElement(c)) {
                            return processChildrenWithInlines(c.children, configuredMarks);
                        }
                        else {
                            const textNode = c;
                            return textNode.isRawHtml
                                ? unescapeHtmlEntities(textNode.text)
                                : formatTextWithMarks(textNode, configuredMarks);
                        }
                    })
                        .join("") || "";
                    const linkTitle = linkElement.link?.title || "";
                    const titleAttr = linkTitle
                        ? ` title="${escapeHtmlAttribute(linkTitle)}"`
                        : "";
                    const relAttr = linkElement.link?.nofollow ? ` rel="nofollow"` : "";
                    if (isInternal) {
                        const itemId = linkElement.link?.itemId || "";
                        const target = linkElement.link?.target || "_self";
                        const queryString = linkElement.link?.queryString || "";
                        const originalHref = linkElement.link?.originalHref;
                        let href;
                        if (originalHref) {
                            // Use original Sitecore RTE href to preserve exact format
                            href = originalHref;
                        }
                        else {
                            // Generate standard Sitecore RTE format for new links
                            href = generateSitecoreDynamicLinkHref(itemId, queryString);
                        }
                        result += `<a href="${escapeHtmlAttribute(href)}" target="${escapeHtmlAttribute(target)}"${titleAttr}${relAttr}>${linkText}</a>`;
                    }
                    else {
                        const rawUrl = linkElement.url || linkElement.link?.url || "#";
                        const url = normalizeUrl(rawUrl);
                        const target = linkElement.link?.target || "_self";
                        const queryString = linkElement.link?.queryString || "";
                        result += `<a href="${escapeHtmlAttribute(url)}" target="${escapeHtmlAttribute(target)}" data-querystring="${escapeHtmlAttribute(queryString)}"${titleAttr}${relAttr}>${linkText}</a>`;
                    }
                }
                else {
                    // Handle other element types
                    result += processChildrenWithInlines(child.children, configuredMarks);
                }
            }
            else {
                // Regular text node
                const textNode = child;
                result += textNode.isRawHtml
                    ? unescapeHtmlEntities(textNode.text)
                    : formatTextWithMarks(textNode, configuredMarks);
            }
        });
        return result;
    };
    // Process all elements
    while (i < value.length) {
        const element = value[i];
        // Handle list items
        if (element.type === "list-item") {
            const listResult = buildNestedListHtml(i, element.indent || 0);
            html += listResult.html;
            i = listResult.nextIndex;
            continue;
        }
        const alignStyle = element.align
            ? ` style="text-align: ${element.align};"`
            : "";
        // Handle horizontal rule elements
        if (element.type === "horizontal-rule") {
            html += "<hr>";
        }
        else if (element.type === "line-break") {
            html += "<br>";
        }
        else if (element.type === "preserved-element") {
            // Handle preserved elements by restoring their original HTML
            const preservedElement = element;
            html += preservedElement.originalHtml;
        }
        else {
            const blockConfig = SLATE_BLOCKS[element.type];
            if (blockConfig &&
                profile.blocks.includes(element.type) &&
                element.children) {
                const processedChildren = processChildrenWithInlines(element.children, profile.marks);
                html += blockConfig.renderHtml(processedChildren, alignStyle);
            }
            else {
                // Fallback for unknown types
                const processedChildren = processChildrenWithInlines(element.children, profile.marks);
                const defaultBlockConfig = SLATE_BLOCKS[defaultBlockType];
                if (defaultBlockConfig) {
                    html += defaultBlockConfig.renderHtml(processedChildren, alignStyle);
                }
                else if (defaultBlockType === "no-tag") {
                    html += processedChildren;
                }
                else {
                    html += `<p${alignStyle}>${processedChildren}</p>`;
                }
            }
        }
        i++;
    }
    // Handle empty content
    if (!html) {
        const defaultBlockConfig = SLATE_BLOCKS[defaultBlockType];
        if (defaultBlockConfig) {
            return defaultBlockConfig.renderHtml("<br>", "");
        }
        else if (defaultBlockType === "no-tag") {
            return "<br>";
        }
        else {
            return "<p><br></p>";
        }
    }
    return html;
};
//# sourceMappingURL=conversion.js.map