import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
import { useEffect, useMemo, useRef, useState } from "react";
import { useEditContext } from "../client/editContext";
import { fieldKey, findComponentRectById, findFieldElements, resolveVersionDiffTargets, } from "../version-diff/versionDiffTargets";
import { versionDiffHighlightClasses } from "../version-diff/versionDiffHighlightStyles";
import { useSlotContext } from "../views/editorSlotContext";
import { measureElementRect, measureTextRangeRects, rectListEquals, toOverlayRect, } from "./overlay/geometry";
import { getAccessibleIframeDocument } from "./overlay/iframeAccess";
import { useOverlayMeasurement } from "./overlay/useOverlayMeasurement";
function measuredDiffHighlightsEqual(previous, next) {
    if (previous.length !== next.length)
        return false;
    for (let i = 0; i < previous.length; i++) {
        const previousItem = previous[i];
        const nextItem = next[i];
        if (previousItem.key !== nextItem.key ||
            previousItem.className !== nextItem.className ||
            !rectListEquals(previousItem.rects, nextItem.rects)) {
            return false;
        }
    }
    return true;
}
export function VersionDiffHighlightings({ iframe, 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,
    ]);
    const rangesByTargetKey = useMemo(() => new Map(targets.map((target) => [
        fieldKey(target.descriptor),
        target.hasDeletionOnlyChange
            ? []
            : target.ranges.filter(([start, end]) => start < end),
    ])), [targets]);
    const highlights = useOverlayMeasurement((metrics) => {
        if (!iframe)
            return [];
        const iframeDoc = getAccessibleIframeDocument(iframe);
        if (!iframeDoc?.body)
            return [];
        const measured = [];
        for (const target of componentTargets) {
            const rect = findComponentRectById(iframe, target.visualId);
            if (!rect)
                continue;
            measured.push({
                key: `component-${target.id}`,
                className: variant === "minimap"
                    ? versionDiffHighlightClasses.componentMini
                    : versionDiffHighlightClasses.component,
                rects: [toOverlayRect(rect, metrics)],
            });
        }
        for (const target of targets) {
            const targetKey = fieldKey(target.descriptor);
            const rects = [];
            const elements = findFieldElements(iframe, target.descriptor);
            elements.forEach((element) => {
                if (target.hasDeletionOnlyChange) {
                    const rect = measureElementRect(element, metrics);
                    if (rect)
                        rects.push(rect);
                    return;
                }
                const ranges = rangesByTargetKey.get(targetKey) || [];
                ranges.forEach(([start, end]) => {
                    const rangeRects = measureTextRangeRects(iframeDoc, element, start, end, metrics);
                    if (rangeRects.length > 0) {
                        rects.push(...rangeRects);
                        return;
                    }
                    const fallbackRect = measureElementRect(element, metrics);
                    if (fallbackRect)
                        rects.push(fallbackRect);
                });
            });
            if (rects.length === 0)
                continue;
            measured.push({
                key: targetKey,
                className: target.hasDeletionOnlyChange
                    ? variant === "minimap"
                        ? versionDiffHighlightClasses.deletionOnlyMini
                        : versionDiffHighlightClasses.deletionOnly
                    : variant === "minimap"
                        ? versionDiffHighlightClasses.textMini
                        : versionDiffHighlightClasses.text,
                rects,
            });
        }
        return measured;
    }, [iframe, targets, componentTargets, rangesByTargetKey, variant], {
        initialValue: [],
        equals: measuredDiffHighlightsEqual,
        interests: ["viewport", "layout", "text", "adornment-data"],
    });
    if (!iframe || highlights.length === 0)
        return null;
    return (_jsx(_Fragment, { children: highlights.flatMap((highlight) => highlight.rects.map((rect, index) => (_jsx("div", { className: highlight.className, style: {
                top: rect.y,
                left: rect.x,
                width: Math.max(rect.width, 2),
                height: Math.max(rect.height, 2),
            } }, `${highlight.key}-${index}`)))) }));
}
//# sourceMappingURL=VersionDiffHighlightings.js.map