
//add-spin--item-tab

  jQuery(function($) {
    // --- Live Probability Total and Progress Bar ---
    function updateProbabilityTotal() {
        var total = 0;
        $('.wsww-spin-table input[data-name="spin_probability"]').each(function() {
            var val = parseFloat($(this).val());
            if (!isNaN(val)) total += val;
        });

        var normalizedTotal = Math.round(total * 100) / 100;
        var isPerfectTotal = Math.abs(normalizedTotal - 100) < 0.01;
        var isOverTotal = normalizedTotal > 100;
        $('#probability-total-value').text(normalizedTotal);
        var percent = Math.min(100, Math.max(0, total));
        var bar = $('#probability-progress-bar');
        var input_fields = $('.wsww-spin-table input[data-name="spin_probability"]');
        var msg = $('#probability-progress-message');
        var meter = $('#probability-total-container');

        var addRowBtn = $('.wsww-item-tabs .btn-add-spin-row');
        // Only target the submit button in the visible tab
        var updateBtn = $('.submit_spin_settings');

        bar.css('width', percent + '%');
        meter.removeClass('wsww-probability-perfect wsww-probability-low wsww-probability-high');

        if (isPerfectTotal) {
            meter.addClass('wsww-probability-perfect');
            msg.text('Perfect');
            updateBtn.prop('disabled', false);
            input_fields.css('border-color', '#65bd63');
        } else if (normalizedTotal < 100) {
            meter.addClass('wsww-probability-low');
            msg.text('Need ' + (100 - normalizedTotal) + ' more');
            updateBtn.prop('disabled', true);
            input_fields.css('border-color', '#e5e7eb');
        } else {
            meter.addClass('wsww-probability-high');
            msg.text('Over by ' + (normalizedTotal - 100));
            updateBtn.prop('disabled', true);
            input_fields.css('border-color', '#e84747');
        }

        addRowBtn
            .prop('disabled', isOverTotal)
            .attr('aria-disabled', isOverTotal ? 'true' : 'false')
            .toggleClass('disabled', isOverTotal);
    }

    // On input
    $(document).on('input', '.wsww-spin-table input[data-name="spin_probability"]', updateProbabilityTotal);

    // Watch tbody for row changes using MutationObserver
    const tbody = document.querySelector('.wsww-spin-table tbody');
    if (tbody) {
        const observer = new MutationObserver(() => {
            updateProbabilityTotal();
        });
        observer.observe(tbody, { childList: true, subtree: true });
    }

    // Initial update
    setTimeout(updateProbabilityTotal, 300);


});

/**
 * Render the spin preview wheel using D3 based on config data from the AJAX response.
 *
 * @param {Object} config Preview configuration sent from the server.
 */
window.wswwRenderSpinPreview = function(config) {
    if (!config) {
        return;
    }

    var previewData = Array.isArray(config.spins) ? config.spins : [];
    var previewCircleSize = parseInt(config.circle_size, 10);

    if (!previewCircleSize || previewCircleSize < 100) {
        previewCircleSize = 450;
    }

    var previewArrowIcon = config.arrow_icon || '';
    var previewCenterIcon = config.center_icon || '';
    var previewStrokeColor = config.stroke_color || '#003B33';
    var previewStrokeSize = parseInt(config.stroke_size, 10);
    var previewFontSize = parseInt(config.font_size, 10);
    var previewFontFamily = config.font_family || 'roboto';
    var previewFontStyle = config.font_style || 'bold';
    var previewCenterBg = config.center_background || '#ffffff';
    var previewCenterBorderColor = config.center_border_color || '#003B33';
    var previewCenterBorderWidth = parseInt(config.center_border_width, 10);

    if (isNaN(previewStrokeSize)) {
        previewStrokeSize = 5;
    }
    if (isNaN(previewFontSize)) {
        previewFontSize = 20;
    }
    if (isNaN(previewCenterBorderWidth)) {
        previewCenterBorderWidth = 3;
    }

    // Adjust circle size relative to preview container width.
    (function() {
        try {
            var previewHost = document.getElementById('design_preview');
            var previewSpinSection = previewHost ? previewHost.querySelector('.spin_section') : null;
            if (previewHost) {
                var hostW = previewHost.clientWidth || previewHost.offsetWidth || 0;
                var spinSectionW = previewSpinSection
                    ? (previewSpinSection.clientWidth || previewSpinSection.offsetWidth || 0)
                    : 0;
                var availableW = spinSectionW > 0 ? spinSectionW : hostW;
                if (availableW > 0) {
                    var viewportW = window.innerWidth || document.documentElement.clientWidth || 0;
                    var targetSize;
                    var minSize;
                    var maxSize;

                    if (viewportW >= 1200) {
                        // Desktop: keep compact and stable so form/wheel do not grow with large screens.
                        targetSize = Math.floor(availableW * 0.96);
                        minSize = 360;
                        maxSize = 480;
                    } else if (viewportW >= 768) {
                        // Tablet/laptop: scale down smoothly while preserving readability.
                        targetSize = Math.floor(availableW * 0.72);
                        minSize = 300;
                        maxSize = 440;
                    } else {
                        // Mobile: fit small screens safely without clipping.
                        targetSize = Math.floor(availableW * 0.82);
                        minSize = 220;
                        maxSize = 320;
                    }

                    previewCircleSize = Math.max(minSize, Math.min(maxSize, targetSize));
                }
            }
        } catch (e) {
            // Ignore calculation errors.
        }
    })();

    function renderWheel() {
        var chartElement = document.getElementById('preview-chart');

        if (!chartElement) {
            return false;
        }

        if (typeof d3 === 'undefined') {
            return false;
        }

        if (!previewData.length) {
            chartElement.innerHTML = '<p style="text-align: center; color: #666;">No preview data found.</p>';
            return true;
        }

        d3.select('#preview-chart').selectAll('*').remove();

        var w = previewCircleSize;
        var h = previewCircleSize;
        var r = Math.min(w, h) / 2;
        var padding = { top: 20, right: 40, bottom: 0, left: 50 };

        var svg = d3.select('#preview-chart')
            .append('svg')
            .attr('width', w + padding.left + padding.right)
            .attr('height', h + padding.top + padding.bottom);

        var container = svg.append('g')
            .attr('class', 'chartholder')
            .attr('transform', 'translate(' + (w / 2 + padding.left) + ',' + (h / 2 + padding.top) + ')');

        var vis = container.append('g');
        var pie = d3.layout.pie().sort(null).value(function() { return 1; });
        var arc = d3.svg.arc().outerRadius(r);

        var arcs = vis.selectAll('g.slice')
            .data(pie(previewData))
            .enter()
            .append('g')
            .attr('class', 'slice');

        arcs.append('path')
            .attr('fill', function(d, i) { return previewData[i].spin_bgcolor; })
            .attr('stroke', previewStrokeColor)
            .attr('stroke-width', previewStrokeSize)
            .attr('d', function(d) { return arc(d); });

        var innerPadding = 50;
        var outerPadding = 30;
        arcs.append('text')
            .attr('transform', function(d) {
                d.innerRadius = 0;
                d.outerRadius = r;
                d.angle = (d.startAngle + d.endAngle) / 2;
                return 'rotate(' + (d.angle * 180 / Math.PI - 90) + ')translate(' + (d.innerRadius + innerPadding) + ')';
            })
            .attr('text-anchor', 'start')
            .attr('dominant-baseline', 'central')
            .attr('style', 'font-size:' + previewFontSize + 'px;font-weight:' + previewFontStyle + ';font-family:' + previewFontFamily + ';overflow:hidden;')
            .text(function(d, i) {
                var label = previewData[i].spin_label || '';
                var charWidth = previewFontSize * 0.6;
                var availableWidth = Math.max(0, r - innerPadding - outerPadding);
                var maxLength = Math.max(3, Math.floor(availableWidth / charWidth));
                if (label.length > maxLength) {
                    return label.substring(0, Math.max(1, maxLength - 2)) + '..';
                }
                return label;
            })
            .each(function(d) {
                var available = Math.max(0, d.outerRadius - outerPadding - (d.innerRadius + innerPadding));
                if (this.getComputedTextLength) {
                    var actual = this.getComputedTextLength();
                    if (actual > available && available > 0) {
                        d3.select(this)
                            .attr('lengthAdjust', 'spacingAndGlyphs')
                            .attr('textLength', available);
                    }
                }
            })
            .attr('fill', function(d, i) {
                var hex = (previewData[i].spin_bgcolor || '#ffffff').replace('#', '');
                if (hex.length === 3) {
                    hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
                }
                var rValue = parseInt(hex.substr(0, 2), 16);
                var gValue = parseInt(hex.substr(2, 2), 16);
                var bValue = parseInt(hex.substr(4, 2), 16);
                var luminance = (0.299 * rValue + 0.587 * gValue + 0.114 * bValue) / 255;
                return luminance > 0.5 ? '#000' : '#fff';
            });

        svg.append('g')
            .attr('transform', 'translate(' + (w + padding.left + padding.right) + ',' + ((h / 2) + padding.top) + ')')
            .append('image')
            .attr('xlink:href', previewArrowIcon)
            .attr('width', 50)
            .attr('height', 50)
            .attr('x', -50)
            .attr('y', -10);

        var centerGroup = container.append('g').attr('class', 'wheel-center-logo');
        centerGroup.append('circle')
            .attr('cx', 0)
            .attr('cy', 0)
            .attr('r', 30)
            .attr('fill', previewCenterBg)
            .attr('stroke', previewCenterBorderColor)
            .attr('stroke-width', previewCenterBorderWidth);

        if (previewCenterIcon) {
            centerGroup.append('image')
                .attr('xlink:href', previewCenterIcon)
                .attr('width', 40)
                .attr('height', 40)
                .attr('x', -20)
                .attr('y', -20);
        }

        return true;
    }

    function waitForReady() {
        var attempts = 0;
        var maxAttempts = 100;
        var checkReady = setInterval(function() {
            attempts++;

            if (renderWheel()) {
                clearInterval(checkReady);
                return;
            }

            if (attempts >= maxAttempts) {
                clearInterval(checkReady);
                var chartElement = document.getElementById('preview-chart');
                if (chartElement) {
                    chartElement.innerHTML = '<p style="text-align: center; color: #666;">Failed to generate preview</p>';
                }
            }
        }, 100);
    }

    waitForReady();
};

// Clipboard: copy shortcode from input or button
(function($){
    $(function(){
        // Click on input copies its value
        $(document).on('click', '.shortcode-clipboard', function(){
            var $input = $(this);
            var val = $input.val();
            // Try modern API first
            if (navigator.clipboard && window.isSecureContext) {
                navigator.clipboard.writeText(val).catch(function(){
                    try {
                        $input.prop('readonly', false).focus().select();
                        document.execCommand('copy');
                    } finally {
                        $input.prop('readonly', true).blur();
                    }
                });
            } else {
                try {
                    $input.prop('readonly', false).focus().select();
                    document.execCommand('copy');
                } finally {
                    $input.prop('readonly', true).blur();
                }
            }
        });

        // Click on copy button copies adjacent input
        $(document).on('click', '.wsww-copy-shortcode', function(e){
            e.preventDefault();
            var $btn = $(this);
            var $input = $btn.siblings('.shortcode-clipboard').first();
            if (!$input.length) {
                $input = $btn.closest('.shortcode-group').find('.shortcode-clipboard').first();
            }
            if (!$input.length) return;

            var text = $input.val();
            var done = function(){
                var originalHtml = $btn.data('original-html');
                if (!originalHtml) {
                    originalHtml = $btn.html();
                    $btn.data('original-html', originalHtml);
                }
                $btn.html('<span class="dashicons dashicons-yes"></span>');
                setTimeout(function(){ $btn.html(originalHtml); }, 1200);
            };

            if (navigator.clipboard && window.isSecureContext) {
                navigator.clipboard.writeText(text).then(done).catch(function(){
                    try {
                        $input.prop('readonly', false).focus().select();
                        document.execCommand('copy');
                        done();
                    } finally {
                        $input.prop('readonly', true).blur();
                    }
                });
            } else {
                try {
                    $input.prop('readonly', false).focus().select();
                    document.execCommand('copy');
                    done();
                } finally {
                    $input.prop('readonly', true).blur();
                }
            }
        });
    });
})(jQuery);

 

//item-tab-js


document.addEventListener('DOMContentLoaded', function() {
    const itemTableBody = document.querySelector('.wsww-spin-table tbody');
    if (!itemTableBody) {
        return;
    }

    // --- PREDEFINED COLOR PALETTES ---
    const colorPalettes = {
        1: [
            { bg: "#B95660", text: "#ffffff" }, 
            { bg: "#F67280", text: "#000000" }, 
            { bg: "#FCD3D8", text: "#001E38" },  
            { bg: "#FEF1F2", text: "#000000" }  
        ],
        2: [
            { bg: "#004C41", text: "#FFFFFF" }, 
            { bg: "#008774", text: "#000000" }, 
            { bg: "#B0E4DD", text: "#001E38" },
            { bg: "#D9F2EF", text: "#000000" } 
        ], 
        3: [
            { bg: "#009FE0", text: "#FFFFFF" }, 
            { bg: "#008FCA", text: "#000000" }, 
            { bg: "#0077A8", text: "#001E38" },  
            { bg: "#D9F1FA", text: "#000000" }  
        ],
        4: [
            { bg: "#99442D", text: "#FFFFFF" }, 
            { bg: "#E66644", text: "#000000" }, 
            { bg: "#FFEAE4", text: "#001E38" },
            { bg: "#FF714B", text: "#000000" } 
        ], 
        5: [
            { bg: "#77123C", text: "#FFFFFF" }, 
            { bg: "#EEB9CF", text: "#000000" }, 
            { bg: "#C71E64", text: "#001E38" },  
            { bg: "#F9E9F0", text: "#000000" }  
        ],
        6: [
            { bg: "#8161FF", text: "#000000" }, 
            { bg: "#A77AFF", text: "#000000" }, 
            { bg: "#C29EFF", text: "#001E38" },
            { bg: "#F2EFFF", text: "#000000" } 
        ], 
        7: [
            { bg: "#B0E4DD", text: "#000000" }, 
            { bg: "#00A991", text: "#000000" }, 
            { bg: "#007F6D", text: "#001E38" },
            { bg: "#00B88F", text: "#000000" } 
        ], 
        8: [
            { bg: "#00376E", text: "#FDEF9A" }, 
            { bg: "#F84B25", text: "#690101" }, 
            { bg: "#F8B214", text: "#001E38" },
            { bg: "#00B88F", text: "#690101" } 
        ], 
    };

    // --- REMEMBER LAST APPLIED PALETTE ---
    let lastAppliedPaletteType = null;

    // --- APPLY PALETTE FUNCTION ---
    function applyPalette(type) {
        const rows = itemTableBody.querySelectorAll("tr");
        const palette = colorPalettes[type];
        const paletteLen = palette.length;

        rows.forEach((row, i) => {
            const bgInput = row.querySelector('input[name*="[spin_bgcolor]"]');
            const textInput = row.querySelector('input[name*="[spin_textcolor]"]');

            if (bgInput && textInput) {
                const theme = palette[i % paletteLen]; // cycle through colors
                bgInput.value = theme.bg;
                textInput.value = theme.text;

                // live preview (optional)
                //  row.style.backgroundColor = theme.bg;
                //  row.style.color = theme.text;
            }
        });
    }

    // --- ATTACH THEME BUTTONS ---
    document.getElementById("btn-theme-1")?.addEventListener("click", () => {
        lastAppliedPaletteType = 1;
        applyPalette(1);
    });
    document.getElementById("btn-theme-2")?.addEventListener("click", () => {
        lastAppliedPaletteType = 2;
        applyPalette(2);
    });
    document.getElementById("btn-theme-3")?.addEventListener("click", () => {
        lastAppliedPaletteType = 3;
        applyPalette(3);
    });
    document.getElementById("btn-theme-4")?.addEventListener("click", () => {
        lastAppliedPaletteType = 4;
        applyPalette(4);
    });
    document.getElementById("btn-theme-5")?.addEventListener("click", () => {
        lastAppliedPaletteType = 5;
        applyPalette(5);
    });
    document.getElementById("btn-theme-6")?.addEventListener("click", () => {
        lastAppliedPaletteType = 6;
        applyPalette(6);
    });
    document.getElementById("btn-theme-7")?.addEventListener("click", () => {
        lastAppliedPaletteType = 7;
        applyPalette(7);
    });
    document.getElementById("btn-theme-8")?.addEventListener("click", () => {
        lastAppliedPaletteType = 8;
        applyPalette(8);
    });

    // --- GET NEXT INDEX FOR NEW ROW ---
    function getNextSpinIndex() {
        const inputs = itemTableBody.querySelectorAll('input[name^="spins["], select[name^="spins["]');
        let max = 0;
        inputs.forEach(el => {
            const m = el.name.match(/spins\[(\d+)\]/);
            if (m) max = Math.max(max, parseInt(m[1], 10));
        });
        return max + 1;
    }

    // --- INFER PALETTE FROM EXISTING ROWS ---
    function detectPaletteTypeFromExisting() {
        const rows = itemTableBody.querySelectorAll('tr');
        if (!rows.length) return null;
        const normalize = (v) => (v || '').toString().trim().toUpperCase();

        const paletteMaps = {};
        Object.keys(colorPalettes).forEach((key) => {
            paletteMaps[key] = new Set(
                (colorPalettes[key] || []).map(c => `${normalize(c.bg)}|${normalize(c.text)}`)
            );
        });

        const counts = {};
        rows.forEach(row => {
            const bgInput = row.querySelector('input[name*="[spin_bgcolor]"]');
            const textInput = row.querySelector('input[name*="[spin_textcolor]"]');
            if (!bgInput || !textInput) return;
            const pair = `${normalize(bgInput.value)}|${normalize(textInput.value)}`;
            Object.keys(paletteMaps).forEach(key => {
                if (paletteMaps[key].has(pair)) {
                    counts[key] = (counts[key] || 0) + 1;
                }
            });
        });

        let bestKey = null; let bestCount = 0;
        Object.keys(counts).forEach(key => {
            if (counts[key] > bestCount) { bestCount = counts[key]; bestKey = parseInt(key, 10); }
        });
        return bestCount > 0 ? bestKey : null;
    }

    // --- DELETE BUTTON HANDLER (event delegation) ---
    document.addEventListener('click', function(e) {
        const btn = e.target.closest('.btn-delete');
        if (btn && btn.closest('.wsww-spin-table')) {
            if (confirm('Are you sure you want to delete this item?')) {
                const row = btn.closest('tr');
                if (row && row.parentElement === itemTableBody) {
                    row.remove();
                }
            }
        }
    });

    // --- ADD ROW HANDLER ---
    document.addEventListener('click', function(e) {
        const addBtn = e.target.closest('.btn.btn-add-spin-row');
        if (!addBtn) return;
        if (addBtn.disabled || addBtn.classList.contains('disabled')) {
            return;
        }

        const tbody = itemTableBody;
        const idx = getNextSpinIndex();

        // Determine default colors when no palette has been selected
        let defaultBg = '#ffffff';
        let defaultText = '#000000';
        if (!lastAppliedPaletteType) {
            // Try to infer an existing palette from current rows; fallback to palette 2
            const inferredType = detectPaletteTypeFromExisting();
            const typeToUse = inferredType || 2;
            const fallbackPalette = (typeof colorPalettes !== 'undefined') ? colorPalettes[typeToUse] : null;
            if (fallbackPalette && fallbackPalette.length) {
                const existingRows = tbody ? tbody.querySelectorAll('tr').length : 0;
                const theme = fallbackPalette[existingRows % fallbackPalette.length];
                if (theme) {
                    defaultBg = theme.bg;
                    defaultText = theme.text;
                }
            }
        }

        const newRow = document.createElement('tr');
        newRow.innerHTML = `
            <td class="ps-3">
              <input type="hidden" name="spins[${idx}][spin_item_unique_id]" value="">
              <select class="form-select" name="spins[${idx}][is_win]">
                <option value="yes">Yes</option>
                <option value="no">No</option>
              </select>
            </td>
            <td>
              <input type="text" class="form-control" name="spins[${idx}][spin_label]" value="">
            </td>
            <td>
              <input type="text" class="form-control" name="spins[${idx}][spin_value]" value="">
            </td>
            <td class="ps-3">
              <input type="number" min="0" max="100" class="form-control" name="spins[${idx}][spin_probability]" data-name="spin_probability" value="0">
            </td>
            <td>
              <input type="color" class="form-control form-control-color" name="spins[${idx}][spin_bgcolor]" value="${defaultBg}">
            </td>
            <td>
              <input type="color" class="form-control form-control-color" name="spins[${idx}][spin_textcolor]" value="${defaultText}">
            </td>
            <td class="pe-3">
              <button type="button" class="btn-delete" title="Delete row" aria-label="Delete row"><span class="dashicons dashicons-trash" aria-hidden="true"></span></button>
            </td>
        `;

        tbody.appendChild(newRow);

     

        // reapply last chosen palette to include the new row
        if (lastAppliedPaletteType) {
            applyPalette(lastAppliedPaletteType);
        }
    });

    
});



// Clamp numeric inputs for wheel stroke font size to [5, 90]
document.addEventListener('input', function(e) {
    const el = e.target;
    if (el && el.name === 'wheel_stroke_font_size') {
        const min = 5;
        const max = 90;
        let v = parseInt(el.value, 10);
        if (isNaN(v)) { return; }
        if (v > max) { el.value = max; }
        if (v < min) { el.value = min; }
    }
});

document.addEventListener('change', function(e) {
    const el = e.target;
    if (el && el.name === 'wheel_stroke_font_size') {
        const min = 5;
        const max = 90;
        let v = parseInt(el.value, 10);
        if (isNaN(v)) { el.value = min; return; }
        if (v > max) { el.value = max; }
        if (v < min) { el.value = min; }
    }
});


// add spin--design tab

document.addEventListener("DOMContentLoaded", function() {
    const select = document.getElementById("centerImageOption");
    const uploadDiv = document.getElementById("customImageUpload");
    const previewImg = document.getElementById("imagePreview");

    if (!select || !uploadDiv || !previewImg) return;

    select.addEventListener("change", function() {
        const selectedOption = this.options[this.selectedIndex];
        const imgUrl = selectedOption.getAttribute("data-img") || "";

        if (this.value === "custom") {
            uploadDiv.style.display = "block";
            previewImg.src = imgUrl;
        } else {
            uploadDiv.style.display = "none";
            previewImg.src = imgUrl;
        }
    });
});

// Preview custom uploaded image
function previewCustomImage(event) {
    const previewImg = document.getElementById("imagePreview");
    if (!previewImg || !event.target.files || !event.target.files[0]) return;
    previewImg.src = URL.createObjectURL(event.target.files[0]);
}






 
// Spin Display Settings --> When Load
document.addEventListener('DOMContentLoaded', () => {
    const spinType = document.getElementById('spin_type');
    if (!spinType) return;

    const body = document.body;
    const toggleClass = () =>
        body.classList.toggle('spin_button', spinType.value === 'spin_button');

    toggleClass(); // Initial check
    spinType.addEventListener('change', toggleClass);
});
 

// CMS/Email sync fields visibility
document.addEventListener('DOMContentLoaded', function() {
    const syncToggle = document.getElementById('wsww-sync-enabled');
    const syncFields = document.getElementById('wsww-sync-settings-fields');

    if (!syncToggle || !syncFields) {
        return;
    }

    const toggleSyncFields = function() {
        syncFields.style.display = syncToggle.checked ? '' : 'none';
    };

    toggleSyncFields();
    syncToggle.addEventListener('change', toggleSyncFields);
});

// Spin Preview Functionality
document.addEventListener('DOMContentLoaded', function() {
    const previewBtn = document.getElementById('preview-spin-btn');
    const previewBtnText = document.getElementById('preview-btn-text');
    const previewContainer = document.getElementById('design_preview');

    const setPreviewBusyState = function(isBusy) {
        if (!previewBtn || !previewBtnText) {
            return;
        }
        previewBtn.disabled = isBusy;
        previewBtn.setAttribute('aria-busy', isBusy ? 'true' : 'false');
        previewBtnText.textContent = isBusy ? 'Updating...' : 'Update Preview';
    };

    if (previewBtn && previewContainer) {
        setTimeout(() => {
            try { previewBtn.click(); } catch (e) {}
        }, 1000);

        previewBtn.addEventListener('click', function(e) {
            e.preventDefault();
            setPreviewBusyState(true);

            previewContainer.innerHTML = '<div style="text-align: center; padding: 40px;"><div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div><p style="margin-top: 10px;">Generating preview...</p></div>';

            const proceed = (inlineCustomImageDataUrl) => {
                let formData;
                try {
                    const form = document.querySelector('form');
                    if (form) {
                        const formDataObj = new FormData(form);
                        formData = {};
                        for (let [key, value] of formDataObj.entries()) {
                            if (key !== '_wpnonce' && key !== 'submit_spin_settings' && key !== '_wp_http_referer') {
                                let cleanValue = value;
                                if (typeof value === 'object') {
                                    cleanValue = '';
                                } else if (typeof value === 'string') {
                                    cleanValue = value.replace(/[\r\n\t]/g, ' ').replace(/\s+/g, ' ').trim();
                                }
                                if (formData[key]) {
                                    if (Array.isArray(formData[key])) {
                                        formData[key].push(cleanValue);
                                    } else {
                                        formData[key] = [formData[key], cleanValue];
                                    }
                                } else {
                                    formData[key] = cleanValue;
                                }
                            }
                        }
                    } else {
                        formData = collectFormData();
                    }
                } catch (e) { formData = collectFormData(); }

                // Inject the data URL for custom center image if available
                if (inlineCustomImageDataUrl) { formData['custom_wheel_center_image_icon_data'] = inlineCustomImageDataUrl; }

                formData = cleanFormDataForJSON(formData);

                try {
                    let formDataJson;
                    try {
                        formDataJson = JSON.stringify(formData);
                    } catch (jsonError) {
                        console.error('JSON stringify failed:', jsonError);
                        console.log('Problematic form data:', formData);
                        for (const [key, value] of Object.entries(formData)) {
                            try { JSON.stringify({ test: value }); } catch (fieldError) { console.error(`Problematic field: ${key} = ${value}`, fieldError); }
                        }
                        throw jsonError;
                    }

                    const xhr = new XMLHttpRequest();
                    xhr.open('POST', wsww_ajax_object.ajax_url, true);
                    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

                    xhr.onreadystatechange = function() {
                        if (xhr.readyState === 4) {
                            setPreviewBusyState(false);
                            if (xhr.status === 200) {
                                try {
                                    const response = JSON.parse(xhr.responseText);
                                    if (response.success) {
                                        previewContainer.innerHTML = response.data.preview_html;
                                        if (response.data.preview_config && typeof window.wswwRenderSpinPreview === 'function') {
                                            window.wswwRenderSpinPreview(response.data.preview_config);
                                        }
                                    } else {
                                        previewContainer.innerHTML = '<div style="text-align: center; padding: 40px; color: #dc3545;"><p>Error: ' + (response.data?.message || 'Failed to generate preview') + '</p></div>';
                                    }
                                } catch (e) {
                                    previewContainer.innerHTML = '<div style="text-align: center; padding: 40px; color: #dc3545;"><p>Error parsing response: ' + e.message + '</p><pre>' + xhr.responseText + '</pre></div>';
                                }
                            } else {
                                previewContainer.innerHTML = '<div style="text-align: center; padding: 40px; color: #dc3545;"><p>Error: ' + xhr.status + ' ' + xhr.statusText + '</p></div>';
                            }
                        }
                    };

                    if (typeof wsww_ajax_object === 'undefined') {
                        throw new Error('AJAX object not defined');
                    }

                    const params = new URLSearchParams();
                    params.append('action', 'wsww_spin_preview');
                    params.append('_ajax_nonce', wsww_ajax_object.preview_nonce);
                    params.append('form_data', formDataJson);

                    for (const [key, value] of Object.entries(formData)) {
                        if (Array.isArray(value)) {
                            value.forEach((item, index) => { params.append(`${key}[${index}]`, item); });
                        } else {
                            params.append(key, value);
                        }
                    }

                    xhr.send(params.toString());
                } catch (e) {
                    setPreviewBusyState(false);
                    previewContainer.innerHTML = '<div style="text-align: center; padding: 40px; color: #dc3545;"><p>Error preparing form data: ' + e.message + '</p></div>';
                }
            };

            // If user chose custom image and selected a file, read it as data URL
            const select = document.getElementById('centerImageOption');
            const fileInput = document.querySelector('input[type="file"][name="custom_wheel_center_image_icon"]');
            const isCustomSelected = select && select.value === 'custom';
            const hasFile = fileInput && fileInput.files && fileInput.files[0];

            if (isCustomSelected && hasFile) {
                const reader = new FileReader();
                reader.onload = function(evt) { proceed(evt.target.result); };
                reader.onerror = function() { proceed(null); };
                reader.readAsDataURL(fileInput.files[0]);
            } else {
                proceed(null);
            }
        });
    }

    function collectFormData() {
        const formData = {};
        
        // Get all form inputs
        const inputs = document.querySelectorAll('input, select, textarea');
        
        inputs.forEach(input => {
            const name = input.name;
            if (name && name.trim() !== '') {
                if (input.type === 'checkbox' || input.type === 'radio') {
                    if (input.checked) {
                        if (formData[name]) {
                            if (Array.isArray(formData[name])) {
                                formData[name].push(input.value || '');
                            } else {
                                formData[name] = [formData[name], input.value || ''];
                            }
                        } else {
                            formData[name] = input.value || '';
                        }
                    }
                } else if (input.type === 'file') {
                    // Skip file inputs for preview
                    return;
                } else if (input.type === 'hidden' && input.name === '_wpnonce') {
                    // Skip nonce fields
                    return;
                } else {
                    // Handle all other input types
                    const value = input.value || '';
                    
                    // Handle array-style names like spins[1][spin_label]
                    if (name.includes('[') && name.includes(']')) {
                        // Parse array notation
                        const parts = name.match(/(\w+)\[([^\]]+)\](?:\[([^\]]+)\])?/);
                        if (parts) {
                            const mainKey = parts[1];
                            const subKey = parts[2];
                            const subSubKey = parts[3];
                            
                            if (!formData[mainKey]) {
                                formData[mainKey] = {};
                            }
                            
                            if (subSubKey) {
                                if (!formData[mainKey][subKey]) {
                                    formData[mainKey][subKey] = {};
                                }
                                formData[mainKey][subKey][subSubKey] = value;
                            } else {
                                formData[mainKey][subKey] = value;
                            }
                        } else {
                            formData[name] = value;
                        }
                    } else {
                        formData[name] = value;
                    }
                }
            }
        });
        
        return formData;
    }
    
    function cleanFormDataForJSON(data) {
        const cleaned = {};
        
        for (const [key, value] of Object.entries(data)) {
            if (value === null || value === undefined) {
                continue;
            }
            
            // Preserve data URLs for custom center image without aggressive cleaning
            if (key === 'custom_wheel_center_image_icon_data') {
                cleaned[key] = value;
                continue;
            }

            if (typeof value === 'object' && !Array.isArray(value)) {
                // Skip objects that aren't arrays
                continue;
            }
            
            if (typeof value === 'string') {
                // Aggressively clean string values
                let cleanValue = value
                    .replace(/[\r\n\t]/g, ' ')  // Replace line breaks and tabs
                    .replace(/\s+/g, ' ')       // Replace multiple spaces with single space
                    .replace(/[^\x20-\x7E]/g, '') // Remove non-ASCII characters except basic printable
                    .trim();
                
                // Only add if not empty
                if (cleanValue.length > 0) {
                    cleaned[key] = cleanValue;
                }
            } else if (Array.isArray(value)) {
                // Clean array values
                const cleanArray = value
                    .map(item => {
                        if (typeof item === 'string') {
                            return item
                                .replace(/[\r\n\t]/g, ' ')
                                .replace(/\s+/g, ' ')
                                .replace(/[^\x20-\x7E]/g, '')
                                .trim();
                        }
                        return item;
                    })
                    .filter(item => item !== null && item !== undefined && item !== '');
                
                if (cleanArray.length > 0) {
                    cleaned[key] = cleanArray;
                }
            } else {
                cleaned[key] = value;
            }
        }
        
        return cleaned;
    }
    
});
