/**
 * ImageZoom – zoom on hover and click (Amazon-style magnifier + lightbox)
 *
 * Supports three zoom modes:
 * - hover: Magnified view in a separate panel on the right (Amazon style)
 * - lens: Magnifying glass that follows cursor
 * - click: Full-screen lightbox modal
 */
import React, { useState, useRef, useCallback, useEffect } from "react";
import { createPortal } from "react-dom";
import { clsx } from "clsx";
import { ensureSeekoraStyles } from "../../styles/inject";
export function ImageZoom({ src, alt = "", mode = "both", zoomLevel = 2.5, className, style, showZoomIndicator = true, lensSize = 150, zoomPanelSize = { width: 400, height: 400 }, images, currentIndex = 0, }) {
    useEffect(() => {
        ensureSeekoraStyles();
    }, []);
    const [isHovering, setIsHovering] = useState(false);
    const [isLightboxOpen, setIsLightboxOpen] = useState(false);
    const [lightboxIndex, setLightboxIndex] = useState(currentIndex);
    const [cursorPos, setCursorPos] = useState({ x: 0, y: 0 });
    const [imageLoaded, setImageLoaded] = useState(false);
    const [touchStart, setTouchStart] = useState(null);
    const [touchEnd, setTouchEnd] = useState(null);
    const imageRef = useRef(null);
    const containerRef = useRef(null);
    const allImages = images && images.length > 0 ? images : [src];
    const hasMultipleImages = allImages.length > 1;
    // Minimum swipe distance (in px) to trigger navigation
    const minSwipeDistance = 50;
    const supportsHover = mode === "hover" || mode === "both";
    const supportsClick = mode === "click" || mode === "both";
    const supportsLens = mode === "lens";
    const handleMouseMove = useCallback((e) => {
        if (!containerRef.current)
            return;
        const rect = containerRef.current.getBoundingClientRect();
        const x = e.clientX - rect.left;
        const y = e.clientY - rect.top;
        setCursorPos({ x, y });
    }, []);
    const handleMouseEnter = useCallback(() => {
        setIsHovering(true);
    }, []);
    const handleMouseLeave = useCallback(() => {
        setIsHovering(false);
    }, []);
    const handleClick = useCallback((e) => {
        if (supportsClick) {
            e?.stopPropagation();
            setLightboxIndex(currentIndex);
            setIsLightboxOpen(true);
        }
    }, [supportsClick, currentIndex]);
    const closeLightbox = useCallback((e) => {
        e?.stopPropagation();
        setIsLightboxOpen(false);
    }, []);
    const goToNext = useCallback(() => {
        setLightboxIndex((i) => (i + 1) % allImages.length);
    }, [allImages.length]);
    const goToPrev = useCallback(() => {
        setLightboxIndex((i) => (i - 1 + allImages.length) % allImages.length);
    }, [allImages.length]);
    // Touch event handlers for swipe
    const handleTouchStart = useCallback((e) => {
        setTouchEnd(null);
        setTouchStart(e.targetTouches[0].clientX);
    }, []);
    const handleTouchMove = useCallback((e) => {
        setTouchEnd(e.targetTouches[0].clientX);
    }, []);
    const handleTouchEnd = useCallback(() => {
        if (!touchStart || !touchEnd)
            return;
        const distance = touchStart - touchEnd;
        const isLeftSwipe = distance > minSwipeDistance;
        const isRightSwipe = distance < -minSwipeDistance;
        if (isLeftSwipe) {
            goToNext();
        }
        else if (isRightSwipe) {
            goToPrev();
        }
    }, [touchStart, touchEnd, minSwipeDistance, goToNext, goToPrev]);
    // Close lightbox on Escape key, navigate with arrow keys
    useEffect(() => {
        if (!isLightboxOpen)
            return;
        const handleKeyboard = (e) => {
            if (e.key === "Escape")
                closeLightbox();
            if (hasMultipleImages) {
                if (e.key === "ArrowRight")
                    goToNext();
                if (e.key === "ArrowLeft")
                    goToPrev();
            }
        };
        window.addEventListener("keydown", handleKeyboard);
        return () => window.removeEventListener("keydown", handleKeyboard);
    }, [isLightboxOpen, closeLightbox, hasMultipleImages, goToNext, goToPrev]);
    // Derive cursor class for the container based on mode
    const zoomModeAttr = supportsClick
        ? "click"
        : supportsHover || supportsLens
            ? "crosshair"
            : "none";
    // Compute the indicator rectangle (what portion of the image the zoom panel shows).
    // indW / containerW = 1 / zoomLevel (the panel shows 1/zoomLevel of the image width).
    // indH is derived from the zoom panel's aspect ratio so it's consistent with what the
    // panel actually renders — no need for the image's natural dimensions.
    const getIndicatorRect = useCallback(() => {
        if (!containerRef.current)
            return { indL: 0, indT: 0, indW: 0, indH: 0 };
        const rect = containerRef.current.getBoundingClientRect();
        const indW = rect.width / zoomLevel;
        const indH = ((zoomPanelSize.height / zoomPanelSize.width) * rect.width) / zoomLevel;
        const indL = Math.max(0, Math.min(rect.width - indW, cursorPos.x - indW / 2));
        const indT = Math.max(0, Math.min(rect.height - indH, cursorPos.y - indH / 2));
        return { indL, indT, indW, indH };
    }, [cursorPos, zoomLevel, zoomPanelSize]);
    // Calculate zoom panel inline style (position + background — all runtime derived)
    const getZoomPanelStyle = () => {
        if (!containerRef.current || !imageLoaded)
            return { display: "none" };
        const rect = containerRef.current.getBoundingClientRect();
        const { indL, indT, indW, indH } = getIndicatorRect();
        // bgPos is derived from the clamped indicator position, not the raw cursor.
        // At indL=0 → bgPosX=0% (show left), at indL=containerW-indW → bgPosX=100% (show right).
        const bgPosX = rect.width - indW > 0 ? (indL / (rect.width - indW)) * 100 : 0;
        const bgPosY = rect.height - indH > 0 ? (indT / (rect.height - indH)) * 100 : 0;
        // Calculate available space in all directions
        const viewportWidth = window.innerWidth;
        const viewportHeight = window.innerHeight;
        const gap = 16;
        const mouseBuffer = 50; // Minimum distance from mouse cursor
        // Calculate mouse position in viewport
        const mouseX = rect.left + cursorPos.x;
        const mouseY = rect.top + cursorPos.y;
        // Calculate space available in each direction
        const spaceRight = viewportWidth - rect.right - gap;
        const spaceLeft = rect.left - gap;
        // Determine optimal horizontal position
        let left;
        let top = rect.top;
        // Try right side first (default Amazon-style)
        if (spaceRight >= zoomPanelSize.width) {
            left = rect.right + gap;
        }
        // Try left side
        else if (spaceLeft >= zoomPanelSize.width) {
            left = rect.left - zoomPanelSize.width - gap;
        }
        // Not enough space on either side - center on the side with more space
        else if (spaceRight > spaceLeft) {
            left = rect.right + gap;
        }
        else {
            left = Math.max(gap, rect.left - zoomPanelSize.width - gap);
        }
        // Adjust vertical position to keep within viewport
        // Try to align with image top by default
        if (rect.top + zoomPanelSize.height > viewportHeight - gap) {
            // Panel would overflow bottom - adjust upward
            top = Math.max(gap, viewportHeight - zoomPanelSize.height - gap);
        }
        // Ensure panel doesn't overlap with mouse cursor
        const panelRight = left + zoomPanelSize.width;
        const panelBottom = top + zoomPanelSize.height;
        // Check if mouse is inside the panel area
        if (mouseX >= left - mouseBuffer &&
            mouseX <= panelRight + mouseBuffer &&
            mouseY >= top - mouseBuffer &&
            mouseY <= panelBottom + mouseBuffer) {
            // Mouse is too close - try to reposition
            // If on right side and there's space on left, flip to left
            if (left > rect.right && spaceLeft >= zoomPanelSize.width) {
                left = rect.left - zoomPanelSize.width - gap;
            }
            // If on left side and there's space on right, flip to right
            else if (left < rect.left && spaceRight >= zoomPanelSize.width) {
                left = rect.right + gap;
            }
        }
        // Clamp to viewport boundaries
        left = Math.max(gap, Math.min(left, viewportWidth - zoomPanelSize.width - gap));
        top = Math.max(gap, Math.min(top, viewportHeight - zoomPanelSize.height - gap));
        return {
            top,
            left,
            width: zoomPanelSize.width,
            height: zoomPanelSize.height,
            backgroundImage: `url(${src})`,
            backgroundSize: `${zoomLevel * 100}%`,
            backgroundPosition: `${bgPosX}% ${bgPosY}%`,
        };
    };
    // Calculate lens position and size (runtime-derived: cursor pos + lensSize prop)
    const getLensStyle = () => {
        if (!containerRef.current)
            return { display: "none" };
        return {
            width: lensSize,
            height: lensSize,
            left: cursorPos.x - lensSize / 2,
            top: cursorPos.y - lensSize / 2,
        };
    };
    const getLensImageStyle = () => {
        if (!containerRef.current || !imageRef.current)
            return {};
        const rect = containerRef.current.getBoundingClientRect();
        return {
            position: "absolute",
            width: rect.width * zoomLevel,
            height: rect.height * zoomLevel,
            left: -(cursorPos.x * zoomLevel - lensSize / 2),
            top: -(cursorPos.y * zoomLevel - lensSize / 2),
            objectFit: "cover",
        };
    };
    return (React.createElement(React.Fragment, null,
        React.createElement("div", { ref: containerRef, className: clsx("seekora-image-zoom", className), "data-zoom-mode": zoomModeAttr, style: style, onMouseMove: handleMouseMove, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onClick: handleClick },
            React.createElement("img", { ref: imageRef, src: src, alt: alt, className: "seekora-image-zoom__img", style: style?.objectFit ? { objectFit: style.objectFit } : undefined, onLoad: () => setImageLoaded(true) }),
            showZoomIndicator && supportsClick && (React.createElement("div", { className: "seekora-image-zoom__indicator", "data-hovering": isHovering ? "true" : "false" }, "\uD83D\uDD0D")),
            supportsLens && isHovering && imageLoaded && (React.createElement("div", { className: "seekora-image-zoom__lens", style: getLensStyle() },
                React.createElement("img", { src: src, alt: "", style: getLensImageStyle() }))),
            supportsHover &&
                isHovering &&
                imageLoaded &&
                containerRef.current &&
                (() => {
                    const { indL, indT, indW, indH } = getIndicatorRect();
                    const hoverAreaStyle = {
                        left: indL,
                        top: indT,
                        width: indW,
                        height: indH,
                    };
                    return (React.createElement("div", { className: "seekora-image-zoom__hover-area", style: hoverAreaStyle }));
                })()),
        supportsHover &&
            isHovering &&
            imageLoaded &&
            typeof document !== "undefined" &&
            createPortal(React.createElement("div", { className: "seekora-image-zoom__panel", style: getZoomPanelStyle() }), document.body),
        isLightboxOpen &&
            typeof document !== "undefined" &&
            createPortal(React.createElement("div", { className: "seekora-image-zoom-lightbox", onClick: closeLightbox, onTouchStart: hasMultipleImages ? handleTouchStart : undefined, onTouchMove: hasMultipleImages ? handleTouchMove : undefined, onTouchEnd: hasMultipleImages ? handleTouchEnd : undefined },
                React.createElement("button", { type: "button", "aria-label": "Close zoom", className: "seekora-image-zoom-lightbox__close", onClick: (e) => {
                        e.stopPropagation();
                        closeLightbox();
                    } }, "\u2715"),
                hasMultipleImages && (React.createElement(React.Fragment, null,
                    React.createElement("button", { type: "button", "aria-label": "Previous image", className: "seekora-image-zoom-lightbox__prev", onClick: (e) => {
                            e.stopPropagation();
                            goToPrev();
                        } }, "\u2039"),
                    React.createElement("button", { type: "button", "aria-label": "Next image", className: "seekora-image-zoom-lightbox__next", onClick: (e) => {
                            e.stopPropagation();
                            goToNext();
                        } }, "\u203A"))),
                React.createElement("img", { src: allImages[lightboxIndex], alt: alt, className: "seekora-image-zoom-lightbox__img", onClick: (e) => e.stopPropagation() }),
                hasMultipleImages && (React.createElement("div", { className: "seekora-image-zoom-lightbox__footer", onClick: (e) => e.stopPropagation() },
                    React.createElement("div", { className: "seekora-image-zoom-lightbox__thumbs" }, allImages.map((img, i) => (React.createElement("button", { key: i, type: "button", className: "seekora-image-zoom-lightbox__thumb", "data-active": i === lightboxIndex ? "true" : "false", onClick: (e) => {
                            e.stopPropagation();
                            setLightboxIndex(i);
                        } },
                        React.createElement("img", { src: img, alt: "" }))))),
                    React.createElement("div", { className: "seekora-image-zoom-lightbox__counter" },
                        lightboxIndex + 1,
                        " / ",
                        allImages.length))),
                React.createElement("div", { className: "seekora-image-zoom-lightbox__instructions" }, hasMultipleImages
                    ? "Use arrow keys or click thumbnails to navigate • ESC to close"
                    : "Click outside or press ESC to close")), document.body)));
}
