jQuery(window).on('elementor/frontend/init', function () {

    elementorFrontend.hooks.addAction(
        'frontend/element_ready/sifency_scroll_bg_changer.default',
        function ($scope) {

            const $handler = $scope.find('.sifency-scroll-bg-handler');
            if (!$handler.length) return;

            let config;
            try {
                config = $handler.data('config');
            } catch (e) {
                console.warn('Scroll BG → invalid config', e);
                return;
            }

            const rawSteps = (config?.steps || []).filter(s => s.color && s.color.trim() !== '');

            if (!rawSteps.length) {
                console.warn('Scroll BG → no valid colour steps found. Please set a colour for each step in the widget settings.');
                return;
            }

            let $target;
            if (config.target === 'body') {
                $target = jQuery('body');
            } else if (config.target === 'parent') {
                $target = $scope.closest(
                    '.elementor-section, .e-con, section, .container, [data-elementor-type]'
                );
            } else if (config.target === 'custom' && config.custom) {
                $target = jQuery(config.custom);
            }

            if (!$target || !$target.length) {
                console.warn('Scroll BG → target not found');
                return;
            }

            $target.addClass('sifency-scroll-bg-target');

            const parseColorToRGB = (colorStr) => {
                if (!colorStr || !colorStr.trim()) return null;

                const el = document.createElement('div');
                el.style.display = 'none';
                el.style.color   = colorStr;
                document.body.appendChild(el);
                const computed = getComputedStyle(el).color;
                document.body.removeChild(el);

                if (!computed || computed === 'rgba(0, 0, 0, 0)') return null;

                const match = computed.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
                if (!match) {
                    console.warn('Scroll BG → could not parse colour:', colorStr);
                    return null;
                }
                return [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])];
            };

            // Build and sort steps; discard any whose colour fails to parse.
            const steps = rawSteps
                .map(step => {
                    const rgb = parseColorToRGB(step.color);
                    return rgb ? { point: parseFloat(step.point) || 0, rgb } : null;
                })
                .filter(Boolean)
                .sort((a, b) => a.point - b.point);

            if (steps.length < 1) {
                console.warn('Scroll BG → no parseable colour steps.');
                return;
            }

            // ── Interpolation helper ─────────────────────────────────────────
            const lerp = (a, b, t) => Math.round(a + (b - a) * t);

            // ── Core update ──────────────────────────────────────────────────
            let ticking = false;

            const updateBg = () => {
                const scrollTop = window.scrollY;
                const maxScroll = document.documentElement.scrollHeight - window.innerHeight;
                const progress  = maxScroll > 0 ? (scrollTop / maxScroll) * 100 : 0;

                let r, g, b;

                if (progress <= steps[0].point) {
                    [r, g, b] = steps[0].rgb;

                } else if (progress >= steps[steps.length - 1].point) {
                    [r, g, b] = steps[steps.length - 1].rgb;

                } else {
                    let from = steps[0];
                    let to   = steps[steps.length - 1];
                    let t    = 1;

                    for (let i = 0; i < steps.length - 1; i++) {
                        if (progress >= steps[i].point && progress <= steps[i + 1].point) {
                            from = steps[i];
                            to   = steps[i + 1];
                            const range = to.point - from.point;
                            t = range > 0 ? (progress - from.point) / range : 0;
                            break;
                        }
                    }

                    r = lerp(from.rgb[0], to.rgb[0], t);
                    g = lerp(from.rgb[1], to.rgb[1], t);
                    b = lerp(from.rgb[2], to.rgb[2], t);
                }

                $target.css('backgroundColor', `rgb(${r}, ${g}, ${b})`);
                ticking = false;
            };

            const onScroll = () => {
                if (!ticking) {
                    window.requestAnimationFrame(updateBg);
                    ticking = true;
                }
            };

            window.addEventListener('scroll', onScroll, { passive: true });
            updateBg();

            $scope.one('destroy', () => {
                window.removeEventListener('scroll', onScroll);
            });
        }
    );
});