import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useMemo, useRef, useState } from "react";
import { useEditContext } from "../client/editContext";
import { fieldKey, findComponentRectById, findFieldElements, getTextNodeAtOffset, resolveVersionDiffTargets, } from "../version-diff/versionDiffTargets";
import { versionDiffHighlightClasses } from "../version-diff/versionDiffHighlightStyles";
import { useSlotContext } from "../views/editorSlotContext";
export function VersionDiffHighlightings({ iframe, scale, pageViewContext, variant = "default", }) {
    const editContext = useEditContext();
    const slotContext = useSlotContext();
    const itemsRepository = editContext?.itemsRepository;
    const [targets, setTargets] = useState([]);
    const [componentTargets, setComponentTargets] = useState([]);
    const previousVersionCache = useRef(new Map());
    const compareToKey = [
        slotContext?.compareTo?.id,
        slotContext?.compareTo?.language,
        slotContext?.compareTo?.version,
    ].join("|");
    useEffect(() => {
        if (!itemsRepository || !iframe || !pageViewContext.page) {
            setTargets([]);
            setComponentTargets([]);
            return;
        }
        let cancelled = false;
        const resolveTargets = async () => {
            const nextTargets = await resolveVersionDiffTargets({
                iframe,
                pageItem: pageViewContext.page.item.descriptor,
                getItem: itemsRepository.getItem,
                baseline: slotContext?.compareMode
                    ? { type: "compare", compareTo: slotContext.compareTo }
                    : { type: "previous" },
                previousVersionCache: previousVersionCache.current,
            });
            if (cancelled)
                return;
            setTargets(nextTargets.fieldTargets);
            setComponentTargets(nextTargets.componentTargets);
        };
        resolveTargets();
        return () => {
            cancelled = true;
        };
    }, [
        itemsRepository,
        iframe,
        pageViewContext.page?.editRevision,
        pageViewContext.page?.item.id,
        pageViewContext.page?.item.language,
        pageViewContext.page?.item.version,
        itemsRepository?.revision,
        slotContext?.compareMode,
        compareToKey,
    ]);
    if (!iframe || (targets.length === 0 && componentTargets.length === 0))
        return null;
    return (_jsxs(_Fragment, { children: [componentTargets.map((target) => (_jsx(ComponentDiffHighlighting, { iframe: iframe, scale: scale, target: target, variant: variant }, target.id))), targets.map((target) => (_jsx(VersionDiffHighlighting, { iframe: iframe, scale: scale, target: target, variant: variant }, fieldKey(target.descriptor))))] }));
}
function ComponentDiffHighlighting({ iframe, scale, target, variant, }) {
    const [rect, setRect] = useState(null);
    useEffect(() => {
        const iframeDoc = iframe.contentWindow?.document;
        if (!iframeDoc?.body) {
            setRect(null);
            return;
        }
        let rafId = null;
        const calculateRect = () => {
            setRect(findComponentRectById(iframe, target.visualId));
        };
        const scheduleUpdate = () => {
            if (rafId != null)
                window.cancelAnimationFrame(rafId);
            rafId = window.requestAnimationFrame(() => {
                rafId = null;
                calculateRect();
            });
        };
        calculateRect();
        const scrollContainer = iframeDoc.scrollingElement || iframeDoc.body;
        const iframeWindow = iframe.contentWindow;
        scrollContainer?.addEventListener("scroll", scheduleUpdate, {
            passive: true,
        });
        iframeWindow?.addEventListener("scroll", scheduleUpdate, { passive: true });
        iframeWindow?.addEventListener("resize", scheduleUpdate);
        return () => {
            if (rafId != null)
                window.cancelAnimationFrame(rafId);
            scrollContainer?.removeEventListener("scroll", scheduleUpdate);
            iframeWindow?.removeEventListener("scroll", scheduleUpdate);
            iframeWindow?.removeEventListener("resize", scheduleUpdate);
        };
    }, [iframe, target.visualId]);
    if (!rect)
        return null;
    return (_jsx("div", { className: variant === "minimap"
            ? versionDiffHighlightClasses.componentMini
            : versionDiffHighlightClasses.component, style: {
            top: rect.top * scale,
            left: rect.left * scale,
            width: Math.max(rect.width * scale, 2),
            height: Math.max(rect.height * scale, 2),
        } }));
}
function VersionDiffHighlighting({ iframe, scale, target, variant, }) {
    const [rects, setRects] = useState([]);
    const ranges = useMemo(() => target.hasDeletionOnlyChange
        ? []
        : target.ranges.filter(([start, end]) => start < end), [target.hasDeletionOnlyChange, target.ranges]);
    useEffect(() => {
        const iframeDoc = iframe.contentWindow?.document;
        if (!iframeDoc?.body) {
            setRects([]);
            return;
        }
        let rafId = null;
        const calculateRects = () => {
            const elements = findFieldElements(iframe, target.descriptor);
            const nextRects = [];
            elements.forEach((element) => {
                if (target.hasDeletionOnlyChange) {
                    nextRects.push(element.getBoundingClientRect());
                    return;
                }
                ranges.forEach(([start, end]) => {
                    const startData = getTextNodeAtOffset(element, start);
                    const endData = getTextNodeAtOffset(element, end);
                    if (!startData || !endData)
                        return;
                    try {
                        const textRange = iframeDoc.createRange();
                        textRange.setStart(startData.node, startData.offset);
                        textRange.setEnd(endData.node, endData.offset);
                        nextRects.push(...Array.from(textRange.getClientRects()));
                    }
                    catch {
                        nextRects.push(element.getBoundingClientRect());
                    }
                });
            });
            setRects(nextRects);
        };
        const scheduleUpdate = () => {
            if (rafId != null)
                window.cancelAnimationFrame(rafId);
            rafId = window.requestAnimationFrame(() => {
                rafId = null;
                calculateRects();
            });
        };
        calculateRects();
        const scrollContainer = iframeDoc.scrollingElement || iframeDoc.body;
        const iframeWindow = iframe.contentWindow;
        scrollContainer?.addEventListener("scroll", scheduleUpdate, {
            passive: true,
        });
        iframeWindow?.addEventListener("scroll", scheduleUpdate, { passive: true });
        iframeWindow?.addEventListener("resize", scheduleUpdate);
        return () => {
            if (rafId != null)
                window.cancelAnimationFrame(rafId);
            scrollContainer?.removeEventListener("scroll", scheduleUpdate);
            iframeWindow?.removeEventListener("scroll", scheduleUpdate);
            iframeWindow?.removeEventListener("resize", scheduleUpdate);
        };
    }, [iframe, ranges, target]);
    if (rects.length === 0)
        return null;
    return (_jsx(_Fragment, { children: rects.map((rect, index) => (_jsx("div", { className: target.hasDeletionOnlyChange
                ? variant === "minimap"
                    ? versionDiffHighlightClasses.deletionOnlyMini
                    : versionDiffHighlightClasses.deletionOnly
                : variant === "minimap"
                    ? versionDiffHighlightClasses.textMini
                    : versionDiffHighlightClasses.text, style: {
                top: rect.top * scale,
                left: rect.left * scale,
                width: Math.max(rect.width * scale, 2),
                height: Math.max(rect.height * scale, 2),
            } }, index))) }));
}
//# sourceMappingURL=VersionDiffHighlightings.js.map