import { jsx as _jsx } from "react/jsx-runtime";
import { Link2, Link2Off, Sparkles } from "lucide-react";
import { getRichTextProfile } from "../../services/contentService";
import { getCachedParsedProfile } from "./utils/profileServiceCache";
import { getComponentById } from "../../componentTreeHelper";
import { LinkEditorDialog, } from "../../LinkEditorDialog";
import { normalizeUrl } from "../../utils/urlUtils";
import { generateInternalLinkUrl } from "./utils/plugins";
import { SLATE_MARKS, } from "./types";
/** Wraps LinkEditorDialog for use with editContext.openDialog (onClose contract). */
function InlineLinkDialogWrapper({ linkValue, onClose, }) {
    return (_jsx(LinkEditorDialog, { linkValue: linkValue, onOk: (link) => onClose(link), onCancel: () => onClose(null) }));
}
// Helper function to execute formatting commands on the contentEditable element in iframe
function executeFormatCommand(command, iframeDocument, value) {
    try {
        // Focus the contentEditable element first
        const activeElement = iframeDocument.activeElement;
        if (activeElement &&
            activeElement.contentEditable === "true") {
            activeElement.focus();
        }
        // Execute the command on the iframe document
        console.log("Executing command:", command, value);
        return iframeDocument.execCommand(command, false, value);
    }
    catch (error) {
        console.error(`Failed to execute command: ${command}`, error);
        return false;
    }
}
// Helper function to get the current contentEditable element for this field in iframe
function getFieldEditableElement(fieldId, iframeDocument) {
    // Look for the contentEditable element with the matching field ID in iframe
    const element = iframeDocument.querySelector(`[data-fieldid="${fieldId}"][contenteditable="true"]`);
    return element;
}
function captureIframeSelection(iframeDocument) {
    const selection = iframeDocument.getSelection();
    if (!selection || selection.rangeCount === 0) {
        return null;
    }
    const ranges = [];
    for (let index = 0; index < selection.rangeCount; index += 1) {
        ranges.push(selection.getRangeAt(index).cloneRange());
    }
    return {
        ranges,
        text: selection.toString(),
    };
}
function restoreIframeSelection(iframeDocument, savedSelection) {
    const selection = iframeDocument.getSelection();
    if (!selection || !savedSelection?.ranges.length) {
        return false;
    }
    selection.removeAllRanges();
    savedSelection.ranges.forEach((range) => selection.addRange(range));
    return true;
}
function insertLinkAtSelection(iframeDocument, element, savedSelection, href, link) {
    element.focus();
    restoreIframeSelection(iframeDocument, savedSelection);
    const selection = iframeDocument.getSelection();
    if (!selection || selection.rangeCount === 0) {
        return false;
    }
    const range = selection.getRangeAt(0);
    const linkElement = iframeDocument.createElement("a");
    linkElement.href = href;
    const target = link.target || (link.type === "external" ? "_self" : "");
    if (target) {
        linkElement.target = target;
    }
    if (link.queryString) {
        linkElement.setAttribute("data-querystring", link.queryString);
    }
    linkElement.textContent =
        link.text ||
            (link.type === "external" ? href : savedSelection?.text) ||
            href;
    range.deleteContents();
    range.insertNode(linkElement);
    const afterLinkRange = iframeDocument.createRange();
    afterLinkRange.setStartAfter(linkElement);
    afterLinkRange.collapse(true);
    selection.removeAllRanges();
    selection.addRange(afterLinkRange);
    return true;
}
// Trigger a save by calling the editContext operations directly
// Wait for DOM to update before reading content to avoid race conditions
async function triggerSave(element, field, editContext, originatingSlotId) {
    try {
        // Wait for DOM updates to complete before reading content
        await new Promise((resolve) => {
            // Use a shorter delay - just enough for execCommand to complete
            setTimeout(resolve, 50);
        });
        const isRichText = element.getAttribute("data-is-richtext") === "true";
        const value = isRichText ? element.innerHTML : element.innerText;
        await editContext.operations.editField({
            field: field.descriptor,
            value: value,
            refresh: "none",
            originatingSlotId,
        });
    }
    catch (error) {
        console.error("Failed to save field value:", error);
    }
}
export function createSlateRichTextContextMenu({ field, editContext, profile, onToggleMark, onAddLink, onStripFormatting, canAddLink, isLinkActive, originatingSlotId, }) {
    if (!profile?.toolbar?.groups) {
        return [];
    }
    const canUseFormatting = editContext.mode === "edit" || editContext.mode === "suggestions";
    const menuItems = [];
    const formatMenuItems = [];
    let hasLinkOption = false;
    const supportedMarks = new Set([
        "bold",
        "italic",
        "underline",
        "strikethrough",
        "subscript",
        "superscript",
    ]);
    for (const group of profile.toolbar.groups) {
        if (!group.options || group.options.length === 0)
            continue;
        const groupItems = [];
        for (const option of group.options) {
            if (option.type === "mark") {
                if (!supportedMarks.has(option.id))
                    continue;
                const markConfig = SLATE_MARKS[option.id];
                if (!markConfig)
                    continue;
                groupItems.push({
                    id: `slate-format-mark-${option.id}`,
                    label: markConfig.label,
                    icon: (_jsx("span", { style: { fontFamily: "monospace", fontWeight: "bold" }, children: markConfig.icon })),
                    command: async () => {
                        onToggleMark(option.id);
                    },
                });
            }
            else if (option.type === "link") {
                hasLinkOption = true;
            }
        }
        if (groupItems.length > 0) {
            if (formatMenuItems.length > 0) {
                formatMenuItems.push({
                    id: `slate-format-separator-${group.id}`,
                    separator: true,
                });
            }
            formatMenuItems.push(...groupItems);
        }
    }
    const selectedRange = editContext.selectedRange;
    if (editContext.configuration.hasAiLicense !== false &&
        selectedRange?.text &&
        selectedRange.fieldId === field.id &&
        selectedRange.itemId === field.descriptor.item.id) {
        menuItems.push({
            id: "slate-ai-edit",
            label: "AI Edit",
            icon: _jsx(Sparkles, { className: "text-highlight-100 h-4 w-4" }),
            command: async () => {
                const event = new CustomEvent("inline-ai-open", {
                    detail: {
                        selectedText: selectedRange.text,
                        fieldId: field.id,
                        itemId: field.descriptor.item.id,
                    },
                });
                document.dispatchEvent(event);
            },
        });
    }
    if (canUseFormatting && formatMenuItems.length > 0) {
        menuItems.push({
            id: "slate-format-submenu",
            label: "Format",
            icon: (_jsx("span", { style: { fontFamily: "monospace", fontWeight: "bold" }, children: "F" })),
            items: formatMenuItems,
        });
    }
    if (canUseFormatting && hasLinkOption) {
        menuItems.push({
            id: "slate-add-link",
            label: "Add Link",
            icon: isLinkActive ? (_jsx(Link2Off, { className: "h-4 w-4", strokeWidth: 1.75 })) : (_jsx(Link2, { className: "h-4 w-4", strokeWidth: 1.75 })),
            disabled: !canAddLink,
            command: async () => {
                if (!canAddLink)
                    return;
                onAddLink();
            },
        });
    }
    if (canUseFormatting) {
        menuItems.push({
            id: "slate-strip-formatting",
            label: "Strip Formatting",
            icon: (_jsx("span", { style: { fontFamily: "monospace", fontWeight: "bold" }, children: "\u2717" })),
            command: async () => {
                onStripFormatting();
            },
        });
    }
    return menuItems;
}
export async function createRichTextContextMenu(field, editContext) {
    const richTextField = field;
    const profilePath = richTextField.customProperties?.profile;
    // Hide formatting when layout components are disabled and this field belongs to a layout component
    try {
        if (editContext?.showLayoutComponents === false && editContext?.page) {
            const owner = getComponentById(field.descriptor.item.id, editContext.page);
            if (owner?.layoutId) {
                return [];
            }
        }
    }
    catch { }
    // Get the iframe document
    const iframeDocument = editContext.getActiveSlotContext()?.primaryPageViewContext.editorIframe
        ?.contentWindow?.document;
    const originatingSlotId = editContext.getActiveSlotContext()?.slotId;
    if (!iframeDocument) {
        console.error("Could not find iframe document for rich text editing");
        return [];
    }
    try {
        // Get the rich text profile using the cached parsed profile
        const contextItemId = field.descriptor.item.id;
        const serviceCall = (path) => getRichTextProfile(path, contextItemId);
        const profile = await getCachedParsedProfile(profilePath, serviceCall);
        if (!profile?.toolbar?.groups) {
            return [];
        }
        // Formatting commands and Add Link only available in edit or suggestions mode
        const canUseFormatting = editContext.mode === "edit" || editContext.mode === "suggestions";
        // Create format submenu items based on the profile
        const formatMenuItems = [];
        let hasLinkOption = false;
        // Process each toolbar group to extract formatting options
        for (const group of profile.toolbar.groups) {
            if (group.options && group.options.length > 0) {
                // Collect valid items for this group first
                const groupItems = [];
                // Process each option in the group
                for (const option of group.options) {
                    let menuItem = null;
                    switch (option.type) {
                        case "mark":
                            const markConfig = SLATE_MARKS[option.id];
                            if (markConfig) {
                                let command = "";
                                // Only support specific formatting commands
                                switch (option.id) {
                                    case "bold":
                                        command = "bold";
                                        break;
                                    case "italic":
                                        command = "italic";
                                        break;
                                    case "underline":
                                        command = "underline";
                                        break;
                                    case "strikethrough":
                                        command = "strikeThrough";
                                        break;
                                    case "subscript":
                                        command = "subscript";
                                        break;
                                    case "superscript":
                                        command = "superscript";
                                        break;
                                    default:
                                        // Skip unsupported commands
                                        continue;
                                }
                                menuItem = {
                                    id: `format-mark-${option.id}`,
                                    label: markConfig.label,
                                    icon: (_jsx("span", { style: { fontFamily: "monospace", fontWeight: "bold" }, children: markConfig.icon })),
                                    command: async () => {
                                        try {
                                            const element = getFieldEditableElement(field.id, iframeDocument);
                                            if (element) {
                                                element.focus();
                                                const success = executeFormatCommand(command, iframeDocument);
                                                if (success) {
                                                    await triggerSave(element, field, editContext, originatingSlotId);
                                                }
                                            }
                                        }
                                        catch (error) {
                                            console.error(`Failed to apply mark formatting: ${option.id}`, error);
                                        }
                                    },
                                };
                            }
                            break;
                        case "link":
                            hasLinkOption = true;
                            break;
                        // Block, alignment, and list formatting not supported
                        case "block":
                        case "alignment":
                        case "list":
                            // Skip unsupported formatting types
                            continue;
                    }
                    if (menuItem) {
                        groupItems.push(menuItem);
                    }
                }
                // Only add group items if we have any valid items for this group
                if (groupItems.length > 0) {
                    // Add separator if we already have items from previous groups
                    if (formatMenuItems.length > 0) {
                        formatMenuItems.push({
                            id: `${group.id}-separator`,
                            separator: true,
                        });
                    }
                    // Add all valid items from this group
                    formatMenuItems.push(...groupItems);
                }
            }
        }
        // Build the context menu items
        const menuItems = [];
        // Add AI Edit option when text is selected and AI is licensed
        const selectedRange = editContext.selectedRange;
        if (editContext.configuration.hasAiLicense !== false &&
            selectedRange?.text &&
            selectedRange.fieldId === field.id &&
            selectedRange.itemId === field.descriptor.item.id) {
            menuItems.push({
                id: "ai-edit",
                label: "AI Edit",
                icon: _jsx(Sparkles, { className: "text-highlight-100 h-4 w-4" }),
                command: async () => {
                    // Dispatch custom event to open the inline AI dialog
                    const event = new CustomEvent("inline-ai-open", {
                        detail: {
                            selectedText: selectedRange.text,
                            fieldId: field.id,
                            itemId: field.descriptor.item.id,
                        },
                    });
                    document.dispatchEvent(event);
                },
            });
        }
        // Add the Format submenu if we have any items (only in edit/suggestions mode)
        if (canUseFormatting && formatMenuItems.length > 0) {
            menuItems.push({
                id: "format-submenu",
                label: "Format",
                icon: (_jsx("span", { style: { fontFamily: "monospace", fontWeight: "bold" }, children: "F" })),
                items: formatMenuItems,
            });
        }
        // Add Link command when available in RTE profile (only in edit/suggestions mode)
        if (canUseFormatting && hasLinkOption) {
            menuItems.push({
                id: "add-link",
                label: "Add Link",
                icon: _jsx(Link2, { className: "h-4 w-4", strokeWidth: 1.75 }),
                command: async () => {
                    try {
                        const element = getFieldEditableElement(field.id, iframeDocument);
                        if (!element || !editContext.openDialog)
                            return;
                        const savedSelection = captureIframeSelection(iframeDocument);
                        element.focus();
                        const link = await editContext.openDialog(InlineLinkDialogWrapper, {
                            linkValue: {
                                type: "external",
                                url: "",
                                target: "_blank",
                            },
                        });
                        if (link) {
                            const href = link.type === "internal"
                                ? generateInternalLinkUrl(link.itemId, link.targetItemLongId, link.queryString)
                                : normalizeUrl(link.url || "#");
                            const success = insertLinkAtSelection(iframeDocument, element, savedSelection, href, link);
                            if (success) {
                                await triggerSave(element, field, editContext, originatingSlotId);
                            }
                        }
                    }
                    catch (error) {
                        console.error("Failed to add link:", error);
                    }
                },
            });
        }
        // Add Strip Formatting command (only in edit/suggestions mode)
        if (canUseFormatting) {
            menuItems.push({
                id: "strip-formatting",
                label: "Strip Formatting",
                icon: (_jsx("span", { style: { fontFamily: "monospace", fontWeight: "bold" }, children: "\u2717" })),
                command: async () => {
                    try {
                        const element = getFieldEditableElement(field.id, iframeDocument);
                        if (element) {
                            element.focus();
                            const success = executeFormatCommand("removeFormat", iframeDocument);
                            if (success) {
                                await triggerSave(element, field, editContext, originatingSlotId);
                            }
                        }
                    }
                    catch (error) {
                        console.error("Failed to strip formatting:", error);
                    }
                },
            });
        }
        return menuItems;
    }
    catch (error) {
        console.error("Error creating RichText context menu:", error);
        return [];
    }
}
//# sourceMappingURL=contextMenuFactory.js.map