import {useEffect, useRef} from "@wordpress/element";
import {hexToRgb} from "../../chatbots/includes/helpers";

// Default easing function (quadratic ease-in-out)
const defaultEasingFunction = (t) => {
    return t < 0.5
        ? 2 * t * t
        : -1 + (4 - 2 * t) * t;
};

export default function useAnimatedBoxShadow({
                                                 color,
                                                 duration = 2500,
                                                 times = [0, 0.5, 1],
                                                 easingFunction = defaultEasingFunction,
                                                 minWidth = 0,
                                                 maxWidth = 3,
                                                 minOpacity = 0,
                                                 maxOpacity = 0.2,
                                                 loop = true,
                                                 delay = 0
                                             }) {
    const elementRef = useRef(null);

    useEffect(() => {
        const element = elementRef.current;
        if (!element || !color) {
            return;
        }

        const rgb = hexToRgb(color);
        if (!rgb) {
            return;
        }

        // Pre-calculate arrays to avoid recreation on each frame
        const widths = [minWidth, maxWidth, minWidth];
        const opacities = [minOpacity, maxOpacity, minOpacity];

        let startTime = null;
        let animationId = null;
        let delayTimeoutId = null;
        let hasCompleted = false;

        const interpolateShadow = (progress) => {
            // Find which segment we're in
            let segmentIndex = 0;
            for (let i = 0; i < times.length - 1; i++) {
                if (progress >= times[i] && progress <= times[i + 1]) {
                    segmentIndex = i;
                    break;
                }
            }

            // Calculate progress within the segment
            const segmentStart = times[segmentIndex];
            const segmentEnd = times[segmentIndex + 1];
            const segmentProgress = (progress - segmentStart) / (segmentEnd - segmentStart);
            const easedProgress = easingFunction(segmentProgress);

            // Interpolate width and opacity values smoothly
            const startWidth = widths[segmentIndex];
            const endWidth = widths[segmentIndex + 1];
            const interpolatedWidth = startWidth + (endWidth - startWidth) * easedProgress;

            const startOpacity = opacities[segmentIndex];
            const endOpacity = opacities[segmentIndex + 1];
            const interpolatedOpacity = startOpacity + (endOpacity - startOpacity) * easedProgress;

            return `0 0 0 ${interpolatedWidth}px rgba(${rgb}, ${interpolatedOpacity})`;
        };

        const animate = (timestamp) => {
            // Check if element still exists in DOM
            if (!elementRef.current) {
                if (animationId) {
                    cancelAnimationFrame(animationId);
                }
                return;
            }

            if (!startTime) {
                startTime = timestamp;
            }
            const elapsed = timestamp - startTime;

            // If not looping and animation has completed, stop
            if (!loop && elapsed >= duration) {
                if (!hasCompleted) {
                    // Set final state
                    elementRef.current.style.boxShadow = interpolateShadow(1);
                    hasCompleted = true;
                }
                return;
            }

            const progress = loop ? (elapsed % duration) / duration : Math.min(elapsed / duration, 1);

            elementRef.current.style.boxShadow = interpolateShadow(progress);

            animationId = requestAnimationFrame(animate);
        };

        const startAnimation = () => {
            animationId = requestAnimationFrame(animate);
        };

        // Start animation after delay
        if (delay > 0) {
            delayTimeoutId = setTimeout(startAnimation, delay);
        } else {
            startAnimation();
        }

        return () => {
            if (animationId) {
                cancelAnimationFrame(animationId);
            }
            if (delayTimeoutId) {
                clearTimeout(delayTimeoutId);
            }
        };
    }, [color, duration, times, easingFunction, minWidth, maxWidth, minOpacity, maxOpacity, loop, delay]);

    return elementRef;
}