import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
import { useEditContext, useFieldsEditContext, } from "../client/editContext";
import { useFieldModification } from "../client/fieldModificationStore";
import { useCallback, useEffect, useLayoutEffect, useState } from "react";
export function FieldEditedIndicator({ field, scale, pageViewContext, scroll, }) {
    const editContext = useEditContext();
    const fieldsContext = useFieldsEditContext();
    if (!editContext)
        return null;
    const pageVersion = pageViewContext.pageItemDescriptor?.version;
    const isTargetingCurrentPageLatest = field.item.version === 0 &&
        field.item.id === pageViewContext.pageItemDescriptor?.id &&
        field.item.language === pageViewContext.pageItemDescriptor?.language;
    // Use a selector that can match either the specific version or version 0 (latest)
    const selector = isTargetingCurrentPageLatest
        ? `[data-fieldid="${field.fieldId}"][data-itemid="${field.item.id}"][data-language="${field.item.language}"]`
        : `[data-fieldid="${field.fieldId}"][data-itemid="${field.item.id}"][data-language="${field.item.language}"][data-version="${field.item.version}"]`;
    const fieldElements = pageViewContext.editorIframe?.contentWindow?.document.querySelectorAll(selector);
    if (!fieldElements)
        return null;
    return (_jsx(_Fragment, { children: [...fieldElements]
            .filter((x) => {
            if (x == fieldsContext?.inlineEditingFieldElement)
                return false;
            // Final filter for version matching
            const elVersion = parseInt(x.getAttribute("data-version") || "0", 10);
            if (field.item.version === 0) {
                // If update is for version 0, only show if element is version 0 OR matches current page version
                return elVersion === 0 || elVersion === pageVersion;
            }
            return elVersion === field.item.version;
        })
            .map((element, index) => (_jsx(SingleFieldEditedIndicator, { element: element, field: field, scale: scale, scroll: scroll }, field.fieldId + field.item.id + index))) }));
}
function SingleFieldEditedIndicator({ element, field, scale, scroll, }) {
    const { isSaved } = useFieldModification(field.fieldId, field.item.id, field.item.language, field.item.version);
    const readRect = useCallback(() => {
        const r = element.getBoundingClientRect();
        return { x: r.x, y: r.y, width: r.width, height: r.height };
    }, [element]);
    const [rect, setRect] = useState(() => readRect());
    const updateRect = useCallback(() => {
        const next = readRect();
        setRect((prev) => {
            if (prev.x === next.x &&
                prev.y === next.y &&
                prev.width === next.width &&
                prev.height === next.height) {
                return prev;
            }
            return next;
        });
    }, [readRect]);
    // Keep the indicator in sync with scroll/resize + content changes inside the iframe.
    useLayoutEffect(() => {
        updateRect();
    }, [updateRect, scale]);
    useEffect(() => {
        const win = element.ownerDocument?.defaultView;
        if (!win)
            return;
        let raf = 0;
        const schedule = () => {
            win.cancelAnimationFrame(raf);
            raf = win.requestAnimationFrame(updateRect);
        };
        // Scroll doesn't bubble; listening on the iframe window keeps the overlay aligned.
        win.addEventListener("scroll", schedule, { passive: true });
        win.addEventListener("resize", schedule, { passive: true });
        let ro;
        if (typeof win.ResizeObserver !== "undefined") {
            try {
                ro = new win.ResizeObserver(schedule);
                if (element instanceof win.HTMLElement) {
                    ro?.observe(element);
                }
            }
            catch {
                // ignore observer failures (older browsers / cross-realm issues)
            }
        }
        // Agent/translation updates can change layout shortly after the DOM update
        // (fonts, hydration, layout reflow). Do a short re-measure burst.
        let burstRaf = 0;
        const start = Date.now();
        const tick = () => {
            schedule();
            if (Date.now() - start < 1000) {
                burstRaf = win.requestAnimationFrame(tick);
            }
        };
        // Initial sync (post-mount)
        schedule();
        tick();
        return () => {
            win.cancelAnimationFrame(raf);
            win.cancelAnimationFrame(burstRaf);
            win.removeEventListener("scroll", schedule);
            win.removeEventListener("resize", schedule);
            ro?.disconnect();
        };
    }, [element, updateRect, field.timestamp]);
    const indicatorRect = rect;
    // Logic: 
    // If isSaved is false (isDirty is true), show saving (Yellow/Purple)
    // If isSaved is true, show saved (Green)
    const stateClass = isSaved ? "saved" : "saving";
    return (_jsx("div", { className: `focus-shadow edited-field ${stateClass} pointer-events-none absolute`, style: {
            left: indicatorRect.x * (scale || 1),
            top: (indicatorRect.y + (scroll || 0)) * (scale || 1),
            width: indicatorRect.width * (scale || 1),
            height: indicatorRect.height * (scale || 1),
            zIndex: 800,
        } }));
}
//# sourceMappingURL=FieldEditedIndicator.js.map