import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { Dialog, DialogContent } from "../components/ui/dialog";
import { StyledDialogTitle } from "../components/ui/styled-dialog-title";
import { useEditContext } from "./client/editContext";
import { useEffect, useRef, useState } from "react";
import { Button } from "../components/ui/button";
import DialogButtons from "./ui/DialogButtons";
import { cn } from "../lib/utils";
import { Crop, RotateCcw } from "lucide-react";
import { SimpleTabs } from "./ui/SimpleTabs";
import { AspectRatioSelector } from "./AspectRatioSelector";
import { toast } from "sonner";
import { tryParsePictureRawValue } from "./pictureRawValue";
export function PictureCropper({ field, onClose, variantName: initialVariantName, }) {
    const [pictureValue, setPictureValue] = useState();
    const [isValid, setIsValid] = useState(true);
    const [rawValue, setRawValue] = useState();
    const [actualImageDimensions, setActualImageDimensions] = useState(null);
    const [activeTabIndex, setActiveTabIndex] = useState(0);
    // Track selected aspect ratio for each variant
    const [selectedAspectRatio, setSelectedAspectRatio] = useState(null);
    // Track crop rectangles for each variant separately
    const [variantRects, setVariantRects] = useState(new Map());
    // Cache image dimensions by URL to avoid showing loading indicator for already loaded images
    const imageDimensionsCache = useRef(new Map());
    const imageRef = useRef(null);
    const onCloseRef = useRef(onClose);
    const initialTabAppliedRef = useRef(false);
    const dragBoundsRef = useRef(null);
    const pendingRectRenderRef = useRef(undefined);
    const rectRenderFrameRef = useRef(null);
    const [rect, setRect] = useState();
    const rectRef = useRef(rect);
    const movingRef = useRef(false);
    const startPosRef = useRef({
        x: 0,
        y: 0,
    });
    const offset = useRef({ x: 0, y: 0 });
    const editContext = useEditContext();
    const EDGE_THRESHOLD = 10; // pixels from edge to detect resize
    const [resizeEdge, setResizeEdge] = useState(null);
    const resizeEdgeRef = useRef(null);
    useEffect(() => {
        onCloseRef.current = onClose;
    }, [onClose]);
    useEffect(() => {
        return () => {
            if (rectRenderFrameRef.current !== null) {
                window.cancelAnimationFrame(rectRenderFrameRef.current);
            }
        };
    }, []);
    const buildRawValueFromVariantRects = () => {
        if (!rawValue || !pictureValue?.variants) {
            return rawValue;
        }
        const nextRawValue = JSON.parse(JSON.stringify(rawValue));
        const nextVariantRects = new Map(variantRects);
        if (selectedVariantName) {
            nextVariantRects.set(selectedVariantName, rectRef.current);
        }
        for (const variant of pictureValue.variants) {
            const variantName = variant.name;
            const variantRect = nextVariantRects.get(variantName);
            let rawVariant = nextRawValue.Variants?.find((x) => x.Name == variantName);
            if (!rawVariant) {
                rawVariant = {
                    Name: variantName,
                    MediaId: variant.mediaId,
                };
                if (!nextRawValue.Variants) {
                    nextRawValue.Variants = [];
                }
                nextRawValue.Variants.push(rawVariant);
            }
            rawVariant.Region = variantRect
                ? {
                    X: variantRect.x,
                    Y: variantRect.y,
                    Width: variantRect.width,
                    Height: variantRect.height,
                }
                : undefined;
        }
        return nextRawValue;
    };
    // Helper function to create default region for aspect ratio locked variants
    const createDefaultRegion = (aspectRatio = selectedAspectRatio) => {
        if (!aspectRatio || !actualImageDimensions) {
            return undefined;
        }
        // Always use the actual loaded image dimensions for aspect ratio calculations
        const sourceWidth = actualImageDimensions.width;
        const sourceHeight = actualImageDimensions.height;
        const sourceAspectRatio = sourceHeight > 0 ? sourceWidth / sourceHeight : 1;
        const targetAspectRatio = aspectRatio;
        // Calculate maximum size that fits the target aspect ratio within the source image
        let width = 1.0; // Start with full width
        let height = (width / targetAspectRatio) * sourceAspectRatio;
        // If height exceeds bounds, start with full height instead
        if (height > 1.0) {
            height = 1.0;
            width = (height * targetAspectRatio) / sourceAspectRatio;
        }
        // Center the rectangle
        const x = (1.0 - width) / 2;
        const y = (1.0 - height) / 2;
        return { x, y, width, height };
    };
    const getResizeEdge = (pos, rect, bounds) => {
        if (!rect || !bounds)
            return null;
        const x = pos.x * bounds.width;
        const y = pos.y * bounds.height;
        const rectX = rect.x * bounds.width;
        const rectY = rect.y * bounds.height;
        const rectWidth = rect.width * bounds.width;
        const rectHeight = rect.height * bounds.height;
        const isNearLeft = Math.abs(x - rectX) < EDGE_THRESHOLD;
        const isNearRight = Math.abs(x - (rectX + rectWidth)) < EDGE_THRESHOLD;
        const isNearTop = Math.abs(y - rectY) < EDGE_THRESHOLD;
        const isNearBottom = Math.abs(y - (rectY + rectHeight)) < EDGE_THRESHOLD;
        if (isNearLeft && isNearTop)
            return "nw";
        if (isNearRight && isNearTop)
            return "ne";
        if (isNearLeft && isNearBottom)
            return "sw";
        if (isNearRight && isNearBottom)
            return "se";
        if (isNearLeft)
            return "w";
        if (isNearRight)
            return "e";
        if (isNearTop)
            return "n";
        if (isNearBottom)
            return "s";
        return null;
    };
    useEffect(() => {
        const deepCopy = JSON.parse(JSON.stringify(field.value));
        setPictureValue(deepCopy);
        const raw = tryParsePictureRawValue(field.rawValue);
        if (!raw) {
            toast.warning("Crop isn't available while this picture field is stored as a basic image value.");
            onCloseRef.current();
            return;
        }
        setRawValue(raw);
    }, [field]);
    // Set initial tab based on the provided variant name
    useEffect(() => {
        if (!initialTabAppliedRef.current &&
            pictureValue?.variants &&
            initialVariantName) {
            const initialIndex = pictureValue.variants.findIndex((variant) => variant.name === initialVariantName);
            if (initialIndex >= 0) {
                setActiveTabIndex(initialIndex);
                initialTabAppliedRef.current = true;
            }
        }
    }, [pictureValue, initialVariantName]);
    const selectedVariant = pictureValue &&
        pictureValue.variants &&
        pictureValue.variants[activeTabIndex]
        ? pictureValue.variants[activeTabIndex]
        : null;
    const selectedVariantName = selectedVariant?.name || "";
    const commitVariantRect = (nextRect = rectRef.current) => {
        if (!selectedVariantName)
            return;
        setVariantRects((prev) => new Map(prev).set(selectedVariantName, nextRect));
    };
    const renderRect = (nextRect, immediate) => {
        if (immediate) {
            if (rectRenderFrameRef.current !== null) {
                window.cancelAnimationFrame(rectRenderFrameRef.current);
                rectRenderFrameRef.current = null;
            }
            pendingRectRenderRef.current = undefined;
            setRect(nextRect);
            return;
        }
        pendingRectRenderRef.current = nextRect;
        if (rectRenderFrameRef.current !== null)
            return;
        rectRenderFrameRef.current = window.requestAnimationFrame(() => {
            rectRenderFrameRef.current = null;
            const pendingRect = pendingRectRenderRef.current;
            pendingRectRenderRef.current = undefined;
            setRect(pendingRect);
        });
    };
    const updateRect = (nextRect, commit = false, immediate = true) => {
        rectRef.current = nextRect;
        renderRect(nextRect, immediate);
        if (commit) {
            commitVariantRect(nextRect);
        }
    };
    // Update selected aspect ratio when switching variants
    useEffect(() => {
        if (selectedVariant) {
            // If variant has locked aspect ratio, use that
            if (selectedVariant.aspectRatioLock) {
                setSelectedAspectRatio(selectedVariant.aspectRatioLock);
            }
            else {
                // Default to free form if no lock
                setSelectedAspectRatio(null);
            }
        }
    }, [selectedVariant]);
    // Manage image dimensions when the image source changes between variants
    const currentImageSrc = selectedVariant?.originalSrc ?? selectedVariant?.src;
    const previousImageSrcRef = useRef(undefined);
    useEffect(() => {
        if (currentImageSrc && currentImageSrc !== previousImageSrcRef.current) {
            // Check if we have cached dimensions for this image
            const cachedDimensions = imageDimensionsCache.current.get(currentImageSrc);
            if (cachedDimensions) {
                setActualImageDimensions(cachedDimensions);
            }
            else {
                // Only reset to null if we don't have cached dimensions
                setActualImageDimensions(null);
            }
            previousImageSrcRef.current = currentImageSrc;
        }
    }, [currentImageSrc]);
    // Load crop rectangle when switching variants
    useEffect(() => {
        if (!selectedVariantName)
            return;
        // Check if we have a current working rect for this variant
        const existingRect = variantRects.get(selectedVariantName);
        // If we have a valid rect, use it
        if (existingRect !== undefined) {
            updateRect(existingRect);
            return;
        }
        // Initialize rect for this variant if not already done
        let initialRect;
        // Try to load from saved region if this variant hasn't been touched yet
        if (selectedVariant?.region &&
            (!selectedAspectRatio ||
                Math.abs(selectedAspectRatio -
                    (selectedVariant.region.width * selectedVariant.width) /
                        (selectedVariant.region.height * selectedVariant.height)) < 0.1) &&
            selectedVariant.region.width > 0 &&
            selectedVariant.region.height > 0) {
            initialRect = {
                width: selectedVariant.region.width,
                height: selectedVariant.region.height,
                y: selectedVariant.region.y,
                x: selectedVariant.region.x,
            };
        }
        else {
            // Try to create a default region if aspect ratio is locked
            initialRect = createDefaultRegion();
        }
        // Store in variantRects and set as current rect
        setVariantRects((prev) => new Map(prev).set(selectedVariantName, initialRect));
        updateRect(initialRect);
    }, [selectedVariant, selectedVariantName]);
    // Create default region when image dimensions become available
    useEffect(() => {
        if (selectedVariant &&
            actualImageDimensions &&
            !selectedVariant?.region &&
            selectedAspectRatio) {
            const workingRect = variantRects.get(selectedVariant.name);
            if (workingRect !== undefined || rectRef.current !== undefined) {
                return;
            }
            const defaultRect = createDefaultRegion();
            setVariantRects((prev) => new Map(prev).set(selectedVariant.name, defaultRect));
            updateRect(defaultRect);
        }
    }, [
        actualImageDimensions,
        selectedVariant,
        selectedAspectRatio,
        variantRects,
    ]);
    useEffect(() => {
        if (!rect) {
            setIsValid(true);
            return;
        }
        if ((selectedVariant?.minWidth && selectedVariant.minWidth > widthPx) ||
            (selectedVariant?.minHeight && selectedVariant?.minHeight > heightPx)) {
            setIsValid(false);
        }
        else
            setIsValid(true);
    }, [rect]);
    const handleMouseMove = (ev) => {
        if (!selectedVariant)
            return null;
        const bounds = ev.buttons === 1
            ? (dragBoundsRef.current ?? imageRef.current?.getBoundingClientRect())
            : imageRef.current?.getBoundingClientRect();
        if (!bounds)
            return;
        const pos = {
            x: (ev.clientX - bounds.left) / bounds.width,
            y: (ev.clientY - bounds.top) / bounds.height,
        };
        // Update cursor on hover (when not dragging)
        if (ev.buttons !== 1) {
            const edge = getResizeEdge(pos, rect, bounds);
            setResizeEdge(edge);
            return;
        }
        if (ev.buttons === 1) {
            if (!rectRef.current || !imageRef.current)
                return;
            const rect = rectRef.current;
            const deltaX = ev.clientX - startPosRef.current.x;
            const deltaY = ev.clientY - startPosRef.current.y;
            if (resizeEdgeRef.current) {
                const pos = {
                    x: (ev.clientX - bounds.left) / bounds.width,
                    y: (ev.clientY - bounds.top) / bounds.height,
                };
                let newRect = { ...rect };
                const aspectRatio = selectedAspectRatio;
                const sourceWidth = actualImageDimensions?.width || 0;
                const sourceHeight = actualImageDimensions?.height || 0;
                const sourceAspectRatio = sourceHeight > 0 ? sourceWidth / sourceHeight : 1;
                // Handle resize based on edge - structure to avoid conflicts between corner handles
                if (resizeEdgeRef.current === "w") {
                    // Pure west edge - resize from left, keep right edge fixed
                    const rightEdge = rect.x + rect.width;
                    const newWidth = Math.max(0.01, rightEdge - pos.x);
                    newRect.width = newWidth;
                    newRect.x = rightEdge - newWidth;
                    if (aspectRatio) {
                        const newHeight = (newWidth / aspectRatio) * sourceAspectRatio;
                        const centerY = rect.y + rect.height / 2;
                        newRect.y = centerY - newHeight / 2;
                        newRect.height = newHeight;
                    }
                }
                else if (resizeEdgeRef.current === "e") {
                    // Pure east edge - resize from right, keep left edge fixed
                    const newWidth = pos.x - rect.x;
                    if (newWidth > 0) {
                        newRect.width = newWidth;
                        if (aspectRatio) {
                            const newHeight = (newWidth / aspectRatio) * sourceAspectRatio;
                            const centerY = rect.y + rect.height / 2;
                            newRect.y = centerY - newHeight / 2;
                            newRect.height = newHeight;
                        }
                    }
                }
                else if (resizeEdgeRef.current === "n") {
                    // Pure north edge - resize from top, keep bottom edge fixed
                    const bottomEdge = rect.y + rect.height;
                    const newHeight = bottomEdge - pos.y;
                    if (newHeight > 0) {
                        newRect.height = newHeight;
                        newRect.y = pos.y;
                        if (aspectRatio) {
                            const newWidth = (newHeight * aspectRatio) / sourceAspectRatio;
                            const centerX = rect.x + rect.width / 2;
                            newRect.x = centerX - newWidth / 2;
                            newRect.width = newWidth;
                        }
                    }
                }
                else if (resizeEdgeRef.current === "s") {
                    // Pure south edge - resize from bottom, keep top edge fixed
                    const newHeight = pos.y - rect.y;
                    if (newHeight > 0) {
                        newRect.height = newHeight;
                        if (aspectRatio) {
                            const newWidth = (newHeight * aspectRatio) / sourceAspectRatio;
                            const centerX = rect.x + rect.width / 2;
                            newRect.x = centerX - newWidth / 2;
                            newRect.width = newWidth;
                        }
                    }
                }
                else if (resizeEdgeRef.current.includes("w") &&
                    resizeEdgeRef.current.includes("n")) {
                    // Northwest corner - keep southeast corner fixed
                    const rightEdge = rect.x + rect.width;
                    const bottomEdge = rect.y + rect.height;
                    const newWidth = Math.max(0.01, rightEdge - pos.x);
                    const newHeight = Math.max(0.01, bottomEdge - pos.y);
                    newRect.width = newWidth;
                    newRect.height = newHeight;
                    newRect.x = rightEdge - newWidth;
                    newRect.y = bottomEdge - newHeight;
                    if (aspectRatio) {
                        // Use mouse movement direction to determine primary dimension
                        if (Math.abs(deltaX) > Math.abs(deltaY)) {
                            newRect.height = (newWidth / aspectRatio) * sourceAspectRatio;
                            newRect.y = bottomEdge - newRect.height;
                        }
                        else {
                            newRect.width = (newHeight * aspectRatio) / sourceAspectRatio;
                            newRect.x = rightEdge - newRect.width;
                        }
                    }
                }
                else if (resizeEdgeRef.current.includes("w") &&
                    resizeEdgeRef.current.includes("s")) {
                    // Southwest corner - keep northeast corner fixed
                    const rightEdge = rect.x + rect.width;
                    const newWidth = Math.max(0.01, rightEdge - pos.x);
                    const newHeight = Math.max(0.01, pos.y - rect.y);
                    newRect.width = newWidth;
                    newRect.height = newHeight;
                    newRect.x = rightEdge - newWidth;
                    if (aspectRatio) {
                        // Use mouse movement direction to determine primary dimension
                        if (Math.abs(deltaX) > Math.abs(deltaY)) {
                            newRect.height = (newWidth / aspectRatio) * sourceAspectRatio;
                        }
                        else {
                            newRect.width = (newHeight * aspectRatio) / sourceAspectRatio;
                            newRect.x = rightEdge - newRect.width;
                        }
                    }
                }
                else if (resizeEdgeRef.current.includes("e") &&
                    resizeEdgeRef.current.includes("n")) {
                    // Northeast corner - keep southwest corner fixed
                    const bottomEdge = rect.y + rect.height;
                    const newWidth = Math.max(0.01, pos.x - rect.x);
                    const newHeight = Math.max(0.01, bottomEdge - pos.y);
                    newRect.width = newWidth;
                    newRect.height = newHeight;
                    newRect.y = bottomEdge - newHeight;
                    if (aspectRatio) {
                        // Use mouse movement direction to determine primary dimension
                        if (Math.abs(deltaX) > Math.abs(deltaY)) {
                            newRect.height = (newWidth / aspectRatio) * sourceAspectRatio;
                            newRect.y = bottomEdge - newRect.height;
                        }
                        else {
                            newRect.width = (newHeight * aspectRatio) / sourceAspectRatio;
                        }
                    }
                }
                else if (resizeEdgeRef.current.includes("e") &&
                    resizeEdgeRef.current.includes("s")) {
                    // Southeast corner - keep northwest corner fixed
                    const newWidth = Math.max(0.01, pos.x - rect.x);
                    const newHeight = Math.max(0.01, pos.y - rect.y);
                    newRect.width = newWidth;
                    newRect.height = newHeight;
                    if (aspectRatio) {
                        // Use mouse movement direction to determine primary dimension
                        if (Math.abs(deltaX) > Math.abs(deltaY)) {
                            newRect.height = (newWidth / aspectRatio) * sourceAspectRatio;
                        }
                        else {
                            newRect.width = (newHeight * aspectRatio) / sourceAspectRatio;
                        }
                    }
                }
                // Constrain to bounds while maintaining aspect ratio
                // For west edge resizes, maintain the right edge position when hitting left bound
                if (newRect.x < 0) {
                    if (resizeEdgeRef.current?.includes("w")) {
                        const rightEdge = rect.x + rect.width; // Original right edge position
                        newRect.x = 0;
                        newRect.width = rightEdge; // Width = distance from left bound to original right edge
                        // Recalculate height if aspect ratio is locked
                        if (aspectRatio) {
                            const newHeight = (rightEdge / aspectRatio) * sourceAspectRatio;
                            if (resizeEdgeRef.current === "w") {
                                const centerY = rect.y + rect.height / 2;
                                newRect.y = centerY - newHeight / 2;
                            }
                            newRect.height = newHeight;
                        }
                    }
                    else {
                        newRect.x = 0;
                    }
                }
                // For north edge resizes, maintain the bottom edge position when hitting top bound
                if (newRect.y < 0) {
                    if (resizeEdgeRef.current?.includes("n")) {
                        const bottomEdge = rect.y + rect.height;
                        newRect.y = 0;
                        newRect.height = bottomEdge; // Keep bottom edge fixed
                        // Recalculate width if aspect ratio is locked
                        if (aspectRatio) {
                            const newWidth = (newRect.height * aspectRatio) / sourceAspectRatio;
                            if (resizeEdgeRef.current === "n") {
                                const centerX = rect.x + rect.width / 2;
                                newRect.x = centerX - newWidth / 2;
                            }
                            newRect.width = newWidth;
                        }
                    }
                    else {
                        newRect.y = 0;
                    }
                }
                // Apply bounds constraints and maintain aspect ratio
                let boundedRect = { ...newRect };
                if (boundedRect.x + boundedRect.width > 1) {
                    boundedRect.width = 1 - boundedRect.x;
                    // Re-apply aspect ratio if it was locked
                    if (aspectRatio) {
                        const newHeight = (boundedRect.width / aspectRatio) * sourceAspectRatio;
                        // Maintain anchoring behavior based on resize edge
                        if (resizeEdgeRef.current === "w" ||
                            resizeEdgeRef.current === "e") {
                            // For horizontal resizes, keep centered vertically
                            const centerY = rect.y + rect.height / 2;
                            boundedRect.y = centerY - newHeight / 2;
                        }
                        boundedRect.height = newHeight;
                    }
                }
                if (boundedRect.y + boundedRect.height > 1) {
                    boundedRect.height = 1 - boundedRect.y;
                    // Re-apply aspect ratio if it was locked
                    if (aspectRatio) {
                        const newWidth = (boundedRect.height * aspectRatio) / sourceAspectRatio;
                        // Maintain anchoring behavior based on resize edge
                        if (resizeEdgeRef.current === "n" ||
                            resizeEdgeRef.current === "s") {
                            // For vertical resizes, keep centered horizontally
                            const centerX = rect.x + rect.width / 2;
                            boundedRect.x = centerX - newWidth / 2;
                        }
                        boundedRect.width = newWidth;
                    }
                }
                // Final check - if aspect ratio re-calculation pushes us out of bounds again,
                // we need to find the maximum size that fits both constraints
                if (aspectRatio &&
                    (boundedRect.x + boundedRect.width > 1 ||
                        boundedRect.y + boundedRect.height > 1)) {
                    const maxWidth = 1 - boundedRect.x;
                    const maxHeight = 1 - boundedRect.y;
                    const maxHeightFromWidth = (maxWidth / aspectRatio) * sourceAspectRatio;
                    const maxWidthFromHeight = (maxHeight * aspectRatio) / sourceAspectRatio;
                    if (maxHeightFromWidth <= maxHeight) {
                        // Width is the limiting factor
                        boundedRect.width = maxWidth;
                        boundedRect.height = maxHeightFromWidth;
                        // Maintain anchoring for horizontal resizes
                        if (resizeEdgeRef.current === "w" ||
                            resizeEdgeRef.current === "e") {
                            const centerY = rect.y + rect.height / 2;
                            boundedRect.y = Math.max(0, Math.min(1 - boundedRect.height, centerY - boundedRect.height / 2));
                        }
                    }
                    else {
                        // Height is the limiting factor
                        boundedRect.height = maxHeight;
                        boundedRect.width = maxWidthFromHeight;
                        // Maintain anchoring for vertical resizes
                        if (resizeEdgeRef.current === "n" ||
                            resizeEdgeRef.current === "s") {
                            const centerX = rect.x + rect.width / 2;
                            boundedRect.x = Math.max(0, Math.min(1 - boundedRect.width, centerX - boundedRect.width / 2));
                        }
                    }
                }
                newRect = boundedRect;
                updateRect(newRect, false, false);
            }
            else if (movingRef.current) {
                updateRect({
                    ...rect,
                    x: Math.max(0, Math.min(1 - rectRef.current.width, (ev.clientX - bounds.left) / bounds.width - offset.current.x)),
                    y: Math.max(0, Math.min(1 - rectRef.current.height, (ev.clientY - bounds.top) / bounds.height - offset.current.y)),
                }, false, false);
            }
            else {
                const sourceWidth = actualImageDimensions?.width || 0;
                const sourceHeight = actualImageDimensions?.height || 0;
                const sourceAspectRatio = sourceHeight > 0 ? sourceWidth / sourceHeight : 1;
                const aspectRatio = selectedAspectRatio;
                const currentX = (ev.clientX - bounds.left) / bounds.width;
                const currentY = (ev.clientY - bounds.top) / bounds.height;
                const minX = Math.min(rect.x, currentX);
                const maxX = Math.max(rect.x, currentX);
                const minY = Math.min(rect.y, currentY);
                const maxY = Math.max(rect.y, currentY);
                let width = maxX - minX;
                let height = maxY - minY;
                if (aspectRatio) {
                    if (Math.abs(deltaX) > Math.abs(deltaY)) {
                        height = (width / aspectRatio) * sourceAspectRatio;
                    }
                    else {
                        width = (height * aspectRatio) / sourceAspectRatio;
                    }
                }
                // Apply bounds constraints and maintain aspect ratio
                if (aspectRatio) {
                    const maxWidth = 1 - minX;
                    const maxHeight = 1 - minY;
                    const maxHeightFromWidth = (maxWidth / aspectRatio) * sourceAspectRatio;
                    const maxWidthFromHeight = (maxHeight * aspectRatio) / sourceAspectRatio;
                    if (maxHeightFromWidth <= maxHeight) {
                        // Width is the limiting factor
                        if (width > maxWidth) {
                            width = maxWidth;
                            height = maxHeightFromWidth;
                        }
                    }
                    else {
                        // Height is the limiting factor
                        if (height > maxHeight) {
                            height = maxHeight;
                            width = maxWidthFromHeight;
                        }
                    }
                }
                else {
                    // No aspect ratio lock, just apply simple bounds
                    if (width + minX > 1) {
                        width = 1 - minX;
                    }
                    if (height + minY > 1) {
                        height = 1 - minY;
                    }
                }
                // Ensure final dimensions are non-negative
                width = Math.max(0, width);
                height = Math.max(0, height);
                const newRect = { x: minX, y: minY, width, height };
                updateRect(newRect, false, false);
            }
            ev.preventDefault();
            ev.stopPropagation();
        }
    };
    const handleMouseUp = () => {
        const finalRect = rectRef.current;
        if (!finalRect || !finalRect.width || !finalRect.height) {
            updateRect(undefined, true);
        }
        else {
            updateRect(finalRect, true);
        }
        movingRef.current = false;
        resizeEdgeRef.current = null;
        dragBoundsRef.current = null;
        setResizeEdge(null);
        // window.removeEventListener("mousemove", handleMouseMove);
        window.removeEventListener("mouseup", handleMouseUp);
    };
    const isInRect = (pos, rect) => {
        if (!rect || !selectedVariant)
            return false;
        return (pos.x >= rect.x &&
            pos.x <= rect.x + rect.width &&
            pos.y >= rect.y &&
            pos.y <= rect.y + rect.height);
    };
    const handleMouseDown = (ev) => {
        ev.preventDefault();
        ev.stopPropagation();
        const bounds = ev.currentTarget.getBoundingClientRect();
        dragBoundsRef.current = bounds;
        const pos = {
            x: (ev.clientX - bounds.left) / bounds.width,
            y: (ev.clientY - bounds.top) / bounds.height,
        };
        const edge = getResizeEdge(pos, rect, bounds);
        if (edge) {
            resizeEdgeRef.current = edge;
            setResizeEdge(edge);
        }
        else if (isInRect(pos, rect)) {
            movingRef.current = true;
            offset.current = {
                x: pos.x - rect.x,
                y: pos.y - rect.y,
            };
        }
        else {
            updateRect({
                x: (ev.clientX - bounds.left) / bounds.width,
                y: (ev.clientY - bounds.top) / bounds.height,
                width: 0,
                height: 0,
            }, false);
        }
        startPosRef.current = { x: ev.clientX, y: ev.clientY };
        window.addEventListener("mouseup", handleMouseUp);
    };
    if (!pictureValue?.variants || pictureValue.variants.length === 0) {
        return null;
    }
    // Create tabs for each variant
    const variantTabs = pictureValue.variants.map((variant, index) => ({
        id: `variant-${index}`,
        label: variant.name,
        content: null, // Content will be rendered separately
    }));
    const imageBounds = imageRef.current?.getBoundingClientRect();
    const sourceWidth = actualImageDimensions?.width || 0;
    const sourceHeight = actualImageDimensions?.height || 0;
    // For output dimensions, prefer variant dimensions if specified
    const outputWidth = selectedVariant?.width && selectedVariant.width > 0
        ? selectedVariant.width
        : sourceWidth;
    const outputHeight = selectedVariant?.height && selectedVariant.height > 0
        ? selectedVariant.height
        : sourceHeight;
    const scale = imageBounds && outputWidth > 0 ? outputWidth / imageBounds.width : 1;
    const widthPx = rect ? Math.round(rect.width * outputWidth) : 0;
    const heightPx = rect ? Math.round(rect.height * outputHeight) : 0;
    return (_jsx(_Fragment, { children: _jsx(Dialog, { open: true, onOpenChange: (open) => !open && onClose(), children: _jsxs(DialogContent, { className: "flex flex-col p-0", style: {
                    width: "85vw",
                    height: "85vh",
                    maxWidth: "none",
                    maxHeight: "none",
                }, children: [_jsx(StyledDialogTitle, { icon: _jsx(Crop, { strokeWidth: 1 }), title: "Crop image" }), _jsxs("div", { className: "justify flex h-full flex-col", children: [_jsxs("div", { className: "flex flex-1 gap-2", children: [_jsxs("div", { className: "flex w-72 flex-col gap-3 p-6 text-sm", children: [_jsx("div", { className: "mb-4", children: _jsx(SimpleTabs, { tabs: variantTabs, activeTab: activeTabIndex, setActiveTab: setActiveTabIndex, className: "border-border-default border-b text-xs", tabClassName: "flex-1 text-center" }) }), selectedVariant && (_jsxs(_Fragment, { children: [_jsx("div", { className: "mb-4", children: _jsx(AspectRatioSelector, { selectedRatio: selectedAspectRatio, onRatioChange: (ratio) => {
                                                                setSelectedAspectRatio(ratio);
                                                                // Reset the crop rect to default when aspect ratio changes
                                                                const defaultRect = createDefaultRegion(ratio);
                                                                updateRect(defaultRect, true);
                                                            }, lockedRatio: selectedVariant.aspectRatioLock }) }), _jsx(LabelAndValue, { label: "Image Dimensions", value: selectedVariant.width > 0 &&
                                                            selectedVariant.height > 0 ? (_jsxs(_Fragment, { children: [selectedVariant.width, " x ", selectedVariant.height] })) : actualImageDimensions ? (_jsxs(_Fragment, { children: [actualImageDimensions.width, " x", " ", actualImageDimensions.height, " (actual)"] })) : (_jsx("span", { className: "text-neutral-grey-50", children: "Loading..." })) }), selectedVariant.minWidth && (_jsx(LabelAndValue, { label: "Minimum Width:", value: selectedVariant.minWidth })), selectedVariant.minHeight && (_jsx(LabelAndValue, { label: "Minimum Height:", value: selectedVariant.minHeight })), rect && (_jsxs(_Fragment, { children: [_jsx(LabelAndValue, { label: "Selection", value: _jsxs(_Fragment, { children: [widthPx, " x ", heightPx] }) }), selectedVariant.minWidth &&
                                                                widthPx < selectedVariant.minWidth && (_jsx("div", { className: "text-feedback-red", children: "Minimum width not met!" })), selectedVariant.minHeight &&
                                                                heightPx < selectedVariant.minHeight && (_jsx("div", { className: "text-feedback-red", children: "Minimum height not met!" }))] }))] }))] }), _jsx("div", { className: "bg-neutral-grey-5 relative flex-1", children: selectedVariant && (_jsxs("div", { className: "absolute inset-3 flex items-center justify-center select-none", children: [!actualImageDimensions && (_jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "text-neutral-grey-50", children: "Loading image..." }) })), !actualImageDimensions && (_jsx("img", { className: "pointer-events-none absolute opacity-0", src: selectedVariant.originalSrc ?? selectedVariant.src, onLoad: (e) => {
                                                        const img = e.target;
                                                        const dimensions = {
                                                            width: img.naturalWidth,
                                                            height: img.naturalHeight,
                                                        };
                                                        // Cache the dimensions for this image URL
                                                        const imgSrc = selectedVariant.originalSrc ?? selectedVariant.src;
                                                        if (imgSrc) {
                                                            imageDimensionsCache.current.set(imgSrc, dimensions);
                                                        }
                                                        setActualImageDimensions(dimensions);
                                                    } })), actualImageDimensions && (_jsxs("div", { ref: imageRef, "data-testid": "picture-cropper-image", className: "relative max-h-full cursor-crosshair", style: {
                                                        aspectRatio: `${sourceWidth}/${sourceHeight}`,
                                                    }, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, children: [_jsx("img", { className: "max-h-full max-w-full object-scale-down", src: selectedVariant.originalSrc ?? selectedVariant.src }), rect && (_jsxs(_Fragment, { children: [_jsx("div", { className: "bg-neutral-grey-100/40 pointer-events-none absolute inset-0", style: {
                                                                        clipPath: `polygon(0% 0%, 0% 100%, ${rect.x * 100}% 100%, ${rect.x * 100}% ${rect.y * 100}%, ${(rect.x + rect.width) * 100}% ${rect.y * 100}%, ${(rect.x + rect.width) * 100}% ${(rect.y + rect.height) * 100}%, ${rect.x * 100}% ${(rect.y + rect.height) * 100}%, ${rect.x * 100}% 100%, 100% 100%, 100% 0%)`,
                                                                    } }), _jsxs("div", { "data-testid": "picture-cropper-rect", className: cn("absolute cursor-move border-2 border-dashed", isValid
                                                                        ? "border-highlight-100"
                                                                        : "border-feedback-red"), style: {
                                                                        left: rect.x * 100 + "%",
                                                                        top: rect.y * 100 + "%",
                                                                        width: rect.width * 100 + "%",
                                                                        height: rect.height * 100 + "%",
                                                                        cursor: resizeEdge
                                                                            ? resizeEdge.length === 1
                                                                                ? `${resizeEdge}-resize`
                                                                                : `${resizeEdge}-resize`
                                                                            : "move",
                                                                    }, children: [_jsx("div", { className: "absolute -top-1.5 -left-1.5 h-3 w-3 cursor-nw-resize rounded-full bg-white/90 shadow-lg" }), _jsx("div", { className: "absolute -top-1.5 -right-1.5 h-3 w-3 cursor-ne-resize rounded-full bg-white/90 shadow-lg" }), _jsx("div", { className: "absolute -bottom-1.5 -left-1.5 h-3 w-3 cursor-sw-resize rounded-full bg-white/90 shadow-lg" }), _jsx("div", { className: "absolute -right-1.5 -bottom-1.5 h-3 w-3 cursor-se-resize rounded-full bg-white/90 shadow-lg" }), _jsx("div", { className: "absolute -top-1.5 left-1/2 h-3 w-3 -translate-x-1/2 transform cursor-n-resize rounded-full bg-white/90 shadow-lg" }), _jsx("div", { className: "absolute -bottom-1.5 left-1/2 h-3 w-3 -translate-x-1/2 transform cursor-s-resize rounded-full bg-white/90 shadow-lg" }), _jsx("div", { className: "absolute top-1/2 -left-1.5 h-3 w-3 -translate-y-1/2 transform cursor-w-resize rounded-full bg-white/90 shadow-lg" }), _jsx("div", { className: "absolute top-1/2 -right-1.5 h-3 w-3 -translate-y-1/2 transform cursor-e-resize rounded-full bg-white/90 shadow-lg" }), rect.width > 0.05 && (_jsxs("div", { className: cn("absolute right-1 bottom-1 rounded p-2 text-xs text-nowrap", isValid
                                                                                ? "bg-neutral-grey-100/40 text-white"
                                                                                : "bg-feedback-red/40 text-white"), children: [widthPx, " x ", heightPx] }))] })] }))] }))] })) })] }), _jsxs(DialogButtons, { children: [_jsx(Button, { onClick: onClose, variant: "ghost", children: "Cancel" }), _jsxs(Button, { onClick: () => {
                                            // If there's an aspect ratio lock, restore the default centered, maximum-sized region
                                            const defaultRect = createDefaultRegion();
                                            updateRect(defaultRect, true);
                                        }, variant: "outline", children: [_jsx(RotateCcw, { strokeWidth: 1 }), "Reset"] }), _jsx(Button, { disabled: !isValid, onClick: async () => {
                                            if (pictureValue && field) {
                                                const nextRawValue = buildRawValueFromVariantRects();
                                                if (!nextRawValue) {
                                                    return;
                                                }
                                                setRawValue(nextRawValue);
                                                await editContext?.operations.editField({
                                                    field: field.descriptor,
                                                    rawValue: JSON.stringify(nextRawValue),
                                                    refresh: "immediate",
                                                });
                                            }
                                            onClose();
                                        }, children: "Save" })] })] })] }) }) }));
}
function LabelAndValue({ label, value, }) {
    return (_jsxs("div", { children: [_jsx("div", { className: "font-medium", children: label }), _jsx("div", { className: "text-xs font-light", children: value })] }));
}
//# sourceMappingURL=PictureCropper.js.map