import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useCallback, useEffect, useRef, useState } from "react";
import { ImagePlus, Sparkles } from "lucide-react";
import { useEditContext } from "../client/editContext";
import { getComponentById } from "../componentTreeHelper";
import { bridgeItemToItemDescriptor } from "./PictureEditorOverlay";
import { tryParsePictureRawValue } from "../pictureRawValue";
import { AiImageEditorDialog } from "../ai-image-editor";
import { LicenseFeatures, useFeature } from "../../licensing";
import { Button } from "../../components/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger, } from "../../components/ui/tooltip";
import { measureBridgeFieldRect, rectEquals, } from "./overlay/geometry";
import { useOverlayMeasurement } from "./overlay/useOverlayMeasurement";
// Below this size the centered buttons no longer fit; the field keeps its
// hover-only editing via the PictureEditorOverlay.
const MIN_FIELD_WIDTH = 80;
const MIN_FIELD_HEIGHT = 40;
/**
 * Persistent affordance on empty image/picture fields: shows centered
 * "Select Image" / "Generate Image" buttons directly on the empty placeholder,
 * so the user can add or AI-generate an image without hovering first (the
 * hover-driven PictureEditorOverlay still provides the full edit menu on top).
 */
export function EmptyImageFieldIndicators({ pageViewContext, }) {
    const editContext = useEditContext();
    const editContextRef = useRef(editContext);
    useEffect(() => {
        editContextRef.current = editContext;
    }, [editContext]);
    const [targets, setTargets] = useState([]);
    const structureFields = pageViewContext?.bridgeStructure?.fields;
    const page = pageViewContext?.page;
    const pageItemDescriptor = pageViewContext?.pageItemDescriptor;
    useEffect(() => {
        let cancelled = false;
        const load = async () => {
            const ctx = editContextRef.current;
            if (!structureFields?.length || !ctx) {
                if (!cancelled)
                    setTargets([]);
                return;
            }
            // The bridge structure lists every rendered field; group them by item so
            // each item is loaded once (the repository caches lookups).
            const byItem = new Map();
            for (const structureField of structureFields) {
                if (structureField.editable === false)
                    continue;
                if (ctx.showLayoutComponents === false &&
                    structureField.componentId &&
                    page &&
                    getComponentById(structureField.componentId, page)?.layoutId) {
                    continue;
                }
                const item = bridgeItemToItemDescriptor(structureField.item, pageItemDescriptor || ctx.currentItemDescriptor);
                if (!item)
                    continue;
                const key = `${item.id}|${item.language}|${item.version}`;
                const entry = byItem.get(key) ?? { item, fieldIds: new Set() };
                entry.fieldIds.add(structureField.fieldId);
                byItem.set(key, entry);
            }
            const found = [];
            for (const { item, fieldIds } of byItem.values()) {
                const fullItem = await ctx.itemsRepository.getItem(item);
                if (!fullItem)
                    continue;
                for (const fieldId of fieldIds) {
                    const field = fullItem.fields.find((f) => f.id === fieldId);
                    if (!field || field.canWrite === false)
                        continue;
                    if (field.type === "image") {
                        if (isEmptyImageField(field)) {
                            found.push({ field: field });
                        }
                    }
                    else if (field.type === "picture") {
                        const pictureField = field;
                        if (!isEmptyPictureField(pictureField))
                            continue;
                        const variantName = getPictureVariantName(pictureField);
                        // Without a resolvable variant we cannot safely target a slot;
                        // leave those to the hover editor.
                        if (!variantName)
                            continue;
                        found.push({ field: pictureField, variantName });
                    }
                }
            }
            if (!cancelled)
                setTargets(found);
        };
        load().catch(() => {
            if (!cancelled)
                setTargets([]);
        });
        return () => {
            cancelled = true;
        };
    }, [structureFields, page, pageItemDescriptor]);
    if (!editContext || !pageViewContext || editContext.dragObject)
        return null;
    const runningActions = editContext.activeFieldActions ?? [];
    return (_jsx(_Fragment, { children: targets
            .filter(
        // Hide the buttons while an AI generation is running on that field —
        // the FieldActionIndicator shows a spinner there instead.
        ({ field }) => !runningActions.some((action) => action.state === "running" &&
            action.field.fieldId === field.descriptor.fieldId &&
            action.field.item.id === field.descriptor.item.id &&
            action.field.item.language === field.descriptor.item.language &&
            action.field.item.version === field.descriptor.item.version))
            .map(({ field, variantName }) => (_jsx(EmptyMediaFieldButtons, { field: field, variantName: variantName, pageViewContext: pageViewContext }, `${field.descriptor.item.id}|${field.descriptor.item.language}|${field.descriptor.item.version}|${field.descriptor.fieldId}`))) }));
}
function EmptyMediaFieldButtons({ field, variantName, pageViewContext, }) {
    const editContext = useEditContext();
    const canUseAi = useFeature(LicenseFeatures.AI);
    const [showAiEditor, setShowAiEditor] = useState(false);
    const bounds = useOverlayMeasurement((metrics) => measureBridgeFieldRect(pageViewContext.bridgeGeometry, pageViewContext.bridgeStructure, field.descriptor, metrics), [pageViewContext.bridgeGeometry, pageViewContext.bridgeStructure, field], {
        initialValue: null,
        equals: rectEquals,
        interests: ["viewport", "layout", "text", "adornment-data"],
    });
    const variant = field.type === "picture"
        ? field.value?.variants?.find((v) => v.name === variantName)
        : undefined;
    const handleSelect = useCallback(async () => {
        if (!editContext)
            return;
        if (field.type === "image") {
            const imageField = field;
            const id = await editContext.selectMedia({
                selectedIdPath: imageField.value?.idPath || "",
                mode: "images",
            });
            if (!id)
                return;
            await editContext.operations.editField({
                field: imageField.descriptor,
                rawValue: `<image mediaid="{${id}}" />`,
                refresh: "immediate",
            });
            return;
        }
        // Picture field: prefer the configured "Select" variant button so any
        // customer override applies; fall back to writing the JSON raw value.
        const pictureField = field;
        const configButton = editContext.configuration?.fieldTypes?.picture?.variantButtons?.find((b) => b.id === "select-image");
        if (configButton?.clientAction) {
            await configButton.clientAction({
                editContext,
                field: pictureField,
                variantName,
                variantData: variant,
            });
            return;
        }
        const id = await editContext.selectMedia({
            selectedIdPath: variant?.idPath || "",
            mode: "images",
        });
        if (!id)
            return;
        const raw = tryParsePictureRawValue(pictureField.rawValue) ?? { Variants: [] };
        const existing = raw.Variants.find((v) => v.Name === variantName);
        if (existing)
            existing.MediaId = id;
        else
            raw.Variants.push({ Name: variantName ?? "", MediaId: id });
        await editContext.operations.editField({
            field: pictureField.descriptor,
            rawValue: JSON.stringify(raw),
            refresh: "immediate",
        });
    }, [editContext, field, variantName, variant]);
    const handleAiComplete = useCallback((result) => {
        setShowAiEditor(false);
        if (result.success && editContext) {
            editContext.addFieldAction({
                field: field.descriptor,
                label: "AI Image Edit",
                state: "running",
                message: "Generating image...",
            });
        }
    }, [editContext, field.descriptor]);
    if (!editContext || !bounds)
        return null;
    if (bounds.width < MIN_FIELD_WIDTH || bounds.height < MIN_FIELD_HEIGHT) {
        return null;
    }
    const aiConfig = field.type === "picture"
        ? editContext.configuration?.fieldTypes?.picture?.aiImageEdit
        : editContext.configuration?.fieldTypes?.image?.aiImageEdit;
    const aiEnabled = canUseAi && aiConfig !== false;
    return (_jsxs("div", { className: "pointer-events-none absolute flex items-center justify-center", style: {
            left: bounds.x,
            top: bounds.y,
            width: bounds.width,
            height: bounds.height,
            zIndex: 780,
        }, "data-testid": "empty-media-field", children: [_jsxs("div", { className: "pointer-events-auto flex items-center justify-center gap-2", onMouseDown: (e) => e.stopPropagation(), children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { size: "iconSm", variant: "default", "aria-label": "Select Image", "data-testid": "empty-media-select", onClick: (e) => {
                                        e.stopPropagation();
                                        handleSelect();
                                    }, children: _jsx(ImagePlus, { strokeWidth: 1.5 }) }) }), _jsx(TooltipContent, { children: "Select Image" })] }), aiEnabled && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { size: "iconSm", variant: "outline", "aria-label": "Generate Image", "data-testid": "empty-media-generate", onClick: (e) => {
                                        e.stopPropagation();
                                        setShowAiEditor(true);
                                    }, children: _jsx(Sparkles, { strokeWidth: 1.5 }) }) }), _jsx(TooltipContent, { children: "Generate Image" })] }))] }), canUseAi && showAiEditor && (_jsx(AiImageEditorDialog, { open: showAiEditor, onClose: () => setShowAiEditor(false), onComplete: handleAiComplete, fieldDescriptor: field.descriptor, originalRawValue: field.rawValue || "", variantName: field.type === "picture" ? variantName : undefined, currentImageSrc: variant?.originalSrc || variant?.src, currentMediaItemId: variant?.mediaId }))] }));
}
function getPictureVariantName(field) {
    return field.value?.variants?.find((v) => v.name)?.name;
}
function isEmptyImageField(field) {
    if (field.value?.src)
        return false;
    if (!field.rawValue)
        return true;
    try {
        const xmlDoc = new DOMParser().parseFromString(field.rawValue, "text/xml");
        const imageElement = xmlDoc.documentElement;
        return (!imageElement.getAttribute("src") && !imageElement.getAttribute("mediaid"));
    }
    catch {
        return true;
    }
}
function isEmptyPictureField(field) {
    if (field.value?.variants?.some((v) => v.src))
        return false;
    // The value may not be resolved yet; treat a raw MediaId as "has image".
    const raw = tryParsePictureRawValue(field.rawValue);
    if (raw?.Variants?.some((v) => v.MediaId))
        return false;
    return true;
}
//# sourceMappingURL=EmptyImageFieldIndicators.js.map