import { jsx, jsxs } from 'react/jsx-runtime';
import React__default, { useState, useEffect } from 'react';
import { useReducedMotion, motion, AnimatePresence } from 'motion/react';
import { DocumentIcon, TrashIcon, XMarkIcon, ArrowPathIcon } from '@heroicons/react/24/outline';
import { FileTypeIcon } from '../../core/FileTypeIcon/FileTypeIcon.js';
import { fileTypes } from '../../core/FileTypeIcon/fileTypes.js';
import { cn } from '../../../utils/cn.js';
import { getFileExtension, formatFileSize } from '../../../utils/formatUtils.js';
import { Popover } from '../../core/Popover/Popover.js';
import '../../core/Popover/PopoverContext.js';
import '../../core/Popover/PopoverBody.js';
import { Button } from '../../core/Button/Button.js';
import { fileUploadProgressTheme } from './FileUploadProgress.theme.js';
import { REMOVE_BUTTON_ENTER, PROGRESS_SPRING, CROSSFADE } from './FileUploadProgress.animations.js';

const isKnownFileType = (ext) => {
    return ext in fileTypes;
};
// SVG viewBox is 36×36 — small enough for crisp rendering, large enough for smooth arcs
const VIEWBOX = 36;
const CENTER = VIEWBOX / 2;
const RadialProgress = ({ progress, status, strokeWidth, trackColor, progressColor, centerTextStyle, statusIconColor, sizeClass, shouldReduceMotion, confirmRemove, completionDelay, onRemove, onRetry, }) => {
    const [isHovered, setIsHovered] = useState(false);
    const [confirmOpen, setConfirmOpen] = useState(false);
    const [showRemove, setShowRemove] = useState(false);
    const radius = (VIEWBOX - strokeWidth) / 2;
    const circumference = 2 * Math.PI * radius;
    const offset = circumference * (1 - progress / 100);
    const isUploading = status === "uploading";
    const isComplete = status === "complete";
    const isError = status === "error";
    // After completing, show tick briefly then transition to remove button
    useEffect(() => {
        if (isComplete) {
            setShowRemove(false);
            const timer = setTimeout(() => setShowRemove(true), completionDelay);
            return () => clearTimeout(timer);
        }
        setShowRemove(false);
    }, [isComplete, completionDelay]);
    const handleClick = () => {
        if (isError && onRetry) {
            onRetry();
            return;
        }
        if (onRemove) {
            if (confirmRemove) {
                setConfirmOpen(true);
            }
            else {
                onRemove();
            }
        }
    };
    const handleConfirm = () => {
        setConfirmOpen(false);
        onRemove === null || onRemove === void 0 ? void 0 : onRemove();
    };
    const isClickable = (isError && onRetry) || onRemove;
    const ariaLabel = isError && onRetry ? "Retry upload" : onRemove ? "Remove file" : undefined;
    // Shared remove button used after completion tick
    const removeButton = (jsx(motion.div, { initial: shouldReduceMotion ? false : REMOVE_BUTTON_ENTER.initial, animate: REMOVE_BUTTON_ENTER.animate, transition: REMOVE_BUTTON_ENTER.transition, className: "shrink-0", children: jsx(Button, { size: "sm", variant: "soft", color: "neutral", "aria-label": "Remove file", iconOnly: true, className: "rounded-full size-8", onClick: confirmRemove ? undefined : () => onRemove === null || onRemove === void 0 ? void 0 : onRemove(), children: jsx(TrashIcon, { className: "size-3.5", strokeWidth: 2 }) }) }, "remove-btn"));
    const radialElement = (jsxs("div", { className: cn("relative shrink-0", sizeClass, isClickable && "cursor-pointer"), onMouseEnter: () => setIsHovered(true), onMouseLeave: () => {
            if (!confirmOpen)
                setIsHovered(false);
        }, onClick: isClickable ? handleClick : undefined, role: isClickable ? "button" : undefined, tabIndex: isClickable ? 0 : undefined, "aria-label": ariaLabel, onKeyDown: isClickable
            ? (e) => {
                if (e.key === "Enter" || e.key === " ") {
                    e.preventDefault();
                    handleClick();
                }
            }
            : undefined, children: [jsxs("svg", { viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`, className: "w-full h-full -rotate-90", children: [jsx("circle", { cx: CENTER, cy: CENTER, r: radius, fill: "none", stroke: trackColor, strokeWidth: strokeWidth }), jsx(motion.circle, { cx: CENTER, cy: CENTER, r: radius, fill: "none", stroke: progressColor, strokeWidth: strokeWidth, strokeLinecap: "round", strokeDasharray: circumference, initial: { strokeDashoffset: circumference }, animate: { strokeDashoffset: isComplete ? 0 : offset }, transition: shouldReduceMotion ? { duration: 0 } : PROGRESS_SPRING })] }), jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: jsxs(AnimatePresence, { mode: "wait", initial: false, children: [isUploading && !isHovered && (jsx(motion.span, { className: centerTextStyle, ...(shouldReduceMotion ? {} : CROSSFADE), children: progress }, "percent")), isUploading && isHovered && onRemove && (jsx(motion.span, { ...(shouldReduceMotion ? {} : CROSSFADE), children: jsx(XMarkIcon, { className: "size-4 text-[var(--color-text-muted)]", strokeWidth: 2.5 }) }, "close")), isComplete && !showRemove && (jsx(motion.span, { ...(shouldReduceMotion ? {} : CROSSFADE), children: jsx("svg", { viewBox: "0 0 24 24", fill: "none", className: cn("size-4", statusIconColor), children: jsx("path", { d: "M5 13l4.5 4.5L19 7", stroke: "currentColor", strokeWidth: 3.5, strokeLinecap: "round", strokeLinejoin: "round" }) }) }, "check")), isError && (jsx(motion.span, { ...(shouldReduceMotion ? {} : CROSSFADE), children: jsx(ArrowPathIcon, { className: cn("size-3.5", statusIconColor), strokeWidth: 2.5 }) }, "retry"))] }) })] }));
    // Determine what to render: radial indicator or remove button
    const showRemoveButton = isComplete && showRemove && onRemove;
    const triggerElement = showRemoveButton ? removeButton : radialElement;
    // No confirm popover needed — return the element directly
    if (!confirmRemove || !onRemove)
        return triggerElement;
    return (jsxs(Popover, { isOpen: confirmOpen, onOpenChange: (open) => {
            setConfirmOpen(open);
            if (!open)
                setIsHovered(false);
        }, placement: "bottom-end", offset: isComplete ? 2 : 6, triggerType: "click", children: [jsx(Popover.Trigger, { children: triggerElement }), jsxs(Popover.Body, { portal: false, className: "flex items-center p-0.5 border-[0.5px] rounded-xl gap-0.5", children: [jsx("span", { className: "text-base font-medium text-[var(--color-text-secondary)] px-3", children: isComplete ? "Remove file?" : "Cancel upload?" }), jsx(Button, { size: "sm", color: "danger", variant: "filled", onClick: handleConfirm, children: "Yes" }), jsx(Button, { size: "sm", variant: "soft", color: "neutral", onClick: () => setConfirmOpen(false), children: "No" })] })] }));
};
// --- Main Component ---
const FileUploadProgress = React__default.forwardRef(({ items, onRemove, onRetry, showFileSize = true, confirmRemove = true, completionDelay = 1500, className, theme: themeOverrides, ...rest }, ref) => {
    var _a;
    const shouldReduceMotion = useReducedMotion();
    const t = fileUploadProgressTheme;
    if (items.length === 0)
        return null;
    const radialProgressColors = {
        ...t.radialProgressColors,
        ...themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.radialProgressColors,
    };
    const statusIconColors = {
        ...t.statusIconColors,
        ...themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.statusIconColors,
    };
    return (jsx("div", { ref: ref, className: cn((_a = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.containerStyle) !== null && _a !== void 0 ? _a : t.containerStyle, className), ...rest, children: items.map((item) => {
            var _a, _b, _c, _d, _e, _f, _g, _h, _j;
            const clampedProgress = Math.min(100, Math.max(0, item.progress));
            const ext = getFileExtension(item.file.name);
            const hasFileTypeIcon = ext !== null && isKnownFileType(ext);
            return (jsxs("div", { className: (_a = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.itemStyle) !== null && _a !== void 0 ? _a : t.itemStyle, children: [hasFileTypeIcon ? (jsx("span", { className: "shrink-0", children: jsx(FileTypeIcon, { type: ext, size: "lg" }) })) : (jsx("span", { className: cn((_b = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.iconContainerStyle) !== null && _b !== void 0 ? _b : t.iconContainerStyle, t.iconSize), children: jsx(DocumentIcon, { className: (_c = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.iconStyle) !== null && _c !== void 0 ? _c : t.iconStyle }) })), jsxs("div", { className: (_d = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileInfoStyle) !== null && _d !== void 0 ? _d : t.fileInfoStyle, children: [jsx("p", { className: (_e = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileNameStyle) !== null && _e !== void 0 ? _e : t.fileNameStyle, children: item.file.name }), showFileSize && (jsx("p", { className: (_f = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileSizeStyle) !== null && _f !== void 0 ? _f : t.fileSizeStyle, children: formatFileSize(item.file.size) })), item.status === "error" && item.error && (jsx("p", { className: (_g = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.errorTextStyle) !== null && _g !== void 0 ? _g : t.errorTextStyle, children: item.error }))] }), jsx(RadialProgress, { progress: clampedProgress, status: item.status, strokeWidth: t.radialStroke, trackColor: (_h = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.radialTrackColor) !== null && _h !== void 0 ? _h : t.radialTrackColor, progressColor: radialProgressColors[item.status], centerTextStyle: (_j = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.radialCenterTextStyle) !== null && _j !== void 0 ? _j : t.radialCenterTextStyle, statusIconColor: statusIconColors[item.status], sizeClass: t.radialSize, shouldReduceMotion: shouldReduceMotion, confirmRemove: confirmRemove, completionDelay: completionDelay, onRemove: onRemove ? () => onRemove(item.id) : undefined, onRetry: onRetry ? () => onRetry(item.id) : undefined })] }, item.id));
        }) }));
});
FileUploadProgress.displayName = "FileUploadProgress";

export { FileUploadProgress };
