import { jsx as _jsx } from "react/jsx-runtime";
import uuid from "react-uuid";
import { Copy, MessageCirclePlus, Palette, Plus, RefreshCcw, Share2, Trash2, TriangleAlert, } from "lucide-react";
import { showCommentPopoverAt } from "../reviews/CommentPopover";
import { loadCustomCommands } from "../services/customCommandsService";
import { getCustomComponentCommands } from "./customCommandConverter";
import { getSharedComponentTarget, loadInsertOptions, } from "../services/editService";
import { SharedFolderSelectorDialog, } from "../ui/SharedFolderSelectorDialog";
const isPlaceholder = (x) => x.components !== undefined;
const defaultIconSize = 16;
function normalizeGuid(value) {
    if (!value)
        return "";
    return value.replace(/[{}]/g, "").toLowerCase();
}
function normalizeText(value) {
    return (value || "").trim().toLowerCase();
}
async function isTemplateAllowedInTargetFolder(targetFolder, templateId, componentTypeId, templateName) {
    if (!templateId)
        return true;
    const insertOptions = await loadInsertOptions(targetFolder);
    const normalizedTemplateId = normalizeGuid(templateId);
    const normalizedComponentTypeId = normalizeGuid(componentTypeId);
    const normalizedTemplateName = normalizeText(templateName);
    const matchedByTemplateId = insertOptions.filter((option) => normalizeGuid(option.templateId) === normalizedTemplateId);
    const matchedByTypeId = insertOptions.filter((option) => normalizeGuid(option.typeId) === normalizedTemplateId);
    const matchedByCompatibleTypeIds = insertOptions.filter((option) => (option.compatibleTypeIds || []).some((id) => normalizeGuid(id) === normalizedTemplateId));
    const matchedByComponentTypeId = insertOptions.filter((option) => normalizeGuid(option.typeId) === normalizedComponentTypeId);
    const matchedByName = insertOptions.filter((option) => normalizeText(option.name) === normalizedTemplateName);
    return (matchedByTemplateId.length > 0 ||
        matchedByTypeId.length > 0 ||
        matchedByCompatibleTypeIds.length > 0 ||
        matchedByComponentTypeId.length > 0 ||
        matchedByName.length > 0);
}
// export function getSelectedComponentCommands(editContext: EditContextType) {
//   const selection = editContext.selection;
//   const selectedComponents = selection
//     .map((x) => getComponentById(x, editContext.page!))
//     .filter((x) => x) as Component[];
//   const componentCommands = getComponentCommands(
//     selectedComponents,
//     editContext,
//   );
//   const componentCommandMenuItems = componentCommands.filter(
//     (x) => x.visibilityScopes.indexOf("menu") >= 0,
//   );
//   return componentCommandMenuItems;
// }
export async function getComponentCommands(entities, editContext) {
    const components = entities.filter((x) => x && !isPlaceholder(x));
    // Load custom commands from backend (e.g., AI commands configured in Sitecore)
    const customCommands = await getCustomComponentCommands(components, editContext, () => loadCustomCommands("frameMenu"), ["editFrame", "contextMenu"]);
    const externalCommands = (await Promise.all((editContext.configuration.componentCommands?.providers ?? []).map((provider) => provider(components, editContext)))).flat();
    const commands = [
        await getCreateCommentCommand(components, editContext),
        await getInsertCommand(components, editContext),
        await getDeleteCommand(components, editContext),
        await getDuplicateCommand(components, editContext),
        await getSyncCommand(entities, editContext),
        ...customCommands,
        await getDesignCommand(components, editContext),
        await getConvertToSharedCommand(components, editContext),
        ...externalCommands,
    ];
    return commands.filter((x) => x !== null);
}
function getInsertCommand(components, editContext) {
    if (components.length !== 1 || isPlaceholder(components[0]))
        return null;
    const item = components[0];
    if (!item)
        return null;
    if (!item.placeholders || item.placeholders.length === 0)
        return null;
    if (editContext.mode === "suggestions")
        return null;
    // Don't show insert for layout components when showLayoutComponents is disabled
    if (item.layoutId && !editContext.showLayoutComponents)
        return null;
    return {
        id: "insert",
        icon: _jsx(Plus, { size: defaultIconSize }),
        label: "Insert component",
        disabled: (context) => !context.editContext.page?.item.canWriteItem,
        visibilityScopes: ["editFrame"],
        execute: async () => {
            editContext.setSelectedForInsertion(item.id);
        },
    };
}
function getDuplicateCommand(components, editContext) {
    if (components.length !== 1)
        return null;
    if (editContext.mode === "suggestions")
        return null;
    const component = components[0];
    if (!component)
        return null;
    // Don't show duplicate for layout components when showLayoutComponents is disabled
    if (component.layoutId && !editContext.showLayoutComponents)
        return null;
    return {
        id: "duplicate",
        icon: _jsx(Copy, { size: defaultIconSize }),
        label: "Duplicate",
        visibilityScopes: ["contextMenu", "menu"],
        disabled: (c) => !(c.editContext.page?.item.canWriteItem || false),
        execute: async (context) => {
            // if (!components[0].parentPlaceholder?.parentComponent.datasourceItem)
            //   return;
            editContext.operations.duplicateComponents({
                componentIds: components.map((x) => x.id),
            });
        },
    };
}
async function getDesignCommand(components, editContext) {
    if (components.length !== 1 || isPlaceholder(components[0]))
        return null;
    const component = components[0];
    if (!component || !component.datasourceItem)
        return null;
    // Don't show design for layout components when showLayoutComponents is disabled
    if (component.layoutId && !editContext.showLayoutComponents)
        return null;
    const item = await editContext.itemsRepository.getItem(component.datasourceItem);
    if (!item)
        return null;
    if (!Object.values(item.fields).find((x) => x.section === "Design"))
        return null;
    return {
        id: "design",
        icon: _jsx(Palette, { size: defaultIconSize }),
        label: "Open Design Options",
        disabled: () => false,
        execute: async (context) => {
            // Switch to the design tab
            editContext.setActiveEditorTab("design");
        },
        visibilityScopes: ["editFrame", "contextMenu"],
    };
}
async function getConvertToSharedCommand(components, editContext) {
    // Only show for single component
    if (components.length !== 1 || isPlaceholder(components[0]))
        return null;
    const component = components[0];
    if (!component || !component.datasourceItem)
        return null;
    // Don't show for layout components when showLayoutComponents is disabled
    if (component.layoutId && !editContext.showLayoutComponents)
        return null;
    // Don't show if already shared
    if (component.isShared)
        return null;
    // Don't show in suggestions mode
    if (editContext.mode === "suggestions")
        return null;
    return {
        id: "convertToShared",
        icon: _jsx(Share2, { size: defaultIconSize }),
        label: "Convert to Shared",
        disabled: (context) => !context.editContext.page?.item.canWriteItem,
        visibilityScopes: ["contextMenu", "menu"],
        execute: async (context) => {
            if (!editContext.page?.item.descriptor)
                return;
            // Get the shared component target info from the backend
            const targetInfo = await getSharedComponentTarget(editContext.page.item.descriptor, component.id);
            if (!targetInfo.supported) {
                editContext.showErrorToast({
                    summary: "Not supported",
                    details: "Converting to shared component is not supported for this page.",
                });
                return;
            }
            let targetFolderId = targetInfo.rootFolderId;
            let targetFolderPath = targetInfo.rootFolderPath;
            const askProceedDespiteInsertOptions = async () => await new Promise((resolve) => {
                editContext.confirm({
                    showCancel: true,
                    message: `The selected folder does not list template "${component.datasourceItem?.templateName || component.datasourceItem?.templateId}" in its insert options. Move "${component.name}" anyway?`,
                    header: "Template not allowed in target folder",
                    icon: _jsx(TriangleAlert, { size: 28 }),
                    accept: () => resolve(true),
                    reject: () => resolve(false),
                });
            });
            if (targetInfo.allowUserSelection && targetInfo.rootFolderId) {
                while (true) {
                    const selectedFolder = await context.openDialog(SharedFolderSelectorDialog, {
                        editContext,
                        language: component.datasourceItem?.language ??
                            editContext.page.item.language,
                        initialFolderId: targetInfo.rootFolderId,
                        header: "Select Shared Component Folder",
                        label: "Move here",
                    });
                    if (!selectedFolder) {
                        return;
                    }
                    targetFolderId = selectedFolder.id;
                    const selectedFolderItem = await editContext.itemsRepository.getItem(selectedFolder);
                    targetFolderPath = selectedFolderItem?.path ?? targetFolderPath;
                    const selectedFolderDescriptor = {
                        id: targetFolderId,
                        language: component.datasourceItem?.language ??
                            editContext.page.item.language,
                        version: 0,
                        ...(editContext.page.item.descriptor.database
                            ? { database: editContext.page.item.descriptor.database }
                            : {}),
                    };
                    let isAllowedByInsertOptions = true;
                    try {
                        isAllowedByInsertOptions = await isTemplateAllowedInTargetFolder(selectedFolderDescriptor, component.datasourceItem?.templateId, component.typeId, component.datasourceItem?.templateName);
                    }
                    catch (error) {
                        console.warn("Failed to verify target folder insert options:", error);
                    }
                    if (isAllowedByInsertOptions)
                        break;
                    const continueAfterWarning = await askProceedDespiteInsertOptions();
                    if (continueAfterWarning)
                        break;
                    // User canceled the warning; return to folder selection dialog.
                }
            }
            if (!targetFolderId) {
                editContext.showErrorToast({
                    summary: "No target folder",
                    details: "Could not determine shared component target folder.",
                });
                return;
            }
            // Root-folder mode: validate once and allow user to proceed or cancel.
            if (!targetInfo.allowUserSelection) {
                const targetFolderDescriptor = {
                    id: targetFolderId,
                    language: component.datasourceItem?.language ??
                        editContext.page.item.language,
                    version: 0,
                    ...(editContext.page.item.descriptor.database
                        ? { database: editContext.page.item.descriptor.database }
                        : {}),
                };
                let isAllowedByInsertOptions = true;
                try {
                    isAllowedByInsertOptions = await isTemplateAllowedInTargetFolder(targetFolderDescriptor, component.datasourceItem?.templateId, component.typeId, component.datasourceItem?.templateName);
                }
                catch (error) {
                    console.warn("Failed to verify target folder insert options:", error);
                }
                if (!isAllowedByInsertOptions) {
                    const continueAfterWarning = await askProceedDespiteInsertOptions();
                    if (!continueAfterWarning)
                        return;
                }
            }
            // Confirm with user
            editContext.confirm({
                showCancel: true,
                message: `Move "${component.name}" to shared location at "${targetFolderPath}"? This will make the component available for use on other pages.`,
                header: "Convert to Shared Component",
                icon: _jsx(Share2, { size: 28 }),
                accept: () => {
                    const op = {
                        type: "convert-to-shared",
                        date: new Date().toISOString(),
                        id: uuid(),
                        componentId: component.id,
                        targetFolderId: targetFolderId,
                        mainItem: editContext.page.item.descriptor,
                        title: `Convert to shared: ${component.name}`,
                    };
                    editContext.operations.executeEditOperation(op);
                },
            });
        },
    };
}
function isLocked(c, editContext) {
    if (editContext.activeSessions.find((x) => x.fieldLock?.item.id === c.id &&
        x.fieldLock.item.language == c.datasourceItem?.language &&
        x.fieldLock.item.version === c.datasourceItem?.version &&
        x.sessionId !== editContext.sessionId) !== undefined) {
        return true;
    }
    else
        return (c.placeholders?.find((x) => x.components.find((child) => isLocked(child, editContext)) !==
            undefined) !== undefined);
}
function getDeleteCommand(components, editContext) {
    if (editContext.mode === "suggestions")
        return null;
    const applicableComponents = components.filter((c) => ((!isPlaceholder(c) && !c.layoutId) ||
        c.layoutId === editContext.page?.item.id) &&
        !isLocked(c, editContext) &&
        editContext.page?.item.canWriteItem &&
        // When showLayoutComponents is disabled, layout components should not be editable
        (editContext.showLayoutComponents || !c.layoutId));
    if (applicableComponents.length === 0)
        return null;
    return {
        id: "delete",
        label: "Delete",
        icon: _jsx(Trash2, { size: 14 }),
        execute: async (context) => deleteComponents(applicableComponents, context.editContext),
        disabled: () => applicableComponents.length === 0 ||
            applicableComponents.length !== components.length,
        visibilityScopes: ["editFrame", "menu", "contextMenu"],
    };
}
function canSynchronize(placeholderData) {
    if (placeholderData.canSynchronize)
        return true;
    placeholderData.components.forEach((c) => {
        if (c.placeholders?.find((x) => canSynchronize(x)))
            return true;
    });
    return false;
}
function getSyncCommand(components, editContext) {
    const placeholders = [];
    for (const component of components) {
        if (isPlaceholder(component) && canSynchronize(component)) {
            placeholders.push({
                item: component.parentComponent
                    ? getItemDescriptor(component.parentComponent, editContext)
                    : undefined,
            });
        }
        else {
            if (component.placeholders?.find((x) => canSynchronize(x))) {
                placeholders.push({
                    item: getItemDescriptor(component, editContext),
                });
            }
        }
    }
    const canSync = placeholders.length > 0 ||
        (components.length === 0 &&
            editContext.page?.rootComponent.placeholders.find((x) => canSynchronize(x)));
    return {
        id: "synchronize",
        label: "Synchronize",
        icon: _jsx(RefreshCcw, { size: 14 }),
        disabled: () => !canSync,
        visibilityScopes: ["menu", "editFrame", "contextMenu"],
        execute: async () => {
            const op = {
                mainItem: editContext.page.item.descriptor,
                type: "synchronize-components",
                date: new Date().toISOString(),
                delete: false,
                id: uuid(),
                placeholders: placeholders,
                title: "Synchronize components",
            };
            editContext.operations.executeEditOperation(op);
        },
    };
}
function deleteComponents(components, editContext) {
    if (!components.length)
        return;
    editContext.confirm({
        showCancel: true,
        message: (components.length > 1
            ? "Are you sure you want to remove these components? "
            : "Are you sure you want to remove this component? ") +
            components.map((x) => x.name).join(", "),
        header: components.length > 1 ? "Remove components" : "Remove component",
        icon: _jsx(TriangleAlert, { size: 28 }),
        accept: () => {
            if (!editContext.page?.item.descriptor)
                return;
            console.log("Remove components", components);
            const op = {
                type: "remove-component",
                date: new Date().toISOString(),
                id: uuid(),
                componentIds: components.map((x) => x.id),
                mainItem: editContext.page.item.descriptor,
                title: "Remove components: " + components.map((x) => x.name).join(", "),
            };
            editContext.operations.executeEditOperation(op);
        },
    });
}
function getCreateCommentCommand(components, editContext) {
    if (components.length !== 1 || isPlaceholder(components[0]))
        return null;
    return {
        id: "addComment",
        label: "Add Comment",
        icon: _jsx(MessageCirclePlus, { size: 14, strokeWidth: 1 }),
        disabled: () => false,
        visibilityScopes: ["contextMenu"],
        execute: async (context) => {
            const ev = context.event;
            if (ev?.preventDefault)
                ev.preventDefault();
            if (ev?.stopPropagation)
                ev.stopPropagation();
            if (ev?.nativeEvent?.stopImmediatePropagation)
                ev.nativeEvent.stopImmediatePropagation();
            const x = ev?.clientX ?? ev?.pageX ?? window.innerWidth / 2;
            const y = ev?.clientY ?? ev?.pageY ?? window.innerHeight / 2;
            setTimeout(() => {
                requestAnimationFrame(() => {
                    const snapshotField = context.editContext.focusedField;
                    const snapshotRange = context.editContext.selectedRange;
                    showCommentPopoverAt({ x, y }, context.editContext, {
                        field: snapshotField,
                        range: snapshotRange,
                    });
                });
            }, 0);
        },
    };
}
function getItemDescriptor(component, editContext) {
    return {
        id: component.id,
        language: component.datasourceItem?.language || editContext.page.item.language,
        version: component.datasourceItem?.version || editContext.page.item.version,
    };
}
//# sourceMappingURL=componentCommands.js.map