(function ($) {
    "use strict";

    // ─────────────────────────────────────────────
    //  Animation preset definitions
    //  Each preset returns { from, to (prev card) }
    // ─────────────────────────────────────────────
    const ANIMATION_PRESETS = {

        'clip-reveal': {
            from: (i) => ({
                clipPath: 'inset(100% 0% 0% 0% round 24px)',
                y: 100,
                scale: 1,
                duration: 0.5,
                ease: 'power4.out',
                stagger: 0.1,
            }),
            inner: { opacity: 0, y: 30, duration: 0.5, ease: 'power3.out', stagger: 0.1 },
        },
        'slide-up': {
            from: (i) => ({
                y: 220,
                opacity: 0,
                skewY: 6,
                duration: 1.4,
                ease: 'power4.out',
            }),
            inner: { opacity: 0, y: 30, duration: 0.7, ease: 'power2.out', stagger: 0.08 },
        },
        'fade-scale': {
            from: (i) => ({
                opacity: 0,
                scale: 0.7,
                y: 60,
                rotateX: 15,
                duration: 1.2,
                ease: 'power3.out',
            }),
            inner: { opacity: 0, scale: 0.85, duration: 0.6, ease: 'back.out(1.5)', stagger: 0.1 },
        },
        'swipe-in': {
            from: (i) => ({
                x: i % 2 === 0 ? '100%' : '-100%',
                opacity: 0,
                rotateY: i % 2 === 0 ? 12 : -12,
                duration: 1.5,
                ease: 'expo.out',
            }),
            inner: { opacity: 0, x: 30, duration: 0.7, ease: 'power2.out', stagger: 0.08 },
        },
    };

    // ─────────────────────────────────────────────
    //  Progress indicator builder
    // ─────────────────────────────────────────────
    const buildProgressTracker = (container, count) => {
        const tracker = document.createElement('div');
        tracker.className = 'sifency-reveal-progress';
        tracker.setAttribute('aria-hidden', 'true');

        const dots = Array.from({ length: count }, (_, i) => {
            const dot = document.createElement('span');
            dot.className = 'srp-dot' + (i === 0 ? ' is-active' : '');
            tracker.appendChild(dot);
            return dot;
        });

        container.appendChild(tracker);

        const globalCounter = container.querySelector('.sgc-current');

        return {
            update: (activeIndex) => {
                dots.forEach((dot, i) => {
                    dot.classList.toggle('is-active', i === activeIndex);
                    dot.classList.toggle('is-revealed', i < activeIndex);
                });
                
                if (globalCounter) {
                    const num = String(activeIndex + 1).padStart(2, '0');
                    if (globalCounter.textContent !== num) {
                        globalCounter.textContent = num;
                    }
                }
            },
        };
    };

    // ─────────────────────────────────────────────
    //  Reveal layout main function
    // ─────────────────────────────────────────────
    const buildRevealTimeline = ({ container, cards, bgText, animation, speed, parallax, snap }) => {

        const preset = ANIMATION_PRESETS[animation] || ANIMATION_PRESETS['clip-reveal'];
        const cardCount = cards.length;

        // Perspective on the container for 3-D transforms
        gsap.set(container, { perspective: 1200, transformStyle: 'preserve-3d' });

        // All cards start stacked; first card is already visible
        gsap.set(cards, { position: 'absolute', inset: 0 });
        gsap.set(cards[0], { zIndex: 1 });

        // Build z-index stack upward
        cards.forEach((card, i) => gsap.set(card, { zIndex: i + 1 }));

        // Progress tracker
        const progress = buildProgressTracker(container, cardCount);

        // Main pinned timeline
        const tl = gsap.timeline({
            scrollTrigger: {
                trigger: container,
                start: 'top top',
                end: () => `+=${cardCount * speed}%`,
                pin: true,
                scrub: 2.2,
                anticipatePin: 1.5,
                snap: snap ? {
                    snapTo: 1 / (cardCount - 1),
                    duration: { min: 0.4, max: 1.2 },
                    delay: 0.15,
                    ease: 'power2.inOut'
                } : false,
                onUpdate: (self) => {
                    const idx = Math.min(
                        cardCount - 1,
                        Math.round(self.progress * (cardCount - 1))
                    );
                    progress.update(idx);
                },
            },
        });

        // ── Background text parallax ──────────────────────────
        if (parallax && bgText) {
            tl.to(bgText, {
                y: '-30%',
                scale: 0.85,
                opacity: 0,
                ease: 'none',
                duration: cardCount,
            }, 0);
        }

        // ── Per-card reveal sequence ──────────────────────────
        cards.forEach((card, i) => {
            if (i === 0) return;   // first card is baseline

            const offset = i;                    // timeline position
            const overlapStart = i - 0.35;             // slight overlap with prev push
            const fromVars = preset.from(i);
            const innerEls = card.querySelectorAll(
                '.sifency-card-title, .sifency-card-text, .sifency-card-tag, .sifency-card-media, [class*="sifency-card-"]'
            );

            // ① Incoming card
            tl.from(card, {
                ...fromVars,
                force3D: true,
                clearProps: 'clipPath,skewY,rotateX,rotateY,x',
            }, overlapStart);

            // ② Stagger inner elements for richness
            if (innerEls.length && preset.inner) {
                tl.from(innerEls, {
                    ...preset.inner,
                    force3D: true,
                    clearProps: 'opacity,y,x,scale',
                }, overlapStart + 0.15);
            }

            // ③ Push previous card back into depth
            tl.to(cards[i - 1], {
                scale: 0.90,
                y: -40,
                rotateX: -6,
                opacity: 0.15,
                duration: 1.4,
                ease: 'power3.inOut',
                force3D: true,
            }, overlapStart);
        });

        return tl;
    };

    // ─────────────────────────────────────────────
    //  Sticky layout main function
    // ─────────────────────────────────────────────
    const buildStickyTimeline = ({ container, cards, speed, cardsLayer, snap }) => {
        const cardCount = cards.length;
        const steps = Math.max(0, cardCount - 1);
        const FULL = "inset(0% round 0%)";
        const CLIPPED = "inset(50% round 0%)";

        // Initial setup
        cards.forEach((card, i) => {
            gsap.set(card, {
                zIndex: i + 1,
                pointerEvents: i === 0 ? "auto" : "none"
            });
            const inner = card.querySelector('.sa-revel-card-inner') || card;
            gsap.set(inner, {
                clipPath: i === 0 ? FULL : CLIPPED,
                autoAlpha: 1,
                willChange: "clip-path, opacity, transform"
            });

            const contentEls = card.querySelectorAll('.sa-reveal-card-rich-title, .card-rich-subtitle, .card-rich-desc, .card-rich-btn, .sa-revel-card-tag-simple');
            if (i > 0) {
                gsap.set(contentEls, { autoAlpha: 0 });
                const title = card.querySelector('.sa-reveal-card-rich-title');
                if (title) gsap.set(title, { yPercent: 100 });
            }
        });

        // Progress tracker
        const progress = buildProgressTracker(container, cardCount);

        const totalScroll = steps * (window.innerHeight * (speed / 100 || 1));

        const tl = gsap.timeline({
            defaults: { ease: "power2.out" },
            scrollTrigger: {
                trigger: container,
                start: "top top",
                end: () => "+=" + totalScroll,
                scrub: 0.6,
                pin: true,
                pinSpacing: true,
                anticipatePin: 1,
                invalidateOnRefresh: true,
                snap: snap ? {
                    snapTo: 1 / (cardCount - 1),
                    duration: { min: 0.2, max: 0.8 },
                    delay: 0.1,
                    ease: "power1.inOut"
                } : false,
                onUpdate: (self) => {
                    const idx = Math.min(cardCount - 1, Math.round(self.progress * (cardCount - 1)));
                    progress.update(idx);
                }
            }
        });

        cards.forEach((card, i) => {
            const inner = card.querySelector('.sa-revel-card-inner') || card;
            const contentEls = card.querySelectorAll('.sa-reveal-card-rich-title, .card-rich-subtitle, .card-rich-desc, .card-rich-btn, .sa-revel-card-tag-simple');
            const title = card.querySelector('.sa-reveal-card-rich-title');

            if (i === 0) {
                if (title) tl.to(title, { duration: 0.35, yPercent: 0 }, 0);
            } else {
                const prevCard = cards[i - 1];
                const prevContentEls = prevCard.querySelectorAll('.sa-reveal-card-rich-title, .card-rich-subtitle, .card-rich-desc, .card-rich-btn, .sa-revel-card-tag-simple');

                tl.to(inner, { duration: 0.6, clipPath: FULL }, "+=0.12");
                tl.set(card, { pointerEvents: "auto" }, "<");
                tl.set(prevCard, { pointerEvents: "none" }, "<");

                // Stagger fade out previous card content
                if (prevContentEls.length) {
                    tl.to(prevContentEls, {
                        autoAlpha: 0,
                        y: -40,
                        duration: 0.45,
                        stagger: 0.08,
                        ease: "power2.in"
                    }, "-=0.55");
                }

                // Fade in and move up current content
                if (contentEls.length) {
                    tl.to(contentEls, {
                        autoAlpha: 1,
                        y: 0,
                        duration: 0.5,
                        stagger: 0.1,
                    }, "<0.1");

                    // Special yPercent animation for title if it exists
                    if (title) {
                        tl.to(title, {
                            yPercent: 0,
                            duration: 0.4,
                            ease: "power2.out"
                        }, "<");
                    }
                }
            }
        });

        return tl;
    };

    // ─────────────────────────────────────────────
    //  Widget initialiser
    // ─────────────────────────────────────────────
    const initRevealShowcase = ($scope) => {
        const container = $scope.find('.sifency-reveal-container')[0];
        if (!container) return;

        const cardsLayer = $scope.find('.sifency-addons-reveal-cards-layer')[0];
        const cards = $scope.find('.sifency-addons-reveal-card').toArray();
        const bgText = $scope.find('.sifency-addons-reveal-bg-text')[0];

        if (!cards.length) return;

        const layout = container.dataset.layout || 'reveal';
        const speed = parseInt(container.dataset.speed, 10) || 100;
        const animation = container.dataset.animation || 'clip-reveal';
        const parallax = container.dataset.parallax === 'yes';
        const snap = container.dataset.snap === 'yes';

        if (typeof window.gsap === 'undefined' || typeof window.ScrollTrigger === 'undefined') {
            console.warn('Sifency: GSAP or ScrollTrigger is missing. Reveal Showcase animation disabled.');
            return;
        }

        gsap.registerPlugin(ScrollTrigger);
        
        const globalCounter = container.querySelector('.sgc-current');
        const updateGlobalCounter = (idx) => {
            if (globalCounter) {
                const num = String(idx + 1).padStart(2, '0');
                if (globalCounter.textContent !== num) {
                    globalCounter.textContent = num;
                }
            }
        };

        // ── GRID layout (unchanged) ────────────────────────────
        if (layout === 'grid') {

            const totalScroll = cardsLayer.offsetHeight - window.innerHeight;

            ScrollTrigger.create({
                trigger: container,
                start: 'top top',
                end: () => '+=' + totalScroll,
                pin: true,
                pinSpacing: true,
                scrub: 1,
                anticipatePin: 1,
                invalidateOnRefresh: true,
                animation: gsap.to(cardsLayer, {
                    y: -totalScroll,
                    ease: 'none',
                    force3D: true,
                }),
            });

            cards.forEach((card, index) => {
                gsap.fromTo(card,
                    { opacity: 0, scale: 0.8 },
                    {
                        opacity: 1,
                        scale: 1,
                        scrollTrigger: {
                            trigger: card,
                            start: 'top bottom',
                            end: 'top center',
                            scrub: true,
                            onEnter: () => updateGlobalCounter(index),
                            onEnterBack: () => updateGlobalCounter(index),
                        },
                    }
                );
            });

            // ── CLIP layout ──────────────────────────
        } else if (layout === 'clip') {
            let triggers = $scope.find('.sifency-addons-reveal-trigger').toArray();
            if (!triggers.length) triggers = cards;

            triggers.forEach((trigger, index) => {
                const item = cards[index];
                if (!item) return;

                const bg = trigger.querySelector('.sifency-addons-reveal-bg') || item.querySelector('.sifency-card-media');

                if (index === 0) {
                    gsap.timeline({
                        scrollTrigger: { 
                            trigger: trigger, start: "top top", end: "bottom top", scrub: true,
                            onEnter: () => updateGlobalCounter(index),
                            onEnterBack: () => updateGlobalCounter(index),
                        },
                        defaults: { ease: "none" },
                    }).fromTo(
                        item,
                        { clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)" },
                        { clipPath: "polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%)" }
                    );
                } else if (index === cards.length - 1) {
                    gsap.timeline({
                        scrollTrigger: { 
                            trigger: trigger, start: "top bottom", end: "bottom bottom", scrub: true,
                            onEnter: () => updateGlobalCounter(index),
                            onEnterBack: () => updateGlobalCounter(index),
                        },
                        defaults: { ease: "none" },
                    }).fromTo(
                        item,
                        { clipPath: "polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%)" },
                        { clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)" }
                    );
                } else {
                    const tl = gsap.timeline({
                        scrollTrigger: { 
                            trigger: trigger, start: "top bottom", end: "bottom top", scrub: true,
                            onEnter: () => updateGlobalCounter(index),
                            onEnterBack: () => updateGlobalCounter(index),
                        },
                        defaults: { ease: "none" },
                    });
                    tl.fromTo(
                        item,
                        { clipPath: "polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%)" },
                        { clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)" }
                    );
                    tl.to(item, { clipPath: "polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%)" });
                }

                if (bg) {
                    gsap.timeline({
                        scrollTrigger: { trigger: trigger, start: "top top", end: "bottom top", scrub: true },
                        defaults: { ease: "none" },
                    }).to(bg, { yPercent: 50 });
                }
            });

            // ── STICKY layout ──────────────────────────
        } else if (layout === 'sticky') {
            buildStickyTimeline({ container, cards, speed, cardsLayer, snap });

            // ── REVEAL layout (default) ──────────────────────────
        } else {
            buildRevealTimeline({ container, cards, bgText, animation, speed, parallax, snap });
        }

        // ── Cleanup on widget destroy ──────────────────────────
        $scope[0].addEventListener('sifency:destroy', () => {
            ScrollTrigger.getAll().forEach(st => st.kill());
        });
    };

    // ─────────────────────────────────────────────
    //  Elementor hook
    // ─────────────────────────────────────────────
    $(window).on('elementor/frontend/init', () => {
        elementorFrontend.hooks.addAction(
            'frontend/element_ready/sifency-reveal-showcase.default',
            initRevealShowcase
        );
    });

})(jQuery);