/**
 * Admin JavaScript - Modern UI
 *
 * @package Spin_Wheel
 */

(function ($) {
    'use strict';

    var swpGridLabelMeasureCanvasAdmin = null;

    function swpAdminGetGridLabelMeasureContext() {
        if (typeof document === 'undefined') {
            return null;
        }
        if (!swpGridLabelMeasureCanvasAdmin) {
            swpGridLabelMeasureCanvasAdmin = document.createElement('canvas');
        }
        return swpGridLabelMeasureCanvasAdmin.getContext('2d');
    }

    function swpAdminLuckyGridTextBlockTopPx(cellH, lineHeightPx, lineCount) {
        var h = Math.max(1, cellH);
        var lh = Math.max(1, lineHeightPx);
        var n = Math.max(1, lineCount);
        var topPx = h / 2 - (lh * (n + 1)) / 2;
        if (topPx < 0) {
            topPx = (h - n * lh) / 2;
        }
        return Math.max(0, Math.round(topPx));
    }

    function swpAdminNineSquaresPrizeIsRenderable(prize) {
        if (!prize) {
            return false;
        }
        var hasImg = prize.imgs && prize.imgs.length > 0
            && prize.imgs.some(function (img) {
                return img && String(img.src || '').trim();
            });
        var rawText = prize.fonts && prize.fonts[0]
            ? String(prize.fonts[0].text || '').replace(/\n/g, ' ').trim()
            : '';
        return hasImg || rawText.length > 0;
    }

    function swpAdminBuildGridLabelLines(ctx, rawText, maxWidth, maxLines) {
        if (!ctx) {
            var single = (rawText || '').toString().replace(/\s+/g, ' ').trim();
            return [single || ''];
        }
        var text = (rawText || '').toString().replace(/\s+/g, ' ').trim();
        if (!text) {
            return [''];
        }
        maxLines = Math.max(1, maxLines);
        var words = text.split(' ');
        var ell = '\u2026';
        var tw = function (s) {
            return ctx.measureText(s).width;
        };

        var clipWord = function (word) {
            if (tw(word) <= maxWidth) {
                return word;
            }
            var w = word;
            while (w.length > 1 && tw(w + ell) > maxWidth) {
                w = w.slice(0, -1);
            }
            return w + ell;
        };

        var lines = [];
        var wi = 0;

        while (wi < words.length && lines.length < maxLines) {
            var onLastLine = (lines.length === maxLines - 1);

            if (onLastLine) {
                var rest = words.slice(wi).join(' ');
                if (tw(rest) <= maxWidth) {
                    lines.push(rest);
                    break;
                }
                var line = '';
                while (wi < words.length) {
                    var w = words[wi];
                    var trial = line ? (line + ' ' + w) : w;
                    if (tw(trial) <= maxWidth) {
                        line = trial;
                        wi++;
                    } else {
                        break;
                    }
                }
                if (!line) {
                    lines.push(clipWord(words[wi]));
                    wi++;
                } else if (wi < words.length) {
                    var t = line;
                    while (t.length && tw(t + ell) > maxWidth) {
                        var sp = t.lastIndexOf(' ');
                        if (sp > 0) {
                            t = t.slice(0, sp);
                        } else {
                            t = t.slice(0, -1);
                        }
                    }
                    lines.push((t || line) + ell);
                } else {
                    lines.push(line);
                }
                break;
            }

            var line2 = '';
            while (wi < words.length) {
                var w2 = words[wi];
                var trial2 = line2 ? (line2 + ' ' + w2) : w2;
                if (tw(trial2) <= maxWidth) {
                    line2 = trial2;
                    wi++;
                } else {
                    break;
                }
            }
            if (line2) {
                lines.push(line2);
            } else if (wi < words.length) {
                lines.push(clipWord(words[wi]));
                wi++;
            }
        }

        return lines.length ? lines : [''];
    }

    function swpAdminFinalizeNineSquaresPrizeFontLayout(prize, cellW, cellH, styles) {
        if (!prize || !prize.fonts || !prize.fonts.length) {
            return;
        }
        var f = prize.fonts[0];
        var raw = String(f.text || '').replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
        if (!raw) {
            return;
        }
        var st = styles || {};
        var fontSize = parseInt(String(f.fontSize || '').replace(/px/g, '').trim(), 10)
            || parseInt(st.prize_font_size, 10)
            || parseInt(st.font_size, 10)
            || 16;
        var lineHeight = parseInt(String(f.lineHeight || '').replace(/px/g, '').trim(), 10);
        if (!isFinite(lineHeight) || lineHeight < 1) {
            lineHeight = parseInt(st.prize_line_height, 10) || fontSize;
        }
        lineHeight = Math.max(fontSize, lineHeight);
        var fontWeight = f.fontWeight || st.prize_font_weight || st.font_weight || '400';
        var fontFamily = f.fontStyle || st.font_style || 'Arial';

        var radialLayout = st.swp_preview_radial === true;
        var maxLines = radialLayout
            ? 2
            : Math.max(1, parseInt(st.line_clamp, 10) || 3);
        var limitPct = Math.min(100, Math.max(30, parseInt(st.length_limit, 10) || 90));
        var maxWidth = Math.max(32, (Math.max(1, cellW) * limitPct) / 100 - 6);

        var ctx = swpAdminGetGridLabelMeasureContext();
        if (ctx) {
            ctx.font = fontWeight + ' ' + fontSize + 'px ' + fontFamily;
        }
        var lines = swpAdminBuildGridLabelLines(ctx, raw, maxWidth, maxLines);
        f.text = lines.join('\n');
        f.wordWrap = false;
        f.lineHeight = lineHeight + 'px';

        var hasImage = prize.imgs && prize.imgs.length;
        var h = Math.max(1, cellH);
        var topPx;
        if (hasImage) {
            var imgTopBase = Math.round(h * 0.14);
            var imgTop = imgTopBase + (parseInt(st.prize_image_top, 10) || 0);
            var imgSize = parseInt(st.prize_image_size, 10) || parseInt(st.prize_image_width, 10) || 70;
            var reservedTop = Math.min(h - lineHeight, imgTop + imgSize + Math.max(4, Math.round(fontSize * 0.22)));
            var zoneH = Math.max(lineHeight, h - reservedTop);
            topPx = reservedTop + Math.max(0, (zoneH - lines.length * lineHeight) / 2);
            topPx = Math.max(0, Math.min(topPx, h - lines.length * lineHeight));
        } else if (radialLayout && lines.length === 1) {
            var fs0 = Math.max(1, fontSize);
            var lh0 = Math.max(1, lineHeight);
            topPx = (h / 2) + 0.35 * fs0 - lh0;
            topPx = Math.max(0, Math.min(topPx, h - lh0 - 1));
            topPx = Math.round(topPx);
        } else {
            topPx = swpAdminLuckyGridTextBlockTopPx(h, lineHeight, lines.length);
        }
        f.top = Math.round(topPx) + 'px';
    }

    $(document).ready(function () {

        /**
         * Match "Maximum Participants" pattern: label + ? tooltip. Moves first .swp-hint in the row into the label and hides the hint.
         */
        function swpSyncLabelTooltipsFromHints($root) {
            $root.find('.swp-form-row').each(function () {
                var $row = $(this);
                var $label = $row.children('label.swp-label').first();
                if (!$label.length || $label.find('.swp-tooltip-wrapper').length) {
                    return;
                }
                var $hint = $row.find('.swp-hint').not('.swp-hint--in-label').not('.swp-time-display').first();
                if (!$hint.length || $hint.hasClass('swp-hint--in-label')) {
                    return;
                }
                var text = $hint.text().replace(/\s+/g, ' ').trim();
                if (!text) {
                    return;
                }
                var $tw = $('<span class="swp-tooltip-wrapper"><span class="swp-tooltip-icon" aria-hidden="true">?</span><span class="swp-tooltip-text" role="tooltip"></span></span>');
                $tw.find('.swp-tooltip-text').text(text);
                $label.append($tw);
                $hint.addClass('swp-hint--in-label').attr('hidden', 'hidden');
            });
        }

        swpSyncLabelTooltipsFromHints($('.swp-modern-editor'));

        // ========================================================================
        // Preview Offcanvas Toggle
        // ========================================================================
        $('#swp-preview-toggle').on('click', function () {
            $('#swp-preview-offcanvas').addClass('active');
            // Refresh preview when opened
            setTimeout(function () {
                refreshPreview();
            }, 300);
        });

        $('#swp-preview-close').on('click', function () {
            $('#swp-preview-offcanvas').removeClass('active');
        });

        // Close on ESC key
        $(document).on('keydown', function (e) {
            if (e.key === 'Escape' && $('#swp-preview-offcanvas').hasClass('active')) {
                $('#swp-preview-offcanvas').removeClass('active');
            }
        });

        // ========================================================================
        // Accordion Functionality
        // ========================================================================
        $(document).on('click', '.swp-accordion-header', function (e) {
            e.preventDefault();
            const $item = $(this).closest('.swp-accordion-item');
            const wasActive = $item.hasClass('active');

            // Toggle current item
            if (wasActive) {
                $item.removeClass('active');
            } else {
                // Close all other accordions
                $('.swp-accordion-item').removeClass('active');
                // Open clicked accordion
                $item.addClass('active');
            }
        });

        // ========================================================================
        // Slider Sync Functionality
        // ========================================================================

        // Sync slider with number input for all range controls
        $('.swp-range-slider').on('input', function () {
            const value = $(this).val();
            const target = $(this).data('target');
            const $target = $(target);
            const isPercentage = $target.attr('id') === 'swp_prize_text_top' ||
                $target.hasClass('percentage-control');
            const isPrizeImgOffsetPx = $target.attr('id') === 'swp_prize_image_left' ||
                $target.attr('id') === 'swp_prize_image_top';
            const isRotation = $target.attr('id') === 'swp_prize_text_rotation' ||
                $target.attr('id') === 'swp_wheel_offset_degree' ||
                $target.attr('id')?.includes('rotation') ||
                $target.attr('id')?.includes('degree');
            const unit = isPercentage ? '%' : (isPrizeImgOffsetPx ? 'px' : (isRotation ? '°' : 'px'));

            $target.val(value).trigger('input');
            $(this).siblings('.swp-slider-value').text(value + unit);
        });

        // Sync number input with slider
        $('.swp-input-with-slider-inline .swp-input').on('input', function () {
            const value = $(this).val();
            const $slider = $(this).siblings('.swp-range-slider');
            const isPercentage = $(this).attr('id') === 'swp_prize_text_top' ||
                $(this).hasClass('percentage-control');
            const isPrizeImgOffsetPx = $(this).attr('id') === 'swp_prize_image_left' ||
                $(this).attr('id') === 'swp_prize_image_top';
            const isRotation = $(this).attr('id') === 'swp_prize_text_rotation' ||
                $(this).attr('id') === 'swp_wheel_offset_degree' ||
                $(this).attr('id')?.includes('rotation') ||
                $(this).attr('id')?.includes('degree');
            const unit = isPercentage ? '%' : (isPrizeImgOffsetPx ? 'px' : (isRotation ? '°' : 'px'));

            $slider.val(value);
            $(this).siblings('.swp-slider-value').text(value + unit);
        });

        // Initialize slider values on page load
        $('.swp-input-with-slider-inline').each(function () {
            const $input = $(this).find('.swp-input');
            const value = $input.val();
            const isPercentage = $input.attr('id') === 'swp_prize_text_top' ||
                $input.hasClass('percentage-control');
            const isPrizeImgOffsetPx = $input.attr('id') === 'swp_prize_image_left' ||
                $input.attr('id') === 'swp_prize_image_top';
            const isRotation = $input.attr('id') === 'swp_prize_text_rotation' ||
                $input.attr('id') === 'swp_wheel_offset_degree' ||
                $input.attr('id')?.includes('rotation') ||
                $input.attr('id')?.includes('degree');
            const unit = isPercentage ? '%' : (isPrizeImgOffsetPx ? 'px' : (isRotation ? '°' : 'px'));
            $(this).find('.swp-slider-value').text(value + unit);
        });

        // ========================================================================
        // Initialize Color Pickers
        // ========================================================================
        function initializeColorPickers() {
            if ($.fn.wpColorPicker) {
                $('.swp-color-picker:not(.wp-color-picker)').each(function () {
                    const $input = $(this);
                    const currentColor = $input.val();

                    $input.wpColorPicker({
                        change: function (event, ui) {
                            // Update preview on color change
                            $(this).trigger('input');
                            refreshPreview();
                        },
                        // Ensure the picker shows the saved color
                        defaultColor: currentColor,
                        palettes: true
                    });

                    // Set the color after initialization to ensure it displays correctly
                    if (currentColor) {
                        setTimeout(function () {
                            $input.wpColorPicker('color', currentColor);
                        }, 50);
                    }
                });
            }
        }

        // Initialize color pickers on page load
        initializeColorPickers();

        // Re-initialize when switching to prizes tab (to handle saved prizes)
        $(document).on('click', '[data-tab="prizes"]', function () {
            setTimeout(function () {
                initializeColorPickers();
            }, 100);
        });

        // ========================================================================
        // WordPress Media Uploader for Prize Images
        // ========================================================================

        $(document).on('click', '.swp-upload-image', function (e) {
            e.preventDefault();

            const $button = $(this);
            const $wrapper = $button.closest('.swp-image-upload-wrapper');
            const $input = $wrapper.find('.swp-image-url');
            const $previewWrapper = $wrapper.find('.swp-image-preview-wrapper');
            const $img = $previewWrapper.find('.swp-prize-image');

            // Create a new media uploader instance each time
            const mediaUploader = wp.media({
                title: 'Select Prize Image',
                button: {
                    text: 'Use this image'
                },
                multiple: false,
                library: {
                    type: 'image'
                }
            });

            // When an image is selected, run a callback
            mediaUploader.on('select', function () {
                const attachment = mediaUploader.state().get('selection').first().toJSON();

                // Set the image URL in hidden input
                $input.val(attachment.url);

                // Update image preview
                $img.attr('src', attachment.url);

                // Hide upload button, show preview
                $button.hide();
                $previewWrapper.show();

                // Refresh preview
                refreshPreview();
            });

            // Open the uploader
            mediaUploader.open();
        });

        // Remove image handler
        $(document).on('click', '.swp-remove-image', function (e) {
            e.preventDefault();

            const $button = $(this);
            const $wrapper = $button.closest('.swp-image-upload-wrapper');
            const $input = $wrapper.find('.swp-image-url');
            const $uploadBtn = $wrapper.find('.swp-upload-image');
            const $previewWrapper = $button.closest('.swp-image-preview-wrapper');
            const $img = $previewWrapper.find('.swp-prize-image');

            // Clear image URL
            $input.val('');
            $img.attr('src', '');

            // Hide preview, show upload button
            $previewWrapper.hide();
            $uploadBtn.show();

            // Refresh preview
            refreshPreview();
        });

        // ========================================================================
        // Settings Image Upload (Modern UI - Click to Upload/Change)
        // ========================================================================
        let settingsMediaUploader;

        // Click on upload area (placeholder or image) to open media uploader
        $(document).on('click', '.swp-image-upload-area', function (e) {
            // Don't trigger if clicking the remove icon
            if ($(e.target).closest('.swp-remove-image-icon').length) {
                return;
            }

            e.preventDefault();

            const $uploadArea = $(this);
            const targetId = $uploadArea.data('target');
            const $input = $('#' + targetId);
            const $placeholder = $uploadArea.find('.swp-upload-placeholder');
            const $previewContainer = $uploadArea.find('.swp-image-preview-container');
            const $previewImg = $previewContainer.find('.swp-preview-image');

            // Create the media uploader
            settingsMediaUploader = wp.media({
                title: 'Select Image',
                button: {
                    text: 'Use this image'
                },
                multiple: false,
                library: {
                    type: 'image'
                }
            });

            // When an image is selected, run a callback
            settingsMediaUploader.on('select', function () {
                const attachment = settingsMediaUploader.state().get('selection').first().toJSON();

                // Set the image URL in hidden input
                $input.val(attachment.url).trigger('change');

                // Update preview image
                $previewImg.attr('src', attachment.url);

                // Show preview, hide placeholder
                $placeholder.hide();
                $previewContainer.show();

                // Refresh preview if in design tab
                if (typeof updatePopupPreview === 'function') {
                    updatePopupPreview();
                }
            });

            // Open the uploader
            settingsMediaUploader.open();
        });

        // Remove image handler (icon on top of image)
        $(document).on('click', '.swp-remove-image-icon', function (e) {
            e.preventDefault();
            e.stopPropagation(); // Prevent triggering the upload area click

            const $button = $(this);
            const $uploadArea = $button.closest('.swp-image-upload-area');
            const targetId = $uploadArea.data('target');
            const $input = $('#' + targetId);
            const $placeholder = $uploadArea.find('.swp-upload-placeholder');
            const $previewContainer = $uploadArea.find('.swp-image-preview-container');
            const $previewImg = $previewContainer.find('.swp-preview-image');

            // Clear image URL
            $input.val('').trigger('change');

            // Clear preview image
            $previewImg.attr('src', '');

            // Hide preview, show placeholder
            $previewContainer.hide();
            $placeholder.show();

            // Refresh preview if in design tab
            if (typeof updatePopupPreview === 'function') {
                updatePopupPreview();
            }
        });

        // ========================================================================
        // Tab Navigation
        // ========================================================================

        // Restore last active tab from localStorage on page load
        const savedTab = localStorage.getItem('swp_active_tab');
        if (savedTab) {
            // Remove all active states
            $('.swp-tab-btn').removeClass('active');
            $('.swp-tab-content').removeClass('active');

            // Activate saved tab
            $('.swp-tab-btn[data-tab="' + savedTab + '"]').addClass('active');
            $('#tab-' + savedTab).addClass('active');
        }

        $('.swp-tab-btn').on('click', function () {
            const tabId = $(this).data('tab');

            // Update active state
            $('.swp-tab-btn').removeClass('active');
            $(this).addClass('active');

            // Show corresponding tab content
            $('.swp-tab-content').removeClass('active');
            $('#tab-' + tabId).addClass('active');

            // Save active tab to localStorage
            localStorage.setItem('swp_active_tab', tabId);
        });

        // ========================================================================
        // Prize List Sorting - DISABLED
        // ========================================================================
        // Drag and drop functionality disabled to prevent manual reordering
        // if ($.fn.sortable) {
        //     $('#swp-prizes-list').sortable({
        //         handle: '.swp-prize-drag',
        //         axis: 'y',
        //         cursor: 'move',
        //         opacity: 0.8,
        //         placeholder: 'swp-prize-placeholder',
        //         start: function (e, ui) {
        //             ui.placeholder.height(ui.item.height());
        //         },
        //         update: function (event, ui) {
        //             updatePrizeIndices();
        //             calculateTotalProbability();
        //             refreshPreview();
        //         }
        //     });
        // }

        // Update prize indices after sorting/removal
        function updatePrizeIndices() {
            $('#swp-prizes-list .swp-prize-row').each(function (index) {
                $(this).attr('data-index', index);
                $(this).find('input, select, textarea').each(function () {
                    const name = $(this).attr('name');
                    if (name) {
                        const newName = name.replace(/\[\d+\]/, '[' + index + ']');
                        $(this).attr('name', newName);
                    }
                });
            });
        }

        // ========================================================================
        // Prize Management
        // ========================================================================
        let prizeIndex = $('#swp-prizes-list .swp-prize-row').length;

        // Generate random vibrant color
        function generateRandomColor() {
            // Predefined palette of vibrant, appealing colors
            const colorPalette = [
                '#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8',
                '#F7DC6F', '#BB8FCE', '#85C1E2', '#F8B739', '#52B788',
                '#E76F51', '#F4A261', '#E9C46A', '#2A9D8F', '#264653',
                '#8338EC', '#FF006E', '#FB5607', '#FFBE0B', '#3A86FF',
                '#06FFA5', '#FF477E', '#7209B7', '#F72585', '#4361EE',
                '#23967F', '#C9184A', '#F77F00', '#06D6A0', '#118AB2',
                '#EF476F', '#FFD166', '#06D6A0', '#118AB2', '#073B4C',
                '#FF9B71', '#6A4C93', '#1982C4', '#8AC926', '#FFCA3A'
            ];

            // Return a random color from the palette
            return colorPalette[Math.floor(Math.random() * colorPalette.length)];
        }

        // Add Prize
        $('#swp-add-prize').on('click', function () {
            const template = $('#swp-prize-template').html();
            const randomColor = generateRandomColor();
            const html = template.replace(/{{index}}/g, prizeIndex).replace(/#ff6b6b/g, randomColor);

            $('#swp-prizes-list').append(html);

            // Reinitialize color pickers for new prize
            $('#swp-prizes-list').find('.swp-color-picker:not(.wp-color-picker)').each(function () {
                $(this).wpColorPicker({
                    change: function (event, ui) {
                        // Trigger preview refresh on color change
                        setTimeout(function () {
                            refreshPreview();
                        }, 100);
                    }
                });
            });

            prizeIndex++;
            calculateTotalProbability();
            refreshPreview();
        });

        // Remove Prize
        $(document).on('click', '.swp-remove-prize', function (e) {
            e.stopPropagation();

            if (confirm(swpAdminData.confirmDelete || 'Are you sure you want to delete this prize?')) {
                $(this).closest('.swp-prize-row').remove();
                updatePrizeIndices();
                calculateTotalProbability();
                refreshPreview();
            }
        });

        // Update probability when changed
        $(document).on('input change', '.swp-probability-input', function () {
            calculateTotalProbability();
        });

        // Calculate total probability
        function calculateTotalProbability() {
            let total = 0;
            $('.swp-probability-input').each(function () {
                total += parseFloat($(this).val()) || 0;
            });

            $('#swp-total-probability').text(total.toFixed(1));

            // Change color based on total
            const $totalEl = $('#swp-total-probability');
            if (Math.abs(total - 100) < 0.1) {
                $totalEl.css('color', '#46b450'); // Green
            } else {
                $totalEl.css('color', '#d63638'); // Red
            }
        }

        // Initialize probability total
        calculateTotalProbability();

        // ========================================================================
        // Range Sliders
        // ========================================================================
        $(document).on('input', '.swp-range-slider', function () {
            const value = $(this).val();
            const targetId = $(this).data('target');
            $(targetId).val(value).trigger('input');

            // Determine the correct unit
            const $target = $(targetId);
            const isPercentage = $target.attr('id') === 'swp_prize_text_top' ||
                $target.hasClass('percentage-control');
            const isPrizeImgOffsetPx = $target.attr('id') === 'swp_prize_image_left' ||
                $target.attr('id') === 'swp_prize_image_top';
            const isRotation = $target.attr('id') === 'swp_prize_text_rotation' ||
                $target.attr('id') === 'swp_wheel_offset_degree' ||
                $target.attr('id')?.includes('rotation') ||
                $target.attr('id')?.includes('degree');
            const unit = isPercentage ? '%' : (isPrizeImgOffsetPx ? 'px' : (isRotation ? '°' : 'px'));

            // Update slider value display
            $(this).siblings('.swp-slider-value').text(value + unit);
        });

        // Sync number input with slider
        $(document).on('input', 'input[type="number"].swp-input', function () {
            const value = $(this).val();
            const $slider = $(this).siblings('.swp-range-slider');
            if ($slider.length) {
                $slider.val(value);
                // Determine the correct unit
                const isPercentage = $(this).attr('id') === 'swp_prize_text_top' ||
                    $(this).hasClass('percentage-control');
                const isPrizeImgOffsetPx = $(this).attr('id') === 'swp_prize_image_left' ||
                    $(this).attr('id') === 'swp_prize_image_top';
                const isRotation = $(this).attr('id') === 'swp_prize_text_rotation' ||
                    $(this).attr('id') === 'swp_wheel_offset_degree' ||
                    $(this).attr('id')?.includes('rotation') ||
                    $(this).attr('id')?.includes('degree');
                const unit = isPercentage ? '%' : (isPrizeImgOffsetPx ? 'px' : (isRotation ? '°' : 'px'));
                // Update display
                $slider.siblings('.swp-slider-value').text(value + unit);
            }
        });

        // ========================================================================
        // Live Preview (Debounced)
        // ========================================================================
        let previewTimeout;
        let wheelPreviewInstance = null;

        $(document).on('input change', '.swp-trigger-preview', function () {
            clearTimeout(previewTimeout);
            if (this.id === 'swp_grid_border_radius') {
                updateDesignSections();
            }
            previewTimeout = setTimeout(function () {
                refreshPreview();
            }, 500);
        });

        // Refresh preview when image URL changes
        $(document).on('input change', '.swp-image-url', function () {
            clearTimeout(previewTimeout);
            previewTimeout = setTimeout(function () {
                refreshPreview();
            }, 500);
        });

        // Refresh preview button
        $('.swp-refresh-preview').on('click', function () {
            refreshPreview();
        });

        function refreshPreview() {
            if (!window.LuckyCanvas) {
                $('#swp-live-preview').html('<p style="text-align:center;color:#d63638;">' + (swpAdminData.luckyCanvasNotLoaded || 'Lucky Canvas library not loaded.') + '</p>');
                return;
            }

            const $preview = $('#swp-live-preview');

            // Get current form values
            const wheelType = $('#swp_wheel_type').val() || 'big_wheel';
            const prizes = collectPrizesData();
            const styles = collectStylesData();

            if (prizes.length === 0) {
                $preview.html('<p style="text-align:center;color:#646970;">' + (swpAdminData.addPrizesToPreview || 'Add prizes to see preview') + '</p>');
                return;
            }

            // Clear and create canvas
            $preview.html('<div id="swp-admin-preview-canvas" style="margin: 20px auto;"></div>');

            // Render wheel based on type
            try {
                switch (wheelType) {
                    case 'big_wheel':
                        renderBigWheelPreview(prizes, styles);
                        break;
                    case 'nine_squares':
                        renderNineSquaresPreview(prizes, styles);
                        break;
                    case 'slot_machine':
                        renderSlotMachinePreview(prizes, styles);
                        break;
                }
            } catch (error) {
                console.error('Preview error:', error);
                $preview.html('<p style="text-align:center;color:#d63638;">' + (swpAdminData.previewError || 'Preview error. Check console.') + '</p>');
            }
        }

        function collectPrizesData() {
            const prizes = [];
            const prizeRepresentation = $('#swp_prize_representation').val() || 'label'; // Get prize representation setting

            $('#swp-prizes-list .swp-prize-row').each(function () {
                const $item = $(this);
                const rawLabel = ($item.find('.swp-prize-label-input').val() || '').toString().replace(/\s+/g, ' ').trim();
                const image = ($item.find('.swp-image-url').val() || '').trim();

                if (prizeRepresentation === 'image') {
                    if (!image) {
                        return;
                    }
                } else if (prizeRepresentation === 'both') {
                    if (!image && !rawLabel) {
                        return;
                    }
                } else if (!rawLabel) {
                    return;
                }

                const label = rawLabel || (swpAdminData.prizeLabelFallback || 'Prize');
                const color = $item.find('.swp-prize-color-input').val() || '#ff6b6b';
                const prizeData = {
                    label: label,
                    color: color,
                    probability: parseFloat($item.find('.swp-probability-input').val()) || 0,
                    background: color
                };

                // Get prize styling settings
                const imageSize = parseInt($('#swp_prize_image_size').val()) || parseInt($('#swp_prize_image_width_hidden').val()) || 70;
                const imageTop = parseInt($('#swp_prize_image_top').val(), 10);
                const imageTopPx = Number.isFinite(imageTop) ? imageTop : 0;
                const imageLeft = parseInt($('#swp_prize_image_left').val(), 10);
                const imageLeftPx = Number.isFinite(imageLeft) ? imageLeft : 0;
                const textTop = parseInt($('#swp_prize_text_top').val()) || 15;
                const prizeFontSize = parseInt($('#swp_prize_font_size').val()) || 16;
                const prizeFontWeight = $('#swp_prize_font_weight').val() || '600';
                const prizeFontColor = $('#swp_prize_font_color').val() || '#000000';
                const prizeLineHeight = parseInt($('#swp_prize_line_height').val()) || 14;
                const prizeTextTopNoImage = parseInt($('#swp_prize_text_top_no_image').val()) || 30;

                // Handle different prize representations (matching frontend logic)
                const prizeImgLayout = {
                    width: imageSize + 'px',
                    height: imageSize + 'px',
                    left: imageLeftPx + 'px',
                    top: imageTopPx + 'px'
                };

                if (prizeRepresentation === 'image' && image && image.trim()) {
                    // Image Only - no text label
                    prizeData.imgs = [{
                        src: image,
                        ...prizeImgLayout
                    }];
                } else if (prizeRepresentation === 'both' && image && image.trim()) {
                    // Both - image with text label
                    prizeData.imgs = [{
                        src: image,
                        ...prizeImgLayout
                    }];
                    prizeData.fonts = [{
                        text: label,
                        top: textTop + '%',
                        fontSize: prizeFontSize + 'px',
                        fontWeight: prizeFontWeight,
                        fontColor: prizeFontColor,
                        lineHeight: prizeLineHeight + 'px'
                    }];
                } else {
                    // Label Only (default) - text only, centered
                    prizeData.fonts = [{
                        text: label,
                        top: prizeTextTopNoImage + '%',
                        fontSize: prizeFontSize + 'px',
                        fontWeight: prizeFontWeight,
                        fontColor: prizeFontColor
                    }];
                }

                prizes.push(prizeData);
            });
            return prizes;
        }

        function collectStylesData() {
            // For Big Wheel, check if we're using the Size field or separate Width/Height
            let width, height;
            if ($('#swp_wheel_type').val() === 'big_wheel') {
                const size = parseInt($('#swp_size').val()) || 460;
                width = size;
                height = size;
            } else {
                width = parseInt($('#swp_width').val()) || 460;
                height = parseInt($('#swp_height').val()) || 460;
            }

            // Get blocks and buttons config from hidden fields (set by presets)
            const blocksConfig = $('#swp_blocks_config').val() || '';
            const buttonsConfig = $('#swp_buttons_config').val() || '';

            return {
                width: width,
                height: height,
                background_color: $('#swp_background_color').val() || '#ffffff',
                padding: parseInt($('#swp_padding').val()) || 0,
                button_text: $('#swp_button_text').val() || 'SPIN',
                button_font_size: parseInt($('#swp_button_font_size').val()) || 18,
                button_text_top: $('#swp_button_text_top').val() !== '' ? parseInt($('#swp_button_text_top').val()) : -10,
                button_radius: parseInt($('#swp_button_radius').val()) || 50,
                show_pointer: $('input[name="swp_styles[show_pointer]"]').is(':checked') ? 1 : 0,
                button_color: $('#swp_button_color').val() || '#ff6b6b',
                button_text_color: $('#swp_button_text_color').val() || '#ffffff',
                font_size: parseInt($('#swp_font_size').val()) || 18,
                font_weight: $('#swp_font_weight').val() || '400',
                gutter: parseInt($('#swp_wheel_gutter').val()) || 0,
                offset_degree: parseInt($('#swp_wheel_offset_degree').val()) || 0,
                stop_range: parseFloat($('#swp_wheel_stop_range').val()) || 0,
                prize_text_rotation: parseInt($('#swp_prize_text_rotation').val()) || 0,
                prize_text_offset_x: parseInt($('#swp_prize_text_offset_x').val()) || 0,
                prize_text_offset_y: parseInt($('#swp_prize_text_offset_y').val()) || 0,
                prize_image_left: parseInt($('#swp_prize_image_left').val(), 10) || 0,
                prize_image_top: parseInt($('#swp_prize_image_top').val(), 10) || 0,
                prize_image_rotation: parseInt($('#swp_prize_image_rotation').val(), 10) || 0,
                prize_font_size: parseInt($('#swp_prize_font_size').val(), 10) || 16,
                prize_line_height: parseInt($('#swp_prize_line_height').val(), 10) || 14,
                prize_image_size: parseInt($('#swp_prize_image_size').val(), 10)
                    || parseInt($('#swp_prize_image_width_hidden').val(), 10) || 70,
                prize_image_width: parseInt($('#swp_prize_image_width_hidden').val(), 10) || 70,
                blocks_config: blocksConfig,
                buttons_config: buttonsConfig,
                grid_border_radius: parseInt($('#swp_grid_border_radius').val(), 10) || 0,
                grid_panel_border_radius: parseInt($('#swp_grid_panel_border_radius').val(), 10) || 0,
                grid_default_background: $('#swp_grid_default_background').val() || '',
                active_preset: ($('#swp_active_preset').val() || 'default').toString(),
                line_clamp: 3,
                length_limit: 90
            };
        }

        function renderBigWheelPreview(prizes, styles) {
            // Destroy previous instance
            if (wheelPreviewInstance && wheelPreviewInstance.destroy) {
                wheelPreviewInstance.destroy();
            }

            wheelPreviewInstance = new window.LuckyCanvas.LuckyWheel('#swp-admin-preview-canvas', {
                width: styles.width + 'px',
                height: styles.height + 'px',
                blocks: (() => {
                    // Check if we have saved blocks configuration from presets
                    if (styles.blocks_config) {
                        try {
                            const blocksConfig = JSON.parse(styles.blocks_config);
                            if (Array.isArray(blocksConfig) && blocksConfig.length > 0) {
                                return blocksConfig;
                            }
                        } catch (e) {
                            console.warn('Failed to parse blocks_config:', e);
                        }
                    }
                    // Check if blocks_config field exists in the form
                    const $blocksField = $('#swp_blocks_config');
                    if ($blocksField.length && $blocksField.val()) {
                        try {
                            const blocksConfig = JSON.parse($blocksField.val());
                            if (Array.isArray(blocksConfig) && blocksConfig.length > 0) {
                                return blocksConfig;
                            }
                        } catch (e) {
                            console.warn('Failed to parse blocks_config from field:', e);
                        }
                    }
                    // Fallback to default block
                    return [
                        {
                            padding: (styles.padding || 0) + 'px',
                            background: styles.background_color || '#ffffff'
                        }
                    ];
                })(),
                prizes: prizes,
                buttons: (() => {
                    // Check if we have saved buttons configuration from presets
                    if (styles.buttons_config) {
                        try {
                            const buttonsConfig = JSON.parse(styles.buttons_config);
                            if (Array.isArray(buttonsConfig) && buttonsConfig.length > 0) {
                                return buttonsConfig;
                            }
                        } catch (e) {
                            console.warn('Failed to parse buttons_config in preview:', e);
                        }
                    }
                    // Check if buttons_config field exists in the form
                    const $buttonsField = $('#swp_buttons_config');
                    if ($buttonsField.length && $buttonsField.val()) {
                        try {
                            const buttonsConfig = JSON.parse($buttonsField.val());
                            if (Array.isArray(buttonsConfig) && buttonsConfig.length > 0) {
                                return buttonsConfig;
                            }
                        } catch (e) {
                            console.warn('Failed to parse buttons_config from field:', e);
                        }
                    }
                    // Fallback to default button
                    return [
                        {
                            radius: (styles.button_radius || 50) + 'px',
                            pointer: !!styles.show_pointer,
                            background: styles.button_color || '#ff6b6b',
                            cursor: 'pointer',
                            fonts: [
                                {
                                    text: styles.button_text || 'SPIN',
                                    top: (styles.button_text_top !== undefined ? styles.button_text_top : -10) + 'px',
                                    fontSize: (styles.button_font_size || 18) + 'px',
                                    lineHeight: (styles.button_font_size || 18) + 'px',
                                    fontWeight: styles.font_weight || '700',
                                    fontColor: styles.button_text_color || '#ffffff'

                                }
                            ]
                        }
                    ];
                })(),
                defaultConfig: {
                    gutter: styles.gutter || 0,
                    stopRange: styles.stop_range || 0,
                    offsetDegree: styles.offset_degree || 0
                },
                defaultStyle: {
                    fontColor: '#333',
                    fontSize: '14px'
                }
            });

            // Apply text rotation / prize image rotation to the preview canvas
            setTimeout(() => {
                const canvas = document.querySelector('#swp-admin-preview-canvas canvas');
                if (!canvas) {
                    return;
                }
                if (styles.prize_text_rotation !== 0 || styles.prize_text_offset_x !== 0 || styles.prize_text_offset_y !== 0) {
                    applyTextRotationToPreview(canvas, styles.prize_text_rotation, styles.prize_text_offset_x, styles.prize_text_offset_y);
                }
                if (styles.prize_image_rotation) {
                    applyPrizeImageDrawRotationToPreview(canvas, styles);
                }
            }, 100);
        }

        function applyTextRotationToPreview(canvas, rotation, offsetX, offsetY) {
            const ctx = canvas.getContext('2d');
            if (!ctx || ctx.__textRotationPatched) return;

            // Mark as patched to avoid duplicate patching
            ctx.__textRotationPatched = true;

            // Store original methods
            const originalFillText = ctx.fillText.bind(ctx);
            const originalStrokeText = ctx.strokeText.bind(ctx);

            // Get rotation in radians
            const rotationRad = (rotation * Math.PI) / 180;

            // Get button text to exclude it from rotation
            const buttonText = $('#swp_button_text').val() || 'SPIN';

            // Override fillText to apply rotation and offset with center origin (only for prize text)
            ctx.fillText = function (text, x, y, maxWidth) {
                // Skip rotation for button text
                if (text === buttonText || text === 'START' || y < 50) {
                    originalFillText(text, x, y, maxWidth);
                    return;
                }

                ctx.save();
                // Move to the text position with offset
                ctx.translate(x + offsetX, y + offsetY);
                // Rotate around the center point (transform-origin: center)
                ctx.rotate(rotationRad);
                // Measure text to center it properly
                const metrics = ctx.measureText(text);
                const textWidth = metrics.width;
                // Draw text centered on the rotation point
                originalFillText(text, -textWidth / 2, 0, maxWidth);
                ctx.restore();
            };

            // Override strokeText to apply rotation and offset with center origin (only for prize text)
            ctx.strokeText = function (text, x, y, maxWidth) {
                // Skip rotation for button text
                if (text === buttonText || text === 'START' || y < 50) {
                    originalStrokeText(text, x, y, maxWidth);
                    return;
                }

                ctx.save();
                // Move to the text position with offset
                ctx.translate(x + offsetX, y + offsetY);
                // Rotate around the center point (transform-origin: center)
                ctx.rotate(rotationRad);
                // Measure text to center it properly
                const metrics = ctx.measureText(text);
                const textWidth = metrics.width;
                // Draw text centered on the rotation point
                originalStrokeText(text, -textWidth / 2, 0, maxWidth);
                ctx.restore();
            };

            // Force redraw
            if (wheelPreviewInstance && wheelPreviewInstance.init) {
                wheelPreviewInstance.init();
            }
        }

        function swpAdminPrizeImageSrcAllowlist() {
            const allow = new Set();
            $('#swp-prizes-list .swp-image-url').each(function () {
                const u = ($(this).val() || '').trim();
                if (u) {
                    allow.add(u);
                }
            });
            return allow;
        }

        function swpAdminImgSrcMatchesAllowlist(imgEl, allow) {
            if (!imgEl || !imgEl.src || !allow || !allow.size) {
                return false;
            }
            const s = imgEl.src.split('?')[0];
            let hit = false;
            allow.forEach(function (u) {
                if (!u || hit) {
                    return;
                }
                const uu = u.split('?')[0];
                if (imgEl.src === u || s === uu || s.indexOf(uu) !== -1 || uu.indexOf(s.split('/').pop()) !== -1) {
                    hit = true;
                }
            });
            return hit;
        }

        function applyPrizeImageDrawRotationToPreview(canvas, styles) {
            const rot = parseInt(styles.prize_image_rotation, 10) || 0;
            if (!rot) {
                return;
            }
            const ctx = canvas.getContext('2d');
            if (!ctx || ctx.__swpPrizeImgDrawPatched) {
                return;
            }
            ctx.__swpPrizeImgDrawPatched = true;
            const allow = swpAdminPrizeImageSrcAllowlist();
            const originalDrawImage = ctx.drawImage.bind(ctx);
            ctx.drawImage = function () {
                const rotNow = parseInt($('#swp_prize_image_rotation').val(), 10) || 0;
                const args = arguments;
                const img = args[0];
                if (!rotNow || !swpAdminImgSrcMatchesAllowlist(img, allow)) {
                    return originalDrawImage.apply(ctx, args);
                }
                const rotRad = (rotNow * Math.PI) / 180;
                if (args.length === 5) {
                    const dx = args[1];
                    const dy = args[2];
                    const dw = args[3];
                    const dh = args[4];
                    ctx.save();
                    ctx.translate(dx + dw / 2, dy + dh / 2);
                    ctx.rotate(rotRad);
                    originalDrawImage(img, -dw / 2, -dh / 2, dw, dh);
                    ctx.restore();
                    return;
                }
                if (args.length === 9) {
                    const sx = args[1];
                    const sy = args[2];
                    const sw = args[3];
                    const sh = args[4];
                    const dx = args[5];
                    const dy = args[6];
                    const dw = args[7];
                    const dh = args[8];
                    ctx.save();
                    ctx.translate(dx + dw / 2, dy + dh / 2);
                    ctx.rotate(rotRad);
                    originalDrawImage(img, sx, sy, sw, sh, -dw / 2, -dh / 2, dw, dh);
                    ctx.restore();
                    return;
                }
                return originalDrawImage.apply(ctx, args);
            };
            if (wheelPreviewInstance && wheelPreviewInstance.init) {
                wheelPreviewInstance.init();
            }
        }

        function luckyGridFirstLineTopPxAdmin(cellH, fontSizePx, lineHeightPx) {
            const h = Math.max(1, cellH);
            const fs = Math.max(1, fontSizePx);
            const lh = Math.max(1, lineHeightPx);
            let topPx = (h / 2) + 0.35 * fs - lh;
            topPx = Math.max(0, Math.min(topPx, h - lh - 1));
            return Math.round(topPx);
        }

        function luckyGridCenterButtonTopPxAdmin(cellH, fontSizePx, lineHeightPx) {
            const h = Math.max(1, cellH);
            const fs = Math.max(1, fontSizePx);
            const lh = Math.max(1, lineHeightPx);
            let topPx = luckyGridFirstLineTopPxAdmin(h, fs, lh) + Math.round(Math.min(fs * 0.2, h * 0.06));
            topPx = Math.max(0, Math.min(topPx, h - lh - 1));
            return topPx;
        }

        function normalizePrizeLayoutForGridPreview(prize, defaults, cellH) {
            const defaultFs = defaults.fontSize;
            const defaultLh = defaults.lineHeight;
            const h = Math.max(1, parseInt(cellH, 10) || 0);
            const imgOffX = parseInt($('#swp_prize_image_left').val(), 10) || 0;
            const imgOffY = parseInt($('#swp_prize_image_top').val(), 10) || 0;
            const px = function (val, fb) {
                if (val === undefined || val === null) {
                    return fb;
                }
                const n = parseInt(String(val).replace(/px/g, '').trim(), 10);
                return Number.isFinite(n) ? n : fb;
            };
            const out = Object.assign({}, prize);
            const hasFonts = out.fonts && out.fonts.length;
            const hasImgs = out.imgs && out.imgs.length;
            if (hasFonts && hasImgs) {
                out.imgs = out.imgs.map(function (img) {
                    const baseTop = h > 1 ? Math.round(h * 0.14) : 15;
                    return Object.assign({}, img, {
                        top: (baseTop + imgOffY) + 'px',
                        left: imgOffX + 'px'
                    });
                });
                out.fonts = out.fonts.map(function (f) {
                    const fs = px(f.fontSize, defaultFs);
                    const lhRaw = px(f.lineHeight, defaultLh);
                    const lhUse = Math.max(lhRaw || 0, fs);
                    let textTopPx = h > 1 ? Math.round(h * 0.56 + 0.35 * fs - lhUse) : NaN;
                    if (Number.isFinite(textTopPx)) {
                        textTopPx = Math.max(0, Math.min(textTopPx, h - lhUse - 1));
                    }
                    return Object.assign({}, f, {
                        top: Number.isFinite(textTopPx) ? (textTopPx + 'px') : '58%',
                        lineHeight: lhUse + 'px',
                        fontSize: f.fontSize || (fs + 'px'),
                        wordWrap: f.wordWrap !== undefined ? f.wordWrap : false
                    });
                });
            } else if (hasFonts && !hasImgs) {
                out.fonts = out.fonts.map(function (f) {
                    const fs = px(f.fontSize, defaultFs);
                    const lhRaw = px(f.lineHeight, defaultLh);
                    const lhUse = Math.max(lhRaw || 0, fs);
                    const topPx = h > 1 ? luckyGridFirstLineTopPxAdmin(h, fs, lhUse) : NaN;
                    return Object.assign({}, f, {
                        top: Number.isFinite(topPx) ? (topPx + 'px') : '42%',
                        lineHeight: lhUse + 'px',
                        fontSize: f.fontSize || (fs + 'px'),
                        wordWrap: f.wordWrap !== undefined ? f.wordWrap : false
                    });
                });
            } else if (hasImgs && !hasFonts) {
                out.imgs = out.imgs.map(function (img) {
                    const iw2 = px(img.width, 48);
                    const cy = h > 1 ? Math.max(0, Math.round(h / 2 - iw2 / 2) + imgOffY) : 0;
                    const cx = h > 1 ? Math.max(0, Math.round(h / 2 - iw2 / 2) + imgOffX) : 0;
                    return Object.assign({}, img, { top: cy + 'px', left: cx + 'px' });
                });
            }
            return out;
        }

        function getLuckyGridRadialRingLayoutsAdmin(z, s, count) {
            const n = Math.max(0, parseInt(count, 10) || 0);
            if (n < 1) {
                return [];
            }
            const hz = z / 2;
            const hs = s / 2;
            const R = hz - hs;
            const maxCoord = z - s;
            const layouts = [];
            for (let i = 0; i < n; i++) {
                const angle = -Math.PI / 2 + (2 * Math.PI * i) / n;
                const cx = hz + R * Math.cos(angle);
                const cy = hz + R * Math.sin(angle);
                let x = Math.round(cx - hs);
                let y = Math.round(cy - hs);
                x = Math.max(0, Math.min(maxCoord, x));
                y = Math.max(0, Math.min(maxCoord, y));
                layouts.push({ x, y, col: s, row: s });
            }
            return layouts;
        }

        function getRingGridPerimeterCoordsForBoundsAdmin(lo, hi) {
            const coords = [];
            const size = hi - lo + 1;
            if (size < 2) {
                return coords;
            }
            let x;
            let y;
            for (x = lo; x <= hi; x++) {
                coords.push([x, lo]);
            }
            for (y = lo + 1; y <= hi; y++) {
                coords.push([hi, y]);
            }
            for (x = hi - 1; x >= lo; x--) {
                coords.push([x, hi]);
            }
            for (y = hi - 1; y > lo; y--) {
                coords.push([lo, y]);
            }
            return coords;
        }

        function getRingGridAllPrizeCoordsAdmin(n) {
            n = Math.floor(Number(n));
            if (!Number.isFinite(n) || n < 3) {
                n = 3;
            }
            if (n === 3) {
                return getRingGridPerimeterCoordsForBoundsAdmin(0, n - 1);
            }
            const c = Math.floor(n / 2);
            const coords = [];
            let y;
            let x;
            for (y = 0; y < n; y++) {
                for (x = 0; x < n; x++) {
                    if (x === c && y === c) {
                        continue;
                    }
                    coords.push([x, y]);
                }
            }
            return coords;
        }

        function normalizeRingGridSizeAdmin(rows, cols) {
            const allowed = [3, 5, 7];
            const r = parseInt(rows, 10);
            const c = parseInt(cols, 10);
            let n = Math.max(
                Number.isFinite(r) ? r : 3,
                Number.isFinite(c) ? c : 3
            );
            n = Math.min(7, Math.max(3, n));
            return allowed.reduce(function (best, a) {
                return Math.abs(a - n) < Math.abs(best - n) ? a : best;
            }, 3);
        }

        function swpAdminSumBlocksPadding() {
            const raw = $('#swp_blocks_config').val();
            if (!raw) {
                return 0;
            }
            try {
                const arr = JSON.parse(raw);
                if (!Array.isArray(arr)) {
                    return 0;
                }
                return arr.reduce(function (sum, b) {
                    const p = b && b.padding != null
                        ? parseInt(String(b.padding).replace(/px/g, '').trim(), 10)
                        : 0;
                    return sum + (Number.isFinite(p) ? p : 0);
                }, 0);
            } catch (e) {
                return 0;
            }
        }

        function swpAdminBlocksFromConfig(styles, fallbackBorderRadius) {
            const raw = $('#swp_blocks_config').val() || styles.blocks_config || '';
            if (raw) {
                try {
                    const arr = JSON.parse(raw);
                    if (Array.isArray(arr) && arr.length > 0) {
                        return arr.map(function (b) {
                            return {
                                padding: b.padding != null ? b.padding : '10px',
                                background: b.background || styles.background_color || '#ffffff',
                                borderRadius: b.borderRadius !== undefined && b.borderRadius !== null
                                    ? b.borderRadius
                                    : fallbackBorderRadius
                            };
                        });
                    }
                } catch (e) {
                    /* use fallback */
                }
            }
            return [{
                padding: (parseInt(styles.padding, 10) || 0) + 'px',
                background: styles.background_color || '#ffffff',
                borderRadius: fallbackBorderRadius
            }];
        }

        function renderNineSquaresPreview(prizes, styles) {
            const presetVal = ($('#swp_active_preset').val() || '').toString();
            const previewRingGrid = presetVal === 'ringGrid';
            const previewGrid2x3 = presetVal === 'grid2x3';
            const previewDocBlocksGrid = previewRingGrid || previewGrid2x3;
            const brField = parseInt($('#swp_grid_border_radius').val(), 10);
            const brSaved = parseInt(styles.grid_border_radius, 10);
            const brEff = Number.isFinite(brField) ? brField : (Number.isFinite(brSaved) ? brSaved : 0);
            const previewRadial = (presetVal === 'circleStyle' || brEff >= 48) && !previewDocBlocksGrid;
            const DOC_Z = 60;
            const DOC_S = 12;
            const DOC_K = 2.8;
            const DOC_PAD_OUT = 10;
            const DOC_PAD_IN = 10;
            let gridRows = previewRadial ? DOC_Z : (parseInt($('#swp_grid_rows').val(), 10) || 3);
            let gridCols = previewRadial ? DOC_Z : (parseInt($('#swp_grid_cols').val(), 10) || 3);
            if (!previewRadial && previewRingGrid) {
                const rn = normalizeRingGridSizeAdmin(gridRows, gridCols);
                gridRows = rn;
                gridCols = rn;
            }
            if (!previewRadial && !previewRingGrid && !previewGrid2x3) {
                const rn = normalizeRingGridSizeAdmin(gridRows, gridCols);
                gridRows = rn;
                gridCols = rn;
            }
            if (!previewRadial && previewGrid2x3) {
                let gr = gridRows;
                let gc = gridCols;
                const n = prizes.length;
                while (gr * gc < n) {
                    if (gc <= gr) {
                        gc++;
                    } else {
                        gr++;
                    }
                }
                gridRows = gr;
                gridCols = gc;
            }
            const gridGutterRaw = parseInt($('#swp_grid_gutter').val(), 10) || 5;
            const gridGutter = previewRadial ? 0 : gridGutterRaw;
            const gridPad = previewRadial
                ? (DOC_PAD_OUT + DOC_PAD_IN)
                : (previewDocBlocksGrid ? (swpAdminSumBlocksPadding() || 20) : (parseInt(styles.padding, 10) || 0));
            const gridCanvasH = parseInt(styles.height, 10) || 460;
            const gridCanvasW = parseInt(styles.width, 10) || 460;
            const innerH = Math.max(1, gridCanvasH - 2 * gridPad);
            const innerW = Math.max(1, gridCanvasW - 2 * gridPad);
            const previewCellH = Math.max(1, (innerH - gridGutter * (gridRows - 1)) / gridRows);
            const previewCellW = Math.max(1, (innerW - gridGutter * (gridCols - 1)) / gridCols);

            const gridFontSize = parseInt($('#swp_prize_font_size').val(), 10) || 16;
            const gridLineHeight = parseInt($('#swp_prize_line_height').val(), 10) || gridFontSize;

            const cellBrNum = previewRadial ? 0 : (Number.isFinite(brEff) ? brEff : 0);
            const gridCellBorderRadius = previewRadial
                ? Infinity
                : (Number.isFinite(brEff) ? brEff : 0);
            const blockBorderRadiusPx = previewRadial
                ? Infinity
                : (cellBrNum + 'px');
            const prizeSpanPreview = previewRadial ? (previewCellH * DOC_S) : previewCellH;

            let gridPrizeList;
            if (previewRadial) {
                const visibleRadial = prizes
                    .map(function (p, idx) {
                        return { p: p, idx: idx };
                    })
                    .filter(function (entry) {
                        return swpAdminNineSquaresPrizeIsRenderable(entry.p);
                    });
                const nVisible = visibleRadial.length;
                const ringLayouts = getLuckyGridRadialRingLayoutsAdmin(DOC_Z, DOC_S, nVisible);
                const ringShadow = styles.grid_shadow || '';
                gridPrizeList = [];
                for (let i = 0; i < nVisible; i++) {
                    const layout = ringLayouts[i];
                    const src = visibleRadial[i].p;
                    const normalized = normalizePrizeLayoutForGridPreview(src, {
                        fontSize: gridFontSize,
                        lineHeight: gridLineHeight
                    }, prizeSpanPreview);
                    gridPrizeList.push(Object.assign({}, normalized, layout, {
                        borderRadius: Infinity,
                        background: normalized.background,
                        shadow: ringShadow
                    }));
                }
            } else {
                const padded = prizes.slice();
                if (previewGrid2x3) {
                    const cellCount = Math.max(1, gridRows * gridCols);
                    while (padded.length < cellCount) {
                        padded.push({
                            background: '#f0f0f0',
                            fonts: [{ text: '?', top: '25%' }]
                        });
                    }
                    gridPrizeList = [];
                    let gi = 0;
                    for (let y = 0; y < gridRows; y++) {
                        for (let x = 0; x < gridCols; x++) {
                            const p = padded[gi];
                            const normalized = normalizePrizeLayoutForGridPreview(p, {
                                fontSize: gridFontSize,
                                lineHeight: gridLineHeight
                            }, previewCellH);
                            gridPrizeList.push(Object.assign({}, normalized, {
                                x: x,
                                y: y,
                                borderRadius: gridCellBorderRadius
                            }));
                            gi++;
                        }
                    }
                } else {
                const ringCoordsCount = previewRingGrid
                    ? getRingGridAllPrizeCoordsAdmin(normalizeRingGridSizeAdmin(
                        parseInt($('#swp_grid_rows').val(), 10) || 3,
                        parseInt($('#swp_grid_cols').val(), 10) || 3
                    )).length
                    : 8;
                while (padded.length < ringCoordsCount) {
                    padded.push({
                        background: '#f0f0f0',
                        fonts: [{ text: '?', top: '25%' }]
                    });
                }
                if (previewRingGrid) {
                    const ringN = normalizeRingGridSizeAdmin(
                        parseInt($('#swp_grid_rows').val(), 10) || 3,
                        parseInt($('#swp_grid_cols').val(), 10) || 3
                    );
                    const ringCoords = getRingGridAllPrizeCoordsAdmin(ringN);
                    const ringShadow = styles.grid_shadow || '';
                    gridPrizeList = ringCoords.map(function (coord, i) {
                        const p = padded[i];
                        const normalized = normalizePrizeLayoutForGridPreview(p, {
                            fontSize: gridFontSize,
                            lineHeight: gridLineHeight
                        }, previewCellH);
                        return Object.assign({}, normalized, {
                            x: coord[0],
                            y: coord[1],
                            borderRadius: gridCellBorderRadius,
                            shadow: ringShadow
                        });
                    });
                } else {
                    gridPrizeList = padded.map(function (p) {
                        return normalizePrizeLayoutForGridPreview(p, {
                            fontSize: gridFontSize,
                            lineHeight: gridLineHeight
                        }, previewCellH);
                    });
                    let idx = 0;
                    for (let y = 0; y < gridRows; y++) {
                        for (let x = 0; x < gridCols; x++) {
                            if (y * gridCols + x === Math.floor((gridRows * gridCols) / 2)) {
                                continue;
                            }
                            if (idx < gridPrizeList.length) {
                                gridPrizeList[idx] = Object.assign({}, gridPrizeList[idx], {
                                    x: x,
                                    y: y,
                                borderRadius: gridCellBorderRadius
                            });
                            idx++;
                            }
                        }
                    }
                }
                }
            }

            var adminLcGrid = Math.max(1, parseInt(styles.line_clamp, 10) || 3);
            var adminGridStylesFin = Object.assign({}, styles, {
                line_clamp: adminLcGrid,
                length_limit: parseInt(styles.length_limit, 10) || 90,
                prize_font_size: gridFontSize,
                prize_line_height: gridLineHeight,
                swp_preview_radial: previewRadial
            });
            var finW = previewRadial ? previewCellW * DOC_S : previewCellW;
            var finH = previewRadial ? previewCellH * DOC_S : previewCellH;
            gridPrizeList.forEach(function (p) {
                swpAdminFinalizeNineSquaresPrizeFontLayout(p, finW, finH, adminGridStylesFin);
            });

            // Destroy previous instance
            if (wheelPreviewInstance && wheelPreviewInstance.destroy) {
                wheelPreviewInstance.destroy();
            }

            const previewBtnFs = styles.button_font_size || 16;
            const previewBtnFsNum = parseInt(previewBtnFs, 10) || 16;
            const previewBtnLhNum = Math.max(1, parseInt(styles.button_line_height, 10) || previewBtnFsNum);
            const previewBtnTopRaw = styles.button_text_top;
            const previewBtnTopParsed = typeof previewBtnTopRaw === 'number'
                ? previewBtnTopRaw
                : parseInt(previewBtnTopRaw, 10);
            const previewBtnCentered = !Number.isFinite(previewBtnTopParsed)
                || previewBtnTopParsed === -10
                || previewBtnTopParsed === 0;
            let previewBtnTop;
            if (previewRadial) {
                previewBtnTop = previewBtnCentered ? '43%' : (previewBtnTopParsed + 'px');
            } else if (previewBtnCentered) {
                previewBtnTop = luckyGridCenterButtonTopPxAdmin(previewCellH, previewBtnFsNum, previewBtnLhNum) + 'px';
            } else {
                previewBtnTop = previewBtnTopParsed + 'px';
            }

            const btnX = Math.floor(gridCols / 2);
            const btnY = Math.floor(gridRows / 2);

            const previewBlocks = previewRadial
                ? [
                    { padding: DOC_PAD_OUT + 'px', background: styles.button_color || '#869cfa', borderRadius: Infinity },
                    { padding: DOC_PAD_IN + 'px', background: styles.background_color || '#e9e8fe', borderRadius: Infinity }
                ]
                : (previewDocBlocksGrid
                    ? (function () {
                        const panelBrField = parseInt($('#swp_grid_panel_border_radius').val(), 10);
                        const panelBrSaved = parseInt(styles.grid_panel_border_radius, 10);
                        const panelBrPx = Number.isFinite(panelBrField)
                            ? panelBrField
                            : (Number.isFinite(panelBrSaved) ? panelBrSaved : 0);
                        const panelFallback = panelBrPx >= 0 ? (panelBrPx + 'px') : '0';
                        return swpAdminBlocksFromConfig(styles, panelFallback);
                    }())
                    : [
                        { padding: gridPad + 'px', background: styles.background_color, borderRadius: blockBorderRadiusPx }
                    ]);

            const previewRadialButtonDiameterPx = Math.max(0, (parseInt(styles.button_radius, 10) || 0) * 2);
            const previewRadialBaseCanvasPx = Math.max(1, Math.min(
                parseInt(styles.width, 10) || 0,
                parseInt(styles.height, 10) || 0
            ));
            const previewRadialButtonSpan = previewRadialButtonDiameterPx > 0
                ? Math.max(DOC_S * 1.2, Math.min(DOC_Z * 0.9, (previewRadialButtonDiameterPx / previewRadialBaseCanvasPx) * DOC_Z))
                : (DOC_S * DOC_K);
            const previewButtons = previewRadial
                ? [
                    {
                        x: DOC_Z / 2 - previewRadialButtonSpan / 2,
                        y: DOC_Z / 2 - previewRadialButtonSpan / 2,
                        col: previewRadialButtonSpan,
                        row: previewRadialButtonSpan,
                        background: styles.button_color,
                        borderRadius: Infinity,
                        fonts: [
                            {
                                text: styles.button_text,
                                top: previewBtnTop,
                                fontSize: previewBtnFsNum + 'px',
                                lineHeight: previewBtnLhNum + 'px',
                                fontWeight: 'bold',
                                fontColor: styles.button_text_color,
                                wordWrap: false
                            }
                        ]
                    }
                ]
                : (previewGrid2x3
                    ? []
                    : [
                        {
                            x: btnX,
                            y: btnY,
                            background: styles.button_color,
                            borderRadius: gridCellBorderRadius,
                            fonts: [
                                {
                                    text: styles.button_text,
                                    top: previewBtnTop,
                                    fontSize: previewBtnFsNum + 'px',
                                    lineHeight: previewBtnLhNum + 'px',
                                    fontWeight: 'bold',
                                    fontColor: styles.button_text_color,
                                    wordWrap: false
                                }
                            ]
                        }
                    ]);

            wheelPreviewInstance = new window.LuckyCanvas.LuckyGrid('#swp-admin-preview-canvas', {
                width: styles.width + 'px',
                height: styles.height + 'px',
                rows: gridRows,
                cols: gridCols,
                blocks: previewBlocks,
                prizes: gridPrizeList,
                defaultConfig: {
                    gutter: gridGutter
                },
                buttons: previewButtons,
                defaultStyle: Object.assign({
                    fontColor: '#333',
                    fontSize: '14px',
                    borderRadius: gridCellBorderRadius
                },
                previewRadial ? { background: '#bac5ee' } : {},
                previewDocBlocksGrid ? {
                    background: ($('#swp_grid_default_background').val() || styles.grid_default_background || '#b8c5f2')
                } : {},
                previewRadial ? { wordWrap: false, lengthLimit: '82%', lineClamp: 2 } : {
                    wordWrap: false,
                    lengthLimit: (parseInt(styles.length_limit, 10) || 90) + '%',
                    lineClamp: Math.max(1, parseInt(styles.line_clamp, 10) || 3)
                })
            });

            setTimeout(function () {
                const canvas = document.querySelector('#swp-admin-preview-canvas canvas');
                if (canvas && styles.prize_image_rotation) {
                    applyPrizeImageDrawRotationToPreview(canvas, styles);
                }
            }, 100);

            if (previewGrid2x3) {
                const $go = $('<button type="button" class="swp-admin-grid-external-spin"></button>');
                $go.text(styles.button_text || 'SPIN');
                const spinMid = styles.button_color || '#e45912';
                $go.css({
                    color: styles.button_text_color || '#ffffff',
                    '--swp-external-spin-mid': spinMid
                });
                $('#swp-live-preview').append($go);
            }
        }

        function renderSlotMachinePreview(prizes, styles) {
            // Destroy previous instance
            if (wheelPreviewInstance && wheelPreviewInstance.destroy) {
                wheelPreviewInstance.destroy();
            }

            wheelPreviewInstance = new window.LuckyCanvas.SlotMachine('#swp-admin-preview-canvas', {
                width: styles.width + 'px',
                height: styles.height + 'px',
                blocks: [
                    { padding: '10px', background: styles.background_color }
                ],
                slots: [
                    { speed: 10 },
                    { speed: 10 },
                    { speed: 10 }
                ],
                prizes: prizes,
                defaultStyle: {
                    fontColor: '#333',
                    fontSize: '12px'
                }
            });
        }

        // Initial preview load
        if ($('#swp-live-preview').length) {
            setTimeout(function () {
                refreshPreview();
            }, 500);
        }

        // ========================================================================
        // Shortcode metabox: Shortcode vs Auto Embed panels
        // ========================================================================
        (function () {
            const $mode = $('#swp_usage_mode');
            if (!$mode.length) {
                return;
            }
            const $short = $('#swp-usage-panel-shortcode');
            const $auto = $('#swp-usage-panel-auto');
            function syncPanels() {
                if ($mode.val() === 'auto_embed') {
                    $short.prop('hidden', true);
                    $auto.prop('hidden', false);
                } else {
                    $short.prop('hidden', false);
                    $auto.prop('hidden', true);
                }
            }
            $mode.on('change', syncPanels);
            syncPanels();
        })();

        // ========================================================================
        // Copy Shortcode
        // ========================================================================
        $('.swp-copy-shortcode').on('click', function () {
            const text = $(this).data('clipboard-text');

            // Create temporary textarea
            const $temp = $('<textarea>');
            $('body').append($temp);
            $temp.val(text).select();
            document.execCommand('copy');
            $temp.remove();

            // Show feedback
            const $btn = $(this);
            const originalText = $btn.text();
            $btn.text(swpAdminData.copied || 'Copied!');

            setTimeout(function () {
                $btn.text(originalText);
            }, 2000);
        });

        // ========================================================================
        // Form Validation on Submit
        // ========================================================================
        $(document).on('submit', '#post', function (e) {
            const $form = $(this);
            const $prizes = $form.find('.swp-prize-row');

            if ($prizes.length === 0) {
                return true;
            }

            let totalProbability = 0;
            $prizes.each(function () {
                const prob = parseFloat($(this).find('.swp-probability-input').val()) || 0;
                totalProbability += prob;
            });

            if (Math.abs(totalProbability - 100) > 0.1) {
                const confirmMsg = (swpAdminData.prizeProbabilityWarning || 'Warning: Prize probabilities should total 100%. Current total: %s%').replace(/%s/g, totalProbability.toFixed(1)) + '\n\n' + (swpAdminData.confirmContinueAnyway || 'Do you want to continue anyway?');
                if (!confirm(confirmMsg)) {
                    e.preventDefault();
                    // Switch to prizes tab
                    $('.swp-tab-btn[data-tab="prizes"]').click();
                    return false;
                }
            }
        });

        // ========================================================================
        // Select Winner (Entries Page)
        // ========================================================================
        $('.swp-select-winner').on('click', function () {
            const $btn = $(this);
            const entryId = $btn.data('entry-id');

            if (!confirm(swpAdminData.confirmWinner || 'Are you sure you want to select this entry as winner?')) {
                return;
            }

            $btn.prop('disabled', true).text(swpAdminData.processing || 'Processing...');

            $.ajax({
                url: swpAdminData.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'swp_select_winner',
                    nonce: swpAdminData.nonce,
                    entry_id: entryId
                },
                success: function (response) {
                    if (response.success) {
                        const $row = $btn.closest('tr');
                        $row.find('td:nth-last-child(2)').html(
                            '<span class="swp-badge swp-badge-success">' + (swpAdminData.winner || 'Winner') + '</span>'
                        );
                        $btn.replaceWith(
                            '<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>'
                        );

                        alert(swpAdminData.winnerSelectedNotified || 'Winner selected and notified successfully!');
                    } else {
                        alert(response.data.message || (swpAdminData.errorSelectingWinner || 'Error selecting winner'));
                        $btn.prop('disabled', false).text(swpAdminData.selectWinner);
                    }
                },
                error: function () {
                    alert(swpAdminData.errorOccurred || 'An error occurred');
                    $btn.prop('disabled', false).text(swpAdminData.selectWinner);
                }
            });
        });

        // Auto-submit filter form when wheel selected
        $('#swp-wheel-select').on('change', function () {
            $(this).closest('form').submit();
        });

        // ========================================================================
        // Advanced Conditions Repeater
        // ========================================================================
        let conditionIndex = $('#swp-conditions-list .swp-condition-row').length;

        // Add Condition
        $('#swp-add-condition').on('click', function () {
            const $row = $('<div class="swp-condition-row" data-index="' + conditionIndex + '"></div>');

            const html = `
                <div class="swp-condition-fields">
                    <select name="swp_settings[advanced_conditions][${conditionIndex}][type]" class="swp-select swp-condition-type">
                        <option value="">Select Type</option>
                        <option value="user_status">User Status</option>
                        <option value="user_role">User Role</option>
                        <option value="page">Page</option>
                    </select>
                    
                    <select name="swp_settings[advanced_conditions][${conditionIndex}][operator]" class="swp-select swp-condition-operator">
                        <option value="is">Is</option>
                        <option value="is_not">Is Not</option>
                    </select>
                    
                    <select name="swp_settings[advanced_conditions][${conditionIndex}][value]" class="swp-select swp-condition-value">
                        <option value="">Select value</option>
                    </select>
                </div>
                
                <button type="button" class="swp-remove-condition" title="Remove Condition">
                    <span class="dashicons dashicons-trash"></span>
                </button>
            `;

            $row.html(html);
            $('#swp-conditions-list').append($row);
            conditionIndex++;
        });

        // Remove Condition
        $(document).on('click', '.swp-remove-condition', function () {
            if (confirm('Are you sure you want to remove this condition?')) {
                $(this).closest('.swp-condition-row').remove();
                updateConditionIndices();
            }
        });

        // Update condition indices after removal
        function updateConditionIndices() {
            $('#swp-conditions-list .swp-condition-row').each(function (index) {
                $(this).attr('data-index', index);
                $(this).find('select').each(function () {
                    const name = $(this).attr('name');
                    if (name) {
                        const newName = name.replace(/\[\d+\]/, '[' + index + ']');
                        $(this).attr('name', newName);
                    }
                });
            });
        }

        // Update value options when type changes
        $(document).on('change', '.swp-condition-type', function () {
            const $row = $(this).closest('.swp-condition-row');
            const $valueSelect = $row.find('.swp-condition-value');
            const type = $(this).val();

            $valueSelect.empty();

            if (type === 'user_status') {
                $valueSelect.append('<option value="logged_in">Logged In</option>');
                $valueSelect.append('<option value="logged_out">Logged Out</option>');
            } else if (type === 'user_role') {
                // Add user roles (would be better to fetch via AJAX, but using static for now)
                $valueSelect.append('<option value="administrator">Administrator</option>');
                $valueSelect.append('<option value="editor">Editor</option>');
                $valueSelect.append('<option value="author">Author</option>');
                $valueSelect.append('<option value="contributor">Contributor</option>');
                $valueSelect.append('<option value="subscriber">Subscriber</option>');
            } else if (type === 'page') {
                // Fetch pages via AJAX
                $valueSelect.append('<option value="">Loading...</option>');

                $.ajax({
                    url: swpAdminData.ajaxUrl,
                    type: 'POST',
                    data: {
                        action: 'swp_get_pages',
                        nonce: swpAdminData.nonce
                    },
                    success: function (response) {
                        if (response.success && response.data.pages) {
                            $valueSelect.empty();
                            $valueSelect.append('<option value="">Select page</option>');
                            response.data.pages.forEach(function (page) {
                                $valueSelect.append('<option value="' + page.id + '">' + page.title + '</option>');
                            });
                        } else {
                            $valueSelect.empty();
                            $valueSelect.append('<option value="">Error loading pages</option>');
                        }
                    },
                    error: function (xhr, status, error) {
                        console.error('Error loading pages:', error);
                        $valueSelect.empty();
                        $valueSelect.append('<option value="">Error loading pages</option>');
                        // Optionally show an alert
                        // alert('Failed to load pages. Please refresh the page and try again.');
                    }
                });
            } else {
                $valueSelect.append('<option value="">Select value</option>');
            }
        });

        // ========================================================================
        // Popup Settings Preview
        // ========================================================================
        function updatePopupPreview() {
            const maxWidth = $('#swp_popup_max_width').val() || 980;
            const widthPercent = $('#swp_popup_width_percent').val() || 90;
            const backgroundColor = $('#swp_popup_background_color').val() || '#ffffff';
            const backgroundImage = $('#swp_popup_background_image').val() || '';
            const borderRadius = $('#swp_popup_border_radius').val() || 20;
            const padding = $('#swp_popup_padding').val() || 50;
            const mobilePadding = Math.round(padding * 0.5); // 50% of desktop padding

            // Build background CSS
            let backgroundCSS = `background-color: ${backgroundColor};`;
            if (backgroundImage && backgroundImage.trim()) {
                backgroundCSS += ` background-image: url('${backgroundImage}'); background-size: cover; background-position: center; background-repeat: no-repeat;`;
            }

            // Update CSS custom properties for popup
            // Remove old style if exists
            $('#swp-popup-preview').remove();

            $('<style id="swp-popup-preview">')
                .text(`
                    .swp-modal-content {
                        max-width: ${maxWidth}px !important;
                        width: ${widthPercent}% !important;
                    }
                    
                    .swp-wheel-wrapper-popup {
                        ${backgroundCSS}
                        border-radius: ${borderRadius}px !important;
                        padding: ${padding}px !important;
                    }
                    
                    @media screen and (max-width: 768px) {
                        .swp-wheel-wrapper-popup {
                            padding: ${mobilePadding}px !important;
                        }
                    }
                `)
                .appendTo('head');
        }

        // Update popup preview when values change
        $('#swp_popup_max_width, #swp_popup_width_percent, #swp_popup_background_color, #swp_popup_background_image, #swp_popup_border_radius, #swp_popup_padding').on('input change', function () {
            updatePopupPreview();
        });

        // Initial popup preview
        updatePopupPreview();

        // Update blocks config when wheel border padding changes
        $('#swp_wheel_border_padding').on('input change', function () {
            const padding = $(this).val();
            const $blocksField = $('#swp_blocks_config');

            if ($blocksField.length && $blocksField.val()) {
                try {
                    const blocks = JSON.parse($blocksField.val());
                    if (Array.isArray(blocks) && blocks.length > 0) {
                        blocks[0].padding = padding + 'px';
                        $blocksField.val(JSON.stringify(blocks));

                        // Also update the in-memory preset object so it persists if we switch back
                        const activePreset = $('#swp_active_preset').val();
                        if (activePreset && presetStyles[activePreset] && presetStyles[activePreset].blocks) {
                            presetStyles[activePreset].blocks[0].padding = padding + 'px';
                        }

                        // Trigger preview update
                        refreshPreview();
                    }
                } catch (e) {
                    console.warn('Failed to update blocks padding:', e);
                }
            }
        });

        // ========================================================================
        // Show/hide wheel-specific design sections based on wheel type
        // ========================================================================
        function presetAllowsElement($el, presetName) {
            const name = (presetName || 'default').toString().trim();
            if ($el.is('[data-visible-off]')) {
                const raw = $el.attr('data-visible-off') || '';
                const excludedPresets = raw.split(',').map((p) => p.trim()).filter(Boolean);
                return !excludedPresets.includes(name);
            }
            if ($el.is('[data-visible-on]')) {
                const raw = $el.attr('data-visible-on') || '';
                const allowedPresets = raw.split(',').map((p) => p.trim()).filter(Boolean);
                return allowedPresets.includes(name);
            }
            return true;
        }

        function swpAdminNineSquaresEffectiveRadial(presetName) {
            const name = (presetName || 'default').toString().trim();
            if (name === 'ringGrid' || name === 'grid2x3') {
                return false;
            }
            if (name === 'circleStyle') {
                return true;
            }
            const br = parseInt($('#swp_grid_border_radius').val(), 10);
            return Number.isFinite(br) && br >= 48;
        }

        function syncGridDimensionAttrs() {
            const preset = ($('#swp_active_preset').val() || '').toString().trim();
            const $r = $('#swp_grid_rows');
            const $c = $('#swp_grid_cols');
            if (!$r.length || !$c.length) {
                return;
            }
            if (preset === 'ringGrid') {
                $r.attr({ min: 3, max: 7, step: 2 });
                $c.attr({ min: 3, max: 7, step: 2 });
            } else if (preset === 'grid2x3') {
                $r.attr({ min: 2, max: 5, step: 1 });
                $c.attr({ min: 2, max: 5, step: 1 });
            } else if (swpAdminNineSquaresEffectiveRadial(preset)) {
                return;
            } else {
                $r.attr({ min: 3, max: 7, step: 2 });
                $c.attr({ min: 3, max: 7, step: 2 });
            }
        }

        function updateDesignSections() {
            const wheelType = $('#swp_wheel_type').val() || 'big_wheel';
            const presetName = ($('#swp_active_preset').val() || 'default').toString().trim();

            $('.swp-design-field-big-wheel').each(function () {
                const $el = $(this);
                const show = wheelType === 'big_wheel' && presetAllowsElement($el, presetName);
                $el.toggle(show);
            });

            $('.swp-design-field-nine-squares').each(function () {
                const $el = $(this);
                let show = wheelType === 'nine_squares' && presetAllowsElement($el, presetName);
                if (show && $el.hasClass('swp-grid-layout-dimensions') && swpAdminNineSquaresEffectiveRadial(presetName)) {
                    show = false;
                }
                $el.toggle(show);
            });

            const radialNine = wheelType === 'nine_squares' && swpAdminNineSquaresEffectiveRadial(presetName);
            $('.swp-circle-radial-grid-hint').toggle(radialNine);

            $('.swp-accordion-item.swp-wheel-specific').not('.swp-design-spin-controls').each(function () {
                const $el = $(this);
                let show = false;
                if ($el.hasClass('swp-design-big-wheel')) {
                    show = wheelType === 'big_wheel' && presetAllowsElement($el, presetName);
                } else if ($el.hasClass('swp-design-nine-squares')) {
                    show = wheelType === 'nine_squares';
                } else if ($el.hasClass('swp-design-slot-machine')) {
                    show = wheelType === 'slot_machine';
                }
                $el.toggle(show);
                if (!show) {
                    $el.removeClass('active');
                }
            });

            $('.swp-accordion-item.swp-design-spin-controls').each(function () {
                const $el = $(this);
                const show = wheelType === 'big_wheel' || wheelType === 'nine_squares';
                $el.toggle(show);
                if (!show) {
                    $el.removeClass('active');
                }
            });

            $('.swp-spin-sub-big-wheel').toggle(wheelType === 'big_wheel');
            $('.swp-button-text-top-hint-big').toggle(wheelType === 'big_wheel');
            $('.swp-button-text-top-hint-grid').toggle(wheelType === 'nine_squares');

            if (wheelType === 'big_wheel') {
                $('.swp-size-big-wheel').show();
                $('.swp-size-other-wheels').hide();
                $('#swp_width, #swp_height').prop('disabled', true);
                /* Hidden fields carry width/height for big wheel (visible inputs are disabled and not posted). */
                $('#swp_hidden_width, #swp_hidden_height').prop('disabled', false);
            } else {
                $('.swp-size-big-wheel').hide();
                $('.swp-size-other-wheels').show();
                $('#swp_width, #swp_height').prop('disabled', false);
                /*
                 * Exclude hidden width/height from POST — they duplicate the visible inputs' names and
                 * would overwrite user edits with stale values (PHP keeps the last field in the form).
                 */
                $('#swp_hidden_width, #swp_hidden_height').prop('disabled', true);
            }
            syncGridDimensionAttrs();
        }

        // Sync Size field to Width/Height for Big Wheel
        $('#swp_size').on('input change', function () {
            const size = $(this).val();
            $('#swp_hidden_width').val(size);
            $('#swp_hidden_height').val(size);
            $('.swp-size-big-wheel .swp-slider-value').text(size + 'px');

            // Trigger preview update
            refreshPreview();
        });

        // Sync Prize Image Size to Width/Height hidden fields
        $('#swp_prize_image_size').on('input change', function () {
            const size = $(this).val();
            $('#swp_prize_image_width_hidden').val(size);
            $('#swp_prize_image_height_hidden').val(size);
            $('#swp_prize_image_size_value').val(size);
        });

        // Initial update
        updateDesignSections();

        // Wheel type + preset grid are synced after presetStyles loads (see preset section).

        // ========================================================================
        // Show/hide popup settings based on display mode
        // ========================================================================
        function updatePopupSettingsVisibility() {
            const displayMode = $('#swp_display_mode').val();

            // Find popup settings accordion
            const $popupSettingsAccordion = $('.swp-accordion-item').filter(function () {
                return $(this).find('.swp-accordion-header[data-target="popup-settings"]').length > 0;
            });

            if (displayMode === 'popup') {
                // Show popup settings if popup mode
                $popupSettingsAccordion.show();
            } else {
                // Hide popup settings if inline mode
                $popupSettingsAccordion.hide().removeClass('active');
            }
        }

        // Initial call to set correct visibility
        updatePopupSettingsVisibility();

        // Update when display mode changes (listen on General tab)
        $(document).on('change', '#swp_display_mode', function () {
            updatePopupSettingsVisibility();
        });

        // ========================================================================
        // Show/hide trigger-specific fields based on display trigger
        // ========================================================================
        function updateTriggerFieldsVisibility() {
            const trigger = $('#swp_display_trigger').val();

            // Hide all trigger fields and disable their inputs
            $('.swp-trigger-field').hide().find('input').prop('disabled', true);

            // Show relevant field based on trigger and enable its input
            if (trigger === 'after_time') {
                $('.swp-trigger-after-time').show().find('input').prop('disabled', false);
            } else if (trigger === 'scroll') {
                $('.swp-trigger-scroll').show().find('input').prop('disabled', false);
            }
            // page_load and exit_intent have no additional fields
        }

        // Initial call to set correct visibility
        updateTriggerFieldsVisibility();

        // Update when display trigger changes
        $(document).on('change', '#swp_display_trigger', function () {
            updateTriggerFieldsVisibility();
        });

        // ========================================================================
        // Show/hide Prize Image Settings based on prize representation
        // ========================================================================
        function updatePrizeImageSettingsVisibility() {
            const prizeRepresentation = $('#swp_prize_representation').val();

            // Find Prize Image Settings accordion
            const $prizeImageAccordion = $('.swp-accordion-item').filter(function () {
                return $(this).find('.swp-accordion-header[data-target="prize-image-settings"]').length > 0;
            });

            // Show only if prize representation is 'image' or 'both'
            if (prizeRepresentation === 'image' || prizeRepresentation === 'both') {
                $prizeImageAccordion.show();
            } else {
                // Hide if prize representation is 'label' (label only)
                $prizeImageAccordion.hide().removeClass('active');
            }
        }

        // Initial call to set correct visibility
        updatePrizeImageSettingsVisibility();

        // Update when prize representation changes
        $(document).on('change', '#swp_prize_representation', function () {
            updatePrizeImageSettingsVisibility();
        });

        // ========================================================================
        // Button Position Controls for Presets
        // ========================================================================
        function updateButtonPositions() {
            const $buttonsField = $('#swp_buttons_config');
            if ($buttonsField.length && $buttonsField.val()) {
                try {
                    const buttons = JSON.parse($buttonsField.val());
                    const arrowTop = $('#swp_button_arrow_top').val();
                    const centerTop = $('#swp_button_center_top').val();

                    // Update button positions in the configuration
                    if (Array.isArray(buttons)) {
                        // Arrow button (usually first)
                        if (buttons[0] && buttons[0].imgs && buttons[0].imgs[0] && arrowTop !== '') {
                            buttons[0].imgs[0].top = arrowTop + '%';
                        }
                        // Center button (usually second)
                        if (buttons[1] && buttons[1].imgs && buttons[1].imgs[0] && centerTop !== '') {
                            buttons[1].imgs[0].top = centerTop + '%';
                        }

                        // Save back to field
                        $buttonsField.val(JSON.stringify(buttons));

                        // Update the in-memory preset object
                        const activePreset = $('#swp_active_preset').val();
                        if (activePreset && presetStyles[activePreset] && presetStyles[activePreset].buttons) {
                            presetStyles[activePreset].buttons = buttons;
                            if (arrowTop !== '') {
                                presetStyles[activePreset].button_arrow_top = parseInt(arrowTop);
                            }
                            if (centerTop !== '') {
                                presetStyles[activePreset].button_center_top = parseInt(centerTop);
                            }
                        }

                        // Trigger preview update
                        refreshPreview();
                    }
                } catch (e) {
                    console.warn('Failed to update button positions:', e);
                }
            }
        }

        // Update button positions when controls change
        $(document).on('input change', '#swp_button_arrow_top, #swp_button_center_top', function () {
            updateButtonPositions();
        });

        // ========================================================================
        // Update Button Text and Styling Dynamically
        // ========================================================================
        function updateButtonTextAndStyle() {
            const $buttonsField = $('#swp_buttons_config');
            if (!$buttonsField.length || !$buttonsField.val()) {
                return;
            }

            try {
                const buttons = JSON.parse($buttonsField.val());
                if (!Array.isArray(buttons) || buttons.length === 0) {
                    return;
                }

                // Get current button settings from form
                const buttonText = $('#swp_button_text').val() || 'SPIN';
                const buttonTextTop = $('#swp_button_text_top').val() !== '' ? $('#swp_button_text_top').val() : '-10';
                const buttonFontSize = $('#swp_button_font_size').val() || '18';
                const buttonTextColor = $('#swp_button_text_color').val() || '#ffffff';
                const buttonColor = $('#swp_button_color').val() || '#f24a09';
                const fontWeight = $('#swp_font_weight').val() || '700';

                // Find the button with fonts (the spin button)
                for (let i = 0; i < buttons.length; i++) {
                    if (buttons[i].fonts && Array.isArray(buttons[i].fonts) && buttons[i].fonts.length > 0) {
                        // Update button text and styling
                        buttons[i].fonts[0].text = buttonText;
                        buttons[i].fonts[0].top = buttonTextTop + 'px';
                        buttons[i].fonts[0].fontSize = buttonFontSize + 'px';
                        buttons[i].fonts[0].fontColor = buttonTextColor;
                        buttons[i].fonts[0].fontWeight = fontWeight;

                        // Update button background color
                        buttons[i].background = buttonColor;
                        break;
                    }
                }

                // Save back to field
                $buttonsField.val(JSON.stringify(buttons));

                // Update the in-memory preset object
                const activePreset = $('#swp_active_preset').val();
                if (activePreset && presetStyles[activePreset]) {
                    presetStyles[activePreset].buttons = buttons;
                }

                // Trigger preview update
                refreshPreview();
            } catch (e) {
                console.warn('Failed to update button text and style:', e);
            }
        }

        // Update button text and styling when button fields change
        $(document).on('input change', '#swp_button_text, #swp_button_text_top, #swp_button_font_size, #swp_button_text_color, #swp_button_color, #swp_font_weight', function () {
            updateButtonTextAndStyle();
        });

        // ========================================================================
        // Preset Styles Functionality
        // ========================================================================

        // Define preset configurations with complete wheel settings including blocks
        const pluginUrl = swpAdminData.pluginUrl || '';

        const presetStyles = {
            default: {
                name: 'Default',
                background_color: '#f7994c',
                padding: 10,
                blocks: [
                    {
                        padding: '10px',
                        background: '#f7994c'
                    }
                ],
                buttons: [
                    {
                        radius: '50px',
                        pointer: true,
                        background: '#f24a09',
                        fonts: [
                            {
                                text: 'SPIN',
                                top: '-10px',
                                fontSize: '18px',
                                fontColor: '#ffffff',
                                fontWeight: '700'
                            }
                        ]
                    }
                ],
                prizes: [
                    { color: '#fff' },
                    { color: '#ffd7b7' },
                    { color: '#fff' },
                    { color: '#ffd7b7' },
                ],
                button_color: '#f24a09',
                show_pointer: 1,
            },

            /** Merged onto `default` when wheel type is nine_squares (big-wheel default stays unchanged). */
            defaultNineSquares: {
                button_text_top: 0,
                grid_rows: 3,
                grid_cols: 3,
                grid_gutter: 5,
                grid_border_radius: 8,
                grid_shadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
                active_background: '#ffd700',
                active_font_color: '#000000',
                active_shadow: '0 4px 16px rgba(255, 215, 0, 0.5)',
            },

            classic: {
                name: 'Classic Red & Gold',
                // Blocks configuration with 3 border images
                padding: 0,
                blocks: [
                    {
                        padding: '62px',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-one-bg.png',
                            width: '100%',
                            height: '100%',
                            // top: '1px',
                            left: '1px',
                        }]
                    },

                ],

                buttons: [
                    {
                        radius: '45%',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-one-arrow.png',
                            width: '90px',
                            height: '90px',
                            top: '-280%'
                        }]
                    },

                    {
                        radius: '45%',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-one-button.png',
                            width: '130px',
                            height: '130px',
                            top: '-90%'

                        }]
                    },
                ],

                // Button top spacing controls
                button_arrow_top: -280,
                button_center_top: -90,

                prizes: [
                    { color: '#fceced' },
                    { color: '#fff' },
                    { color: '#fceced' },
                    { color: '#fff' },

                ],
            },
            ocean: {
                name: 'Ocean Blue',
                padding: 0,
                // Blocks configuration with border images
                blocks: [
                    {
                        padding: '43px',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-two-bg.png',
                            width: '100%',
                            height: '100%',
                            top: '6px',
                            left: '-1px',
                        }]
                    },
                ],

                buttons: [
                    {
                        radius: '45%',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-two-arrow.png',
                            width: '80px',
                            height: '80px',
                            top: '-260%'
                        }]
                    },
                    {
                        radius: '45%',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-two-button.png',
                            width: '200px',
                            height: '200px',
                            top: '-120%'
                        }]
                    }
                ],

                // Button top spacing controls
                button_arrow_top: -260,
                button_center_top: -120,

                prizes: [
                    { color: '#fdebc3' },  // Ocean Blue
                    { color: '#fff' },     // White
                    { color: '#fdebc3' },  // Deep Blue
                    { color: '#fff' },  // Light Blue
                ],
            },
            festive: {
                name: 'Festive Mix',
                padding: 0,
                // Blocks configuration with 3 border images
                blocks: [
                    {
                        padding: '50px',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-three-bg.png',
                            width: '100%',
                            height: '100%',
                            top: '6px',
                            left: '-5px',
                        }]
                    },
                ],

                buttons: [
                    {
                        radius: '45%',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-three-button.png',
                            width: '130px',
                            height: '130px',
                            top: '-100%'
                        }]
                    }
                ],

                // Button top spacing controls
                button_center_top: -100,

                prizes: [
                    { color: '#e8b1ff' },
                    { color: '#fff' },
                    { color: '#e8b1ff' },
                    { color: '#fff' },
                ],
            },

            // Crimson Black Wheel 
            crimson: {
                name: 'Crimson Black Wheel ',
                padding: 0,
                // Blocks configuration with 3 border images
                blocks: [
                    {
                        padding: '46px',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-4-bg.png',
                            width: '100%',
                            height: '100%',
                            top: '-1px',
                            // left: '-1px',
                        }]
                    },
                ],

                buttons: [
                    {
                        radius: '45%',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-4-arrows.png',
                            width: '100px',
                            height: '100px',
                            top: '-255%'
                        }]
                    },
                    {
                        radius: '45%',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-4-button.png',
                            width: '100px',
                            height: '100px',
                            top: '-60%'
                        }]
                    }
                ],

                // Button top spacing controls
                button_arrow_top: -255,
                button_center_top: -60,

                prizes: [
                    { color: '#fce2bf' },
                    { color: '#fff' },
                    { color: '#fce2bf' },
                    { color: '#fff' },
                ],
            },

            // Mega Reward Spinner
            megaReward: {
                name: 'Mega Reward Spinner',
                padding: 0,
                blocks: [
                    {
                        padding: '57px',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-5-bg.png',
                            width: '100%',
                            height: '100%',
                            // top: '1px',
                            // left: '1px',
                        }]
                    },
                ],

                buttons: [
                    {
                        radius: '45%',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-5-arrow.png',
                            width: '100px',
                            height: '100px',
                            top: '-290%'
                        }]
                    },
                    {
                        radius: '45%',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-5-button.png',
                            width: '135px',
                            height: '135px',
                            top: '-85%'
                        }]
                    }
                ],

                // Button top spacing controls
                button_arrow_top: -290,
                button_center_top: -85,

                prizes: [
                    { color: '#eff1f1' },
                    { color: '#ccefff' },
                    { color: '#eff1f1' },
                    { color: '#ccefff' },
                ],
            },

            // Candy Pop Wheel
            candyPop: {
                name: 'Candy Pop Wheel',
                padding: 0,
                blocks: [
                    {
                        padding: '68px',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-6-bg.png',
                            width: '100%',
                            height: '100%',
                            top: '-5px',
                            // left: '1px',
                        }]
                    },
                ],

                buttons: [
                    {
                        radius: '45%',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-6-arrow.png',
                            width: '100px',
                            height: '100px',
                            top: '-310%'
                        }]
                    },
                    {
                        radius: '45%',
                        imgs: [{
                            src: pluginUrl + 'assets/images/presets/preset-6-button.png',
                            width: '100px',
                            height: '100px',
                            top: '-75%'
                        }]
                    }
                ],

                // Button top spacing controls
                button_arrow_top: -310,
                button_center_top: -75,

                prizes: [
                    { color: '#fff' },
                    { color: '#fff6c4' },
                    { color: '#fff' },
                    { color: '#fff6c4' },
                ],
            },

            /**
             * Nine-square optional preset: circular / pill-shaped cells (Default preset = square cells).
             */
            circleStyle: {
                name: 'Circle Style',
                width: 460,
                height: 460,
                background_color: '#e8e4f4',
                padding: 14,
                blocks: [
                    {
                        padding: '14px',
                        background: '#e8e4f4',
                    },
                ],
                buttons: [
                    {
                        radius: '50px',
                        pointer: false,
                        background: '#b0c4f4',
                        fonts: [
                            {
                                text: 'SPIN',
                                top: '0px',
                                fontSize: '18px',
                                fontColor: '#000000',
                                fontWeight: '700',
                            },
                        ],
                    },
                ],
                prizes: [
                    { color: '#b0c4f4' },
                    { color: '#b0c4f4' },
                    { color: '#b0c4f4' },
                    { color: '#b0c4f4' },
                    { color: '#b0c4f4' },
                    { color: '#b0c4f4' },
                    { color: '#b0c4f4' },
                    { color: '#b0c4f4' },
                ],
                button_color: '#b0c4f4',
                button_text_color: '#000000',
                show_pointer: 0,
                button_radius: 48,
                prize_font_size: 15,
                prize_font_color: '#000000',
                prize_line_height: 16,
                grid_rows: 3,
                grid_cols: 3,
                grid_gutter: 10,
                grid_border_radius: 50,
                grid_shadow: 'none',
                active_background: '#9eb6f0',
                active_font_color: '#000000',
                active_shadow: 'none',
            },

            /**
             * Nine-square: perimeter ring (center = spin). Size 3×3, 5×5, or 7×7 from rows/cols.
             *
             * Prize colors mirror the Ring Grid preset card thumbnail (rainbow ring around the
             * center spin button). Order is the clockwise ring walk from top-left so the eight
             * outer cells of a 3×3 grid line up visually with the thumbnail. Cycled to 48
             * entries to support 5×5 and 7×7 layouts as well.
             */
            ringGrid: {
                name: 'Ring Grid',
                width: 460,
                height: 460,
                background_color: '#e9e8fe',
                grid_default_background: '#b8c5f2',
                padding: 0,
                blocks: [
                    { padding: '10px', background: '#869cfa' },
                    { padding: '10px', background: '#e9e8fe' },
                ],
                prizes: (function () {
                    const colors = [
                        '#ff6b9d', '#fcc419', '#51cf66', '#cc5de8',
                        '#94d82d', '#4dabf7', '#ff922b', '#339af0'
                    ];
                    const out = [];
                    let i;
                    for (i = 0; i < 48; i++) {
                        out.push({ color: colors[i % colors.length] });
                    }
                    return out;
                }()),
                button_color: '#9c9dd8',
                button_text_color: '#ffffff',
                show_pointer: 0,
                button_radius: 12,
                prize_font_size: 14,
                prize_font_color: '#333333',
                prize_line_height: 16,
                grid_rows: 3,
                grid_cols: 3,
                grid_gutter: 0,
                grid_border_radius: 50,
                grid_panel_border_radius: 24,
                grid_shadow: 'none',
                active_background: '#f7cf9f',
                active_font_color: '#000000',
                active_shadow: 'none',
            },

            /**
             * Nine-square: External Spin — doc-style blocks + spin button below canvas.
             *
             * Prize colors mirror the External Spin preset card thumbnail: row-major rainbow
             * matching the six tiles a user sees on the preset card so the picker, admin
             * preview, and live frontend all look like the thumbnail after applying.
             */
            grid2x3: {
                name: 'External Spin',
                width: 460,
                height: 307,
                background_color: '#e9e8fe',
                grid_default_background: '#b8c5f2',
                padding: 0,
                blocks: [
                    { padding: '10px', background: '#869cfa' },
                    { padding: '10px', background: '#e9e8fe' },
                ],
                prizes: [
                    { color: '#ff6b9d' },
                    { color: '#fcc419' },
                    { color: '#51cf66' },
                    { color: '#339af0' },
                    { color: '#cc5de8' },
                    { color: '#94d82d' },
                ],
                button_color: '#e45912',
                button_text_color: '#ffffff',
                show_pointer: 0,
                button_radius: 12,
                prize_font_size: 14,
                prize_font_color: '#333333',
                prize_line_height: 16,
                grid_rows: 2,
                grid_cols: 3,
                grid_gutter: 0,
                grid_border_radius: 8,
                grid_panel_border_radius: 20,
                grid_shadow: 'none',
                active_background: '#f7cf9f',
                active_font_color: '#000000',
                active_shadow: 'none',
            },
        };

        function getPresetCardLayout(presetKey) {
            const $c = $('.swp-preset-card[data-preset="' + presetKey + '"]');
            if (!$c.length) {
                return 'any';
            }
            return $c.attr('data-swp-preset-layout') || 'any';
        }

        function isActivePresetAllowedForWheelType(presetKey, wheelType) {
            const layout = getPresetCardLayout(presetKey);
            if (layout === 'any') {
                return true;
            }
            if (wheelType === 'slot_machine') {
                return false;
            }
            return layout === wheelType;
        }

        function syncPresetGridToWheelType() {
            const wheelType = $('#swp_wheel_type').val() || 'big_wheel';
            $('.swp-preset-grid .swp-preset-card').each(function () {
                const layout = $(this).attr('data-swp-preset-layout') || 'any';
                let show = layout === 'any';
                if (!show) {
                    if (wheelType === 'slot_machine') {
                        show = false;
                    } else {
                        show = layout === wheelType;
                    }
                }
                $(this).toggle(show);
            });
            updateDefaultPresetThumbnailVisibility();
        }

        function resolvePresetForApplication(presetName) {
            const base = presetStyles[presetName];
            if (!base) {
                return null;
            }
            if (presetName !== 'default') {
                return base;
            }
            const wheelType = $('#swp_wheel_type').val() || 'big_wheel';
            if (wheelType === 'nine_squares' && presetStyles.defaultNineSquares) {
                return $.extend(true, {}, base, presetStyles.defaultNineSquares);
            }
            return base;
        }

        function updateDefaultPresetThumbnailVisibility() {
            const $wrap = $('.swp-preset-preview--default');
            if (!$wrap.length) {
                return;
            }
            const wheelType = $('#swp_wheel_type').val() || 'big_wheel';
            const $big = $wrap.find('.swp-preset-default-thumb--big-wheel');
            const $grid = $wrap.find('.swp-preset-default-thumb--nine-squares');
            if (wheelType === 'nine_squares') {
                $big.hide();
                $grid.show();
                $wrap.addClass('swp-preset-default-preview--grid');
            } else {
                $big.show();
                $grid.hide();
                $wrap.removeClass('swp-preset-default-preview--grid');
            }
        }

        // Hydrate presetStyles from saved configuration
        // This ensures that if we saved custom padding for a preset, it's remembered on reload
        const savedBlocksConfig = $('#swp_blocks_config').val();
        const savedActivePreset = $('#swp_active_preset').val();

        if (savedBlocksConfig && savedActivePreset && presetStyles[savedActivePreset]) {
            try {
                const savedBlocks = JSON.parse(savedBlocksConfig);
                if (Array.isArray(savedBlocks) && savedBlocks.length > 0) {
                    // Update the in-memory preset with the saved blocks
                    presetStyles[savedActivePreset].blocks = savedBlocks;
                }
            } catch (e) {
                console.warn('Failed to parse saved blocks config:', e);
            }
        }

        // Toggle visibility of Basic Settings and Big Wheel Configuration based on preset
        function togglePresetSettingsVisibility(presetName) {
            // Find the Basic Settings accordion item
            const $basicSettings = $('.swp-accordion-item').filter(function () {
                return $(this).find('.swp-accordion-header[data-target="basic-settings"]').length > 0;
            });

            // Always show the main sections
            $basicSettings.show();

            // Handle fields with visibility attributes
            $('[data-visible-on], [data-visible-off]').each(function () {
                const $el = $(this);
                let shouldShow = true; // Default state depends on attribute used

                // Priority 1: data-visible-off (Exclusion)
                // If present, show everywhere EXCEPT listed presets
                if ($el.is('[data-visible-off]')) {
                    const visibleOff = $el.data('visible-off');
                    const excludedPresets = visibleOff.split(',').map(p => p.trim());

                    if (excludedPresets.includes(presetName)) {
                        shouldShow = false;
                    } else {
                        shouldShow = true;
                    }
                }
                // Priority 2: data-visible-on (Inclusion)
                // If present, show ONLY in listed presets
                else if ($el.is('[data-visible-on]')) {
                    const visibleOn = $el.data('visible-on');
                    const allowedPresets = visibleOn.split(',').map(p => p.trim());

                    if (allowedPresets.includes(presetName)) {
                        shouldShow = true;
                    } else {
                        shouldShow = false;
                    }
                }

                if (shouldShow) {
                    $el.show();
                } else {
                    $el.hide();
                }
            });

            updateDesignSections();
        }

        function swpApplyPresetConfiguration(presetName, options) {
            const opts = options || {};
            const preset = resolvePresetForApplication(presetName);

            if (!preset) {
                console.error('Preset not found:', presetName);
                return false;
            }

            $('.swp-preset-card').removeClass('swp-preset-active');
            $('.swp-preset-card[data-preset="' + presetName + '"]').addClass('swp-preset-active');

            $('#swp_active_preset').val(presetName);

            applyPresetValues(preset);

            if (preset.blocks) {
                const $blocksField = $('#swp_blocks_config');
                if ($blocksField.length) {
                    $blocksField.val(JSON.stringify(preset.blocks));

                    if (preset.blocks.length > 0 && preset.blocks[0].padding) {
                        const paddingVal = parseInt(preset.blocks[0].padding, 10);
                        $('#swp_wheel_border_padding').val(paddingVal);
                    }
                }
            } else {
                $('#swp_blocks_config').val('');
            }

            if (preset.buttons) {
                const $buttonsField = $('#swp_buttons_config');
                if ($buttonsField.length) {
                    $buttonsField.val(JSON.stringify(preset.buttons));
                }
            } else {
                $('#swp_buttons_config').val('');
            }

            let colorsToApply = preset.colors;
            if (!colorsToApply && preset.prizes && Array.isArray(preset.prizes)) {
                colorsToApply = preset.prizes.map(prize => prize.color);
            }
            if (colorsToApply && colorsToApply.length > 0) {
                applyColorsToFirstPrizes(colorsToApply);
            }

            if (!opts.silent) {
                showPresetNotification(preset.name + ' applied successfully!');
            }

            togglePresetSettingsVisibility(presetName);

            setTimeout(function () {
                refreshPreview();
            }, 300);

            return true;
        }

        function reconcileActivePresetForWheelType() {
            const wheelType = $('#swp_wheel_type').val() || 'big_wheel';
            const active = ($('#swp_active_preset').val() || 'default').toString().trim();
            if (!isActivePresetAllowedForWheelType(active, wheelType)) {
                swpApplyPresetConfiguration('default', { silent: true });
            }
        }

        // Restore active preset on page load
        let activePreset = $('#swp_active_preset').val();

        if (!activePreset) {
            activePreset = 'default';
            $('#swp_active_preset').val('default');
        }

        syncPresetGridToWheelType();

        if (!isActivePresetAllowedForWheelType(activePreset, $('#swp_wheel_type').val() || 'big_wheel')) {
            swpApplyPresetConfiguration('default', { silent: true });
            activePreset = 'default';
        } else {
            $('.swp-preset-card').removeClass('swp-preset-active');
            $('.swp-preset-card[data-preset="' + activePreset + '"]').addClass('swp-preset-active');
            togglePresetSettingsVisibility(activePreset);
        }

        $(document).on('change', '#swp_wheel_type', function () {
            syncPresetGridToWheelType();
            const wheelType = $('#swp_wheel_type').val() || 'big_wheel';
            const current = ($('#swp_active_preset').val() || 'default').toString().trim();
            if (!isActivePresetAllowedForWheelType(current, wheelType)) {
                swpApplyPresetConfiguration('default', { silent: true });
            } else if (current === 'default') {
                swpApplyPresetConfiguration('default', { silent: true });
            } else {
                togglePresetSettingsVisibility(current);
            }
        });

        // Apply preset styles
        $(document).on('click', '.swp-preset-card', function (e) {
            e.preventDefault();
            e.stopPropagation();

            const presetName = $(this).data('preset');

            if (!presetStyles[presetName]) {
                console.error('Preset not found:', presetName);
                return;
            }

            swpApplyPresetConfiguration(presetName, { silent: false });
        });

        // Apply all preset values to form fields
        function applyPresetValues(preset) {
            // Helper function to update input and trigger change
            const updateField = (selector, value) => {
                const $field = $(selector);
                if ($field.length) {
                    $field.val(value).trigger('change').trigger('input');

                    // Update range slider if exists
                    const $slider = $field.siblings('.swp-range-slider');
                    if ($slider.length) {
                        $slider.val(value);
                        // Determine the correct unit
                        const isPercentage = $field.attr('id') === 'swp_prize_text_top' ||
                            $field.hasClass('percentage-control');
                        const isPrizeImgOffsetPx = $field.attr('id') === 'swp_prize_image_left' ||
                            $field.attr('id') === 'swp_prize_image_top';
                        const isRotation = $field.attr('id') === 'swp_prize_text_rotation' ||
                            $field.attr('id') === 'swp_wheel_offset_degree' ||
                            $field.attr('id')?.includes('rotation') ||
                            $field.attr('id')?.includes('degree');
                        const unit = isPercentage ? '%' : (isPrizeImgOffsetPx ? 'px' : (isRotation ? '°' : 'px'));
                        $field.siblings('.swp-slider-value').text(value + unit);
                    }
                }
            };

            // Helper function for color pickers
            const updateColorPicker = (selector, value) => {
                const $field = $(selector);
                if ($field.length) {
                    $field.val(value).trigger('change');
                    if ($field.hasClass('wp-color-picker')) {
                        $field.wpColorPicker('color', value);
                    }
                }
            };

            // Helper function for checkboxes
            const updateCheckbox = (selector, value) => {
                const $field = $(selector);
                if ($field.length) {
                    $field.prop('checked', value == 1).trigger('change');
                }
            };

            // Basic Settings
            if (preset.width) {
                updateField('#swp_width', preset.width);
                updateField('#swp_size', preset.width);
                updateField('#swp_hidden_width', preset.width);
            }
            if (preset.height) {
                updateField('#swp_height', preset.height);
                updateField('#swp_hidden_height', preset.height);
            }
            if (preset.background_color) {
                updateColorPicker('#swp_background_color', preset.background_color);
            }
            if (preset.padding !== undefined) {
                updateField('#swp_padding', preset.padding);
            }

            // Big Wheel Settings
            if (preset.gutter !== undefined) {
                updateField('#swp_wheel_gutter', preset.gutter);
            }
            if (preset.offset_degree !== undefined) {
                updateField('#swp_wheel_offset_degree', preset.offset_degree);
            }
            if (preset.stop_range !== undefined) {
                updateField('#swp_wheel_stop_range', preset.stop_range);
            }

            // Prize Label Typography
            if (preset.prize_font_size) {
                updateField('#swp_prize_font_size', preset.prize_font_size);
            }
            if (preset.prize_font_color) {
                updateColorPicker('#swp_prize_font_color', preset.prize_font_color);
            }
            if (preset.prize_font_weight) {
                $('#swp_prize_font_weight').val(preset.prize_font_weight).trigger('change');
            }
            if (preset.prize_line_height) {
                updateField('#swp_prize_line_height', preset.prize_line_height);
            }
            if (preset.prize_text_top_no_image !== undefined) {
                updateField('#swp_prize_text_top_no_image', preset.prize_text_top_no_image);
            }

            // Prize Image Settings
            if (preset.prize_image_size) {
                updateField('#swp_prize_image_size', preset.prize_image_size);
                updateField('#swp_prize_image_width_hidden', preset.prize_image_size);
                updateField('#swp_prize_image_height_hidden', preset.prize_image_size);
                updateField('#swp_prize_image_size_value', preset.prize_image_size);
            }
            if (preset.prize_image_top !== undefined) {
                updateField('#swp_prize_image_top', preset.prize_image_top);
            }
            if (preset.prize_image_left !== undefined) {
                updateField('#swp_prize_image_left', preset.prize_image_left);
            }
            if (preset.prize_image_rotation !== undefined) {
                updateField('#swp_prize_image_rotation', preset.prize_image_rotation);
            }
            if (preset.prize_text_top !== undefined) {
                updateField('#swp_prize_text_top', preset.prize_text_top);
            }

            // Spin Button Settings
            if (preset.button_text) {
                updateField('#swp_button_text', preset.button_text);
            }
            if (preset.button_font_size) {
                updateField('#swp_button_font_size', preset.button_font_size);
            }
            if (preset.button_text_top !== undefined) {
                updateField('#swp_button_text_top', preset.button_text_top);
            }
            if (preset.button_radius) {
                updateField('#swp_button_radius', preset.button_radius);
            }
            if (preset.show_pointer !== undefined) {
                updateCheckbox('input[name="swp_styles[show_pointer]"]', preset.show_pointer);
            }
            if (preset.button_color) {
                updateColorPicker('#swp_button_color', preset.button_color);
            }
            if (preset.button_text_color) {
                updateColorPicker('#swp_button_text_color', preset.button_text_color);
            }

            // Button Top Spacing Controls
            if (preset.button_arrow_top !== undefined) {
                updateField('#swp_button_arrow_top', preset.button_arrow_top);
            }
            if (preset.button_center_top !== undefined) {
                updateField('#swp_button_center_top', preset.button_center_top);
            }

            // Animation Settings
            if (preset.speed) {
                updateField('#swp_speed', preset.speed);
            }
            if (preset.acceleration_time) {
                updateField('#swp_acceleration_time', preset.acceleration_time);
            }
            if (preset.deceleration_time) {
                updateField('#swp_deceleration_time', preset.deceleration_time);
            }

            // Popup Settings
            if (preset.popup_max_width) {
                updateField('#swp_popup_max_width', preset.popup_max_width);
            }
            if (preset.popup_width_percent) {
                updateField('#swp_popup_width_percent', preset.popup_width_percent);
            }
            if (preset.popup_background_color) {
                updateColorPicker('#swp_popup_background_color', preset.popup_background_color);
            }
            if (preset.popup_background_image !== undefined) {
                // Clear popup background image if preset sets it to empty
                updateField('#swp_popup_background_image', preset.popup_background_image);
                if (!preset.popup_background_image) {
                    // Hide image preview, show placeholder
                    $('.swp-image-upload-area[data-target="swp_popup_background_image"]')
                        .find('.swp-image-preview-container').hide();
                    $('.swp-image-upload-area[data-target="swp_popup_background_image"]')
                        .find('.swp-upload-placeholder').show();
                }
            }
            if (preset.popup_border_radius) {
                updateField('#swp_popup_border_radius', preset.popup_border_radius);
            }
            if (preset.popup_padding) {
                updateField('#swp_popup_padding', preset.popup_padding);
            }

            // Nine-square grid layout
            if (preset.grid_rows !== undefined) {
                updateField('#swp_grid_rows', preset.grid_rows);
            }
            if (preset.grid_cols !== undefined) {
                updateField('#swp_grid_cols', preset.grid_cols);
            }
            if (preset.grid_gutter !== undefined) {
                updateField('#swp_grid_gutter', preset.grid_gutter);
            }
            if (preset.grid_border_radius !== undefined) {
                updateField('#swp_grid_border_radius', preset.grid_border_radius);
            }
            if (preset.grid_panel_border_radius !== undefined) {
                updateField('#swp_grid_panel_border_radius', preset.grid_panel_border_radius);
            }
            if (preset.grid_shadow !== undefined) {
                updateField('#swp_grid_shadow', preset.grid_shadow);
            }
            if (preset.grid_default_background) {
                updateField('#swp_grid_default_background', preset.grid_default_background);
            }
            if (preset.active_background) {
                updateColorPicker('#swp_active_background', preset.active_background);
            }
            if (preset.active_font_color) {
                updateColorPicker('#swp_active_font_color', preset.active_font_color);
            }
            if (preset.active_shadow !== undefined) {
                updateField('#swp_active_shadow', preset.active_shadow);
            }

            // Form Style Settings
            if (preset.form_title_color) {
                updateColorPicker('#swp_form_title_color', preset.form_title_color);
            }
            if (preset.form_description_color) {
                updateColorPicker('#swp_form_description_color', preset.form_description_color);
            }
            if (preset.form_label_color) {
                updateColorPicker('#swp_form_label_color', preset.form_label_color);
            }
            if (preset.form_input_color) {
                updateColorPicker('#swp_form_input_color', preset.form_input_color);
            }
            if (preset.form_input_background_color) {
                updateColorPicker('#swp_form_input_background_color', preset.form_input_background_color);
            }
            if (preset.form_input_border_color) {
                updateColorPicker('#swp_form_input_border_color', preset.form_input_border_color);
            }
            if (preset.form_input_focus_border_color) {
                updateColorPicker('#swp_form_input_focus_border_color', preset.form_input_focus_border_color);
            }
        }

        // Apply colors to first prizes
        function applyColorsToFirstPrizes(colors) {
            if (!colors || colors.length === 0) {
                return;
            }

            // Apply colors to existing prizes
            $('.swp-prize-row').each(function (index) {
                if (index < colors.length) {
                    const color = colors[index];
                    const $row = $(this);
                    const $colorInput = $row.find('.swp-prize-color-input');

                    if ($colorInput.length && color) {
                        // Update the input value first
                        $colorInput.val(color);

                        // If it's a WordPress color picker, update it properly
                        if ($colorInput.hasClass('wp-color-picker')) {
                            // Use setTimeout to ensure the color picker is ready
                            setTimeout(function () {
                                $colorInput.wpColorPicker('color', color);

                                // Trigger input and change events for proper updating
                                $colorInput.trigger('input').trigger('change');
                            }, 10);
                        } else {
                            // For non-color-picker inputs, just trigger change
                            $colorInput.trigger('input').trigger('change');
                        }

                        // Also update the color picker button directly (for immediate visual feedback)
                        const $colorButton = $colorInput.siblings('.wp-picker-container').find('.wp-color-result');
                        if ($colorButton.length) {
                            $colorButton.css('background-color', color);
                        }
                    }
                }
            });
        }

        // Update button positions dynamically
        function updateButtonPositions() {
            const activePreset = $('#swp_active_preset').val();
            if (!activePreset || !presetStyles[activePreset] || !presetStyles[activePreset].buttons) {
                return;
            }

            const arrowTop = $('#swp_button_arrow_top').val();
            const centerTop = $('#swp_button_center_top').val();

            // Update the preset configuration
            if (arrowTop !== undefined && arrowTop !== '') {
                if (presetStyles[activePreset].buttons[0] && presetStyles[activePreset].buttons[0].imgs) {
                    presetStyles[activePreset].buttons[0].imgs[0].top = arrowTop + '%';
                }
            }

            if (centerTop !== undefined && centerTop !== '') {
                const buttonIndex = presetStyles[activePreset].buttons.length > 1 ? 1 : 0;
                if (presetStyles[activePreset].buttons[buttonIndex] && presetStyles[activePreset].buttons[buttonIndex].imgs) {
                    presetStyles[activePreset].buttons[buttonIndex].imgs[0].top = centerTop + '%';
                }
            }

            // Update the buttons config field
            $('#swp_buttons_config').val(JSON.stringify(presetStyles[activePreset].buttons));

            // Trigger preview update
            setTimeout(function () {
                refreshPreview();
            }, 100);
        }

        // Listen for button position changes
        $(document).on('input change', '#swp_button_arrow_top, #swp_button_center_top', function () {
            updateButtonPositions();
        });

        // Show notification
        function showPresetNotification(message) {
            // Remove existing notification if any
            $('.swp-preset-notification').remove();

            // Create notification with enhanced message
            const $notification = $('<div class="swp-preset-notification">' +
                '<span class="dashicons dashicons-yes-alt"></span> ' +
                '<span>' + message + '</span>' +
                '</div>');

            // Add to body instead of section for fixed positioning
            $('body').append($notification);

            // Show with animation
            setTimeout(() => {
                $notification.addClass('show');
            }, 10);

            // Remove after 4 seconds
            setTimeout(() => {
                $notification.removeClass('show');
                setTimeout(() => {
                    $notification.remove();
                }, 400); // Wait for transition to finish
            }, 4000);
        }

        // Auto-apply default preset for new wheels
        // Apply when active preset is 'default' and no blocks config is saved
        if (activePreset === 'default' && !$('#swp_blocks_config').val()) {
            // Trigger click on default preset card to apply it fully
            setTimeout(function () {
                const $defaultCard = $('.swp-preset-card[data-preset="default"]');
                if ($defaultCard.length) {
                    $defaultCard.trigger('click');
                }
            }, 100);
        }

    });

    // ========== Wheel Mode Toggle - Show/Hide Instant Mode Fields ==========
    function toggleInstantModeFields(animate) {
        const $wheelMode = $('#swp_wheel_mode');
        const $instantModeFields = $('.swp-instant-mode-only');

        if ($wheelMode.length === 0 || $instantModeFields.length === 0) {
            return;
        }

        const wheelMode = $wheelMode.val();

        if (wheelMode === 'instant') {
            if (animate) {
                $instantModeFields.slideDown(200);
            } else {
                $instantModeFields.show();
            }
        } else {
            if (animate) {
                $instantModeFields.slideUp(200);
            } else {
                $instantModeFields.hide();
            }
        }
    }

    // Initialize on page load
    if ($('#swp_wheel_mode').length > 0) {
        toggleInstantModeFields(false);

        // Bind change event
        $('#swp_wheel_mode').on('change', function () {
            toggleInstantModeFields(true);
        });
    }

})(jQuery);
