(function ($) {
    "use strict";

    const random = (min, max) => gsap.utils.random(min, max);

    /**
     * Kill GSAP/ScrollTrigger state so animation type can change in the editor.
     */
    const cleanupStaggerHeading = (heading) => {
        if (!heading) {
            return;
        }

        ScrollTrigger.getAll().forEach((st) => {
            if (st.trigger === heading || heading.contains(st.trigger)) {
                st.kill();
            }
        });

        gsap.killTweensOf(heading.querySelectorAll(".sifency-letter-span, .sifency-word-span"));
        heading.classList.remove("sifency-text-splitted");
        heading.removeAttribute("data-anim-type");
    };

    /**
     * Build from/to props per animation style.
     */
    const getAnimationProps = (animType, config) => {
        const staggerTime = parseFloat(config.stagger || 0.05);
        const durationTime = parseFloat(config.duration || 1);
        const staggerFrom = config.stagger_from || "start";
        const baseEase = config.ease || "power3.out";

        const baseTo = {
            opacity: 1,
            duration: durationTime,
            ease: baseEase,
            stagger: {
                each: staggerTime,
                from: staggerFrom,
            },
        };

        const presets = {
            reveal: {
                from: { yPercent: 120, opacity: 1 },
                to: { yPercent: 0, ease: "expo.out" },
            },
            scale: {
                from: { scale: 0.5, opacity: 0 },
                to: { scale: 1, ease: "power3.out" },
            },
            "fade-in": {
                from: { opacity: 0 },
                to: { ease: "none" },
            },
            "fade-up": {
                from: { y: 50, opacity: 0 },
                to: { y: 0 },
            },
            "fade-down": {
                from: { y: -50, opacity: 0 },
                to: { y: 0 },
            },
            "slide-left": {
                from: { x: 50, opacity: 0 },
                to: { x: 0 },
            },
            "slide-right": {
                from: { x: -50, opacity: 0 },
                to: { x: 0 },
            },
            "slide-up-fade": {
                from: { y: 80, opacity: 0, filter: "blur(4px)" },
                to: { y: 0, filter: "blur(0px)", ease: "power3.out" },
            },
            "slide-down-fade": {
                from: { y: -80, opacity: 0, filter: "blur(4px)" },
                to: { y: 0, filter: "blur(0px)", ease: "power3.out" },
            },
            "mask-up": {
                from: { yPercent: 110, opacity: 1 },
                to: { yPercent: 0, ease: "expo.out" },
            },
            "mask-down": {
                from: { yPercent: -110, opacity: 1 },
                to: { yPercent: 0, ease: "expo.out" },
            },
            "mask-left": {
                from: { xPercent: 110, opacity: 0 },
                to: { xPercent: 0, ease: "expo.out" },
            },
            "mask-right": {
                from: { xPercent: -110, opacity: 1 },
                to: { xPercent: 0, ease: "expo.out" },
            },
            "blur-in": {
                from: { filter: "blur(20px)", opacity: 0, scale: 1.2 },
                to: { filter: "blur(0px)", scale: 1, ease: "power2.out" },
            },
            "wipe-right": {
                from: { xPercent: -100, opacity: 1 },
                to: { xPercent: 0, ease: "power3.out" },
            },
            "curtain-open": {
                from: { scaleX: 0, opacity: 1, transformOrigin: "left center" },
                to: { scaleX: 1, ease: "power3.inOut" },
            },
            "venetian-blinds": {
                from: { scaleY: 0, opacity: 0, transformOrigin: "top center" },
                to: { scaleY: 1, ease: "power2.out" },
            },
            "paint-brush": {
                from: { scaleX: 0, opacity: 1, transformOrigin: "left center", filter: "blur(3px)" },
                to: { scaleX: 1, filter: "blur(0px)", ease: "power3.inOut" },
            },
            typewriter: {
                from: { opacity: 0, scale: 0.85 },
                to: { opacity: 1, scale: 1, ease: "steps(1)" },
            },
            "zoom-in": {
                from: { scale: 0.2, opacity: 0 },
                to: { scale: 1, ease: "back.out(1.5)" },
            },
            "zoom-out": {
                from: { scale: 2, opacity: 0 },
                to: { scale: 1, ease: "power4.out" },
            },
            "letter-spacing": {
                from: { letterSpacing: "0.4em", opacity: 0, filter: "blur(5px)" },
                to: { letterSpacing: "0em", filter: "blur(0px)", ease: "expo.out" },
            },
            "stamp-in": {
                from: { scale: 2.5, opacity: 0 },
                to: { scale: 1, ease: "back.out(2)" },
            },
            "uppercase-slam": {
                from: { y: -120, scaleY: 2, opacity: 0, transformOrigin: "top center" },
                to: { y: 0, scaleY: 1, ease: "power4.out" },
            },
            "italic-slide": {
                from: { skewX: 25, x: 60, opacity: 0 },
                to: { skewX: 0, x: 0, ease: "power3.out" },
            },
            "ticker-tape": {
                from: { xPercent: 100, opacity: 0 },
                to: { xPercent: 0, ease: "power2.out" },
            },
            "weight-shift": {
                from: { scaleY: 2, y: -20, opacity: 0, transformOrigin: "bottom center" },
                to: { scaleY: 1, y: 0, ease: "elastic.out(1, 0.5)" },
            },
            "flip-x": {
                from: { rotateX: -90, opacity: 0, transformOrigin: "50% 50% -30px" },
                to: { rotateX: 0, ease: "back.out(1.2)" },
            },
            "flip-y": {
                from: { rotateY: 90, opacity: 0, transformOrigin: "0% 50%" },
                to: { rotateY: 0, ease: "power4.out" },
            },
            "flip-z": {
                from: { rotateZ: () => random(-180, 180), opacity: 0, scale: 0.5 },
                to: { rotateZ: 0, scale: 1, ease: "power3.out" },
            },
            "rotate-3d": {
                from: { rotateX: 90, rotateY: 45, rotateZ: -45, opacity: 0, scale: 0.5 },
                to: { rotateX: 0, rotateY: 0, rotateZ: 0, scale: 1, ease: "power3.out" },
            },
            "perspective-tilt": {
                from: { z: -400, rotateX: 35, opacity: 0 },
                to: { z: 0, rotateX: 0, ease: "power4.out" },
            },
            swing: {
                from: { rotateZ: 45, opacity: 0, transformOrigin: "top center" },
                to: { rotateZ: 0, ease: "elastic.out(1, 0.4)" },
            },
            "cube-rotate": {
                from: { rotateY: 180, opacity: 0, z: -150 },
                to: { rotateY: 0, z: 0, ease: "power3.out" },
            },
            "card-flip": {
                from: { rotateY: 90, opacity: 0, transformOrigin: "left center" },
                to: { rotateY: 0, ease: "power2.out" },
            },
            "fold-in": {
                from: { rotateX: 90, opacity: 0, transformOrigin: "top center", z: -80 },
                to: { rotateX: 0, z: 0, ease: "power3.out" },
            },
            "casino-flip": {
                from: { rotateX: 360, opacity: 0 },
                to: { rotateX: 0, ease: "power3.out" },
            },
            "depth-emerge": {
                from: { z: -600, opacity: 0, scale: 0.3 },
                to: { z: 0, scale: 1, ease: "power4.out" },
            },
            "depth-blur": {
                from: { z: -250, filter: "blur(16px)", opacity: 0 },
                to: { z: 0, filter: "blur(0px)", ease: "power4.out" },
            },
            "tunnel-in": {
                from: { scale: 5, opacity: 0, filter: "blur(12px)" },
                to: { scale: 1, filter: "blur(0px)", ease: "power3.out" },
            },
            "bounce-in": {
                from: { y: -100, opacity: 0 },
                to: { y: 0, ease: "bounce.out" },
            },
            "elastic-drop": {
                from: { y: -80, scaleY: 1.8, opacity: 0, transformOrigin: "bottom center" },
                to: { y: 0, scaleY: 1, ease: "elastic.out(1, 0.3)" },
            },
            "rubber-band": {
                from: { scaleX: 0.3, scaleY: 1.6, opacity: 0 },
                to: { scaleX: 1, scaleY: 1, ease: "elastic.out(1, 0.3)" },
            },
            jello: {
                from: { skewX: -25, opacity: 0 },
                to: { skewX: 0, ease: "elastic.out(1, 0.2)" },
            },
            "gravity-fall": {
                from: { y: -200, opacity: 0 },
                to: { y: 0, ease: "bounce.out" },
            },
            pendulum: {
                from: { rotateZ: 50, opacity: 0, transformOrigin: "top center" },
                to: { rotateZ: 0, ease: "elastic.out(1, 0.5)" },
            },
            slingshot: {
                from: { x: 150, scaleX: 0.3, opacity: 0 },
                to: { x: 0, scaleX: 1, ease: "back.out(2.5)" },
            },
            ricochet: {
                from: { y: -100, x: () => random(-40, 40), opacity: 0 },
                to: { y: 0, x: 0, ease: "bounce.out" },
            },
            "slot-machine": {
                from: { y: -250, opacity: 0 },
                to: { y: 0, ease: "bounce.out" },
            },
            "pop-bounce": {
                from: { y: -80, scale: 1.4, opacity: 0 },
                to: { y: 0, scale: 1, ease: "bounce.out" },
            },
            "spring-pop": {
                from: { scale: 0, opacity: 0 },
                to: { scale: 1, ease: "elastic.out(1.5, 0.3)" },
            },
            heartbeat: {
                from: { scaleX: 0, scaleY: 0, opacity: 0 },
                to: { scaleX: 1, scaleY: 1, ease: "elastic.out(2, 0.4)" },
            },
            ripple: {
                from: { scale: 0, opacity: 0 },
                to: { scale: 1, ease: "back.out(1.5)", stagger: { each: staggerTime, from: "center" } },
            },
            "pulse-in": {
                from: { scale: 0.4, opacity: 0 },
                to: { scale: 1, ease: "elastic.out(1.5, 0.5)" },
            },
            "neon-on": {
                from: { opacity: 0, filter: "blur(10px) brightness(0)" },
                to: { filter: "blur(0px) brightness(1)", ease: "power3.out" },
            },
            "cyber-glitch": {
                from: {
                    x: () => random(-20, 20),
                    skewX: () => random(-15, 15),
                    opacity: 0,
                    filter: "hue-rotate(90deg)",
                },
                to: { x: 0, skewX: 0, filter: "hue-rotate(0deg)", ease: "steps(4)" },
            },
            hologram: {
                from: { scaleY: 0, opacity: 0, filter: "brightness(3) blur(4px)" },
                to: { scaleY: 1, filter: "brightness(1) blur(0px)", ease: "power2.out" },
            },
            "matrix-rain": {
                from: { y: () => random(-180, -40), opacity: 0, filter: "blur(2px)" },
                to: { y: 0, filter: "blur(0px)", ease: "power2.in" },
            },
            "circuit-trace": {
                from: { opacity: 0, x: () => random(-8, 8) },
                to: { opacity: 1, x: 0, ease: "steps(5)" },
            },
            "pixel-dissolve": {
                from: {
                    scale: () => random(0.4, 1.8),
                    opacity: 0,
                    x: () => random(-12, 12),
                    y: () => random(-12, 12),
                },
                to: { scale: 1, x: 0, y: 0, ease: "power3.out" },
            },
            "scan-line": {
                from: { scaleY: 0, transformOrigin: "top center", opacity: 0.3 },
                to: { scaleY: 1, opacity: 1, ease: "power1.inOut" },
            },
            "data-stream": {
                from: { y: -50, opacity: 0, scale: 0.85, filter: "blur(4px)" },
                to: { y: 0, scale: 1, filter: "blur(0px)", ease: "power4.out" },
            },
            "quantum-leap": {
                from: {
                    x: () => random(-150, 150),
                    y: () => random(-150, 150),
                    scale: () => random(0.1, 0.4),
                    opacity: 0,
                },
                to: { x: 0, y: 0, scale: 1, ease: "expo.out" },
            },
            "warp-drive": {
                from: { scaleX: 6, x: -150, opacity: 0, filter: "blur(8px)" },
                to: { scaleX: 1, x: 0, filter: "blur(0px)", ease: "expo.out" },
            },
            "energy-surge": {
                from: { scaleX: 0.05, opacity: 0, filter: "brightness(4) blur(4px)" },
                to: { scaleX: 1, filter: "brightness(1) blur(0px)", ease: "expo.out" },
            },
            "light-speed": {
                from: { x: -400, skewX: -25, opacity: 0, filter: "blur(6px)" },
                to: { x: 0, skewX: 0, filter: "blur(0px)", ease: "expo.out" },
            },
            "flash-in": {
                from: { opacity: 0, scale: 1.6, filter: "brightness(6)" },
                to: { opacity: 1, scale: 1, filter: "brightness(1)", ease: "power2.out" },
            },
            "glow-pulse": {
                from: { opacity: 0, filter: "blur(12px) brightness(2.5)", scale: 1.25 },
                to: { opacity: 1, filter: "blur(0px) brightness(1)", scale: 1, ease: "power3.out" },
            },
            shatter: {
                from: {
                    x: () => random(-120, 120),
                    y: () => random(-120, 120),
                    rotation: () => random(-180, 180),
                    opacity: 0,
                    scale: 0.2,
                },
                to: { x: 0, y: 0, rotation: 0, scale: 1, ease: "power4.out" },
            },
            implode: {
                from: { scale: 3.5, opacity: 0, filter: "blur(18px)" },
                to: { scale: 1, filter: "blur(0px)", ease: "expo.out" },
            },
            "explode-in": {
                from: {
                    scale: 0,
                    x: () => random(-150, 150),
                    y: () => random(-150, 150),
                    opacity: 0,
                },
                to: { scale: 1, x: 0, y: 0, ease: "power3.out" },
            },
            "smoke-rise": {
                from: { y: 40, opacity: 0, scaleX: 1.4, filter: "blur(10px)" },
                to: { y: 0, scaleX: 1, filter: "blur(0px)", ease: "power2.out" },
            },
            "liquid-flow": {
                from: { scaleY: 0.2, y: 30, opacity: 0, transformOrigin: "bottom center" },
                to: { scaleY: 1, y: 0, ease: "elastic.out(1, 0.5)" },
            },
            "dust-settle": {
                from: {
                    y: () => random(-30, -8),
                    x: () => random(-10, 10),
                    opacity: 0,
                    scale: () => random(0.5, 0.85),
                },
                to: { y: 0, x: 0, scale: 1, ease: "power2.out" },
            },
            "orbit-in": {
                from: { rotation: 360, scale: 0, opacity: 0 },
                to: { rotation: 0, scale: 1, ease: "power3.out" },
            },
            "spiral-in": {
                from: { rotation: 540, scale: 0, opacity: 0 },
                to: { rotation: 0, scale: 1, ease: "power4.out" },
            },
            vortex: {
                from: { rotation: () => random(-360, 360), scale: 0, opacity: 0 },
                to: { rotation: 0, scale: 1, ease: "back.out(2)" },
            },
            "magnetic-pull": {
                from: { x: () => random(-80, 80), y: () => random(-40, 40), opacity: 0 },
                to: { x: 0, y: 0, ease: "power4.out" },
            },
            "rise-spin": {
                from: { y: 70, rotation: -200, opacity: 0, scale: 0.4 },
                to: { y: 0, rotation: 0, scale: 1, ease: "back.out(1.5)" },
            },
            "glitch-in": {
                from: { x: () => random(-25, 25), skewX: () => random(-12, 12), opacity: 0 },
                to: { x: 0, skewX: 0, clearProps: "transform", ease: "power3.out" },
            },
            wobble: {
                from: { y: -60, rotateZ: 25, opacity: 0 },
                to: { y: 0, rotateZ: 0, ease: "elastic.out(1.2, 0.4)" },
            },
            "random-scatter": {
                from: {
                    x: () => random(-90, 90),
                    y: () => random(-90, 90),
                    rotation: () => random(-90, 90),
                    opacity: 0,
                    scale: 0.4,
                },
                to: { x: 0, y: 0, rotation: 0, scale: 1, ease: "power4.out" },
            },
            "morph-in": {
                from: { scale: () => random(0.3, 1.6), opacity: 0, filter: "blur(6px)" },
                to: { scale: 1, filter: "blur(0px)", ease: "power3.out" },
            },
            shockwave: {
                from: { scale: 0, skewX: 18, opacity: 0 },
                to: { scale: 1, skewX: 0, ease: "elastic.out(1.2, 0.4)" },
            },
            "dissolve-up": {
                from: { y: 30, opacity: 0, filter: "blur(8px)", scale: 0.92 },
                to: { y: 0, filter: "blur(0px)", scale: 1, ease: "power2.out" },
            },
            "fall-rotate": {
                from: { y: -120, rotation: () => random(-50, 50), opacity: 0 },
                to: { y: 0, rotation: 0, ease: "power3.out" },
            },
            "stretch-x": {
                from: { scaleX: 0, opacity: 0, transformOrigin: "center center" },
                to: { scaleX: 1, ease: "elastic.out(1, 0.4)" },
            },
            "stretch-y": {
                from: { scaleY: 0, opacity: 0, transformOrigin: "center center" },
                to: { scaleY: 1, ease: "elastic.out(1, 0.4)" },
            },
            "wind-sweep": {
                from: { x: 100, skewX: -18, opacity: 0 },
                to: { x: 0, skewX: 0, ease: "power3.out" },
            },
            "retro-fade": {
                from: { opacity: 0, filter: "sepia(1) blur(4px)", scale: 1.15 },
                to: { filter: "sepia(0) blur(0px)", scale: 1, ease: "power2.out" },
            },
        };

        const preset = presets[animType] || presets["mask-up"];

        return {
            from: Object.assign({ force3D: true }, preset.from),
            to: Object.assign({}, baseTo, preset.to),
            special: animType,
        };
    };

    /**
     * Wave / neon use a timeline for distinct motion.
     */
    const runSpecialAnimation = (animType, animTargets, heading, config) => {
        const durationTime = parseFloat(config.duration || 1);
        const staggerTime = parseFloat(config.stagger || 0.05);
        const scrollStart = config.start || 90;
        const scrubVal = config.scrub;
        const repeatVal = config.repeat;

        const stConfig = {
            trigger: heading,
            start: `top ${scrollStart}%`,
            end: scrubVal ? "bottom 20%" : "bottom top",
            scrub: scrubVal,
        };

        if (!scrubVal) {
            stConfig.toggleActions = repeatVal ? "play pause resume reset" : "play none none reverse";
        }

        const tl = gsap.timeline({
            scrollTrigger: stConfig,
            defaults: { ease: config.ease || "power3.out" },
        });

        if (animType === "wave-up" || animType === "wave-down") {
            const direction = animType === "wave-up" ? 1 : -1;
            animTargets.forEach((target, index) => {
                const waveOffset = Math.sin((index / Math.max(animTargets.length - 1, 1)) * Math.PI) * 40;
                tl.fromTo(
                    target,
                    { y: direction * (50 + waveOffset), opacity: 0, rotation: direction * 8 },
                    {
                        y: 0,
                        opacity: 1,
                        rotation: 0,
                        duration: durationTime * 0.85,
                        ease: "back.out(1.4)",
                    },
                    index * staggerTime
                );
            });
            return;
        }

        if (animType === "neon-flicker") {
            gsap.set(animTargets, { opacity: 0 });
            animTargets.forEach((target, index) => {
                tl.to(
                    target,
                    {
                        opacity: 1,
                        duration: 0.05,
                        ease: "none",
                        repeat: 2,
                        yoyo: true,
                    },
                    index * staggerTime
                );
                tl.to(
                    target,
                    {
                        opacity: 1,
                        duration: durationTime * 0.3,
                        ease: "power1.inOut",
                    },
                    index * staggerTime + 0.15
                );
            });
        }
    };

    const splitHeadingText = (heading, textContainer, text, splitType) => {
        textContainer.innerHTML = "";
        const animTargets = [];
        const words = text.split(/\s+/).filter(Boolean);

        words.forEach((word, wordIndex) => {
            const wordSpan = document.createElement("span");
            wordSpan.className = "sifency-word-span";

            if (splitType === "words") {
                wordSpan.textContent = word;
                textContainer.appendChild(wordSpan);
                animTargets.push(wordSpan);
            } else {
                word.split("").forEach((char) => {
                    const charSpan = document.createElement("span");
                    charSpan.className = "sifency-letter-span";
                    charSpan.textContent = char;
                    wordSpan.appendChild(charSpan);
                    animTargets.push(charSpan);
                });
                textContainer.appendChild(wordSpan);
            }

            if (wordIndex < words.length - 1) {
                textContainer.appendChild(document.createTextNode(" "));
            }
        });

        return animTargets;
    };

    const initStaggeredText = ($scope) => {
        const heading = $scope.find(".sifency-anim-heading")[0];
        if (!heading) {
            return;
        }

        if (typeof gsap === "undefined" || typeof ScrollTrigger === "undefined") {
            console.error("Sifency Error: GSAP or ScrollTrigger is missing.");
            return;
        }

        const config = JSON.parse(heading.dataset.config || "{}");
        const animType = config.type || "mask-up";

        if (heading.classList.contains("sifency-text-splitted") && heading.dataset.animType === animType) {
            return;
        }

        cleanupStaggerHeading(heading);

        const linkElement = heading.querySelector("a");
        const textContainer = linkElement || heading;
        const text = (heading.dataset.originalText || textContainer.textContent || "").trim();

        if (!text) {
            return;
        }

        heading.dataset.originalText = text;
        heading.dataset.animType = animType;
        heading.classList.add("sifency-text-splitted");

        const animTargets = splitHeadingText(heading, textContainer, text, config.split || "chars");

        const runAnimation = () => {
            const specialTypes = ["wave-up", "wave-down", "neon-flicker"];

            if (specialTypes.includes(animType)) {
                runSpecialAnimation(animType, animTargets, heading, config);
                return;
            }

            const { from, to } = getAnimationProps(animType, config);

            gsap.set(animTargets, from);

            const scrubVal = config.scrub;
            const repeatVal = config.repeat;
            const scrollStart = config.start || 90;

            const stConfig = {
                trigger: heading,
                start: `top ${scrollStart}%`,
                end: scrubVal ? "bottom 20%" : "bottom top",
                scrub: scrubVal,
            };

            if (!scrubVal) {
                stConfig.toggleActions = repeatVal ? "play pause resume reset" : "play none none reverse";
            }

            gsap.to(animTargets, {
                ...to,
                scrollTrigger: stConfig,
            });
        };

        if (document.body.classList.contains("sifency-preloader-active")) {
            window.addEventListener(
                "sifency/preloader/done",
                () => {
                    setTimeout(runAnimation, 300);
                },
                { once: true }
            );
        } else {
            runAnimation();
        }
    };

    $(window).on("elementor/frontend/init", function () {
        elementorFrontend.hooks.addAction("frontend/element_ready/sifency-staggered-text.default", initStaggeredText);

        if (elementorFrontend.isEditMode && elementorFrontend.channels && elementorFrontend.channels.editor) {
            elementorFrontend.channels.editor.on("change", function (changedModel) {
                if (!changedModel || changedModel.get("widgetType") !== "sifency-staggered-text") {
                    return;
                }
                const $widget = elementorFrontend.elements.$window
                    .find(`.elementor-element-${changedModel.get("id")}`)
                    .find(".sifency-anim-heading")
                    .closest(".elementor-widget-sifency-staggered-text");
                if ($widget.length) {
                    initStaggeredText($widget);
                }
            });
        }
    });
})(jQuery);
