/**
 * Wuclean Common JavaScript - Shared Utility Functions
 * 
 * This file contains reusable JavaScript functionality used across all cleanup pages
 * (products, images, orders, users) for consistency and maintainability.
 */

const ptWucleanCommon = window.pt_wuclean_common_vars || {};

function ptWucleanFormat(template) {
    var args = Array.prototype.slice.call(arguments, 1);
    return args.reduce(function(result, value) {
        return result.replace(/%[sd]/, value);
    }, template);
}

function ptWucleanGetString(key, fallback) {
    return Object.prototype.hasOwnProperty.call(ptWucleanCommon, key) ? ptWucleanCommon[key] : fallback;
}

/**
 * Admin / AJAX output rules (Wuclean):
 * - Strings from wp_send_json_* are plain text in the DOM unless documented as HTML
 *   that was sanitized with wp_kses_post() on the server.
 * - Prefer .text(), ptWucleanInsertPlainTextNoticeBefore(), or escape then assign HTML.
 * - Use ptWucleanSetKsesTrustedNoticeHtml() only for that server-side wp_kses_post HTML.
 *
 * @param {*} str Raw value.
 * @return {string}
 */
function ptWucleanEscapeHtml(str) {
    str = (str === null || str === undefined) ? '' : String(str);
    return str
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#039;');
}

/**
 * Normalize wp_send_json_success / wp_send_json_error `data` to a string for safe .text() / alert().
 *
 * @param {*} data response.data
 * @param {string} fallback
 * @return {string}
 */
function ptWucleanCoerceAjaxMessage(data, fallback) {
    if (data === null || typeof data === 'undefined') {
        return fallback;
    }
    if (typeof data === 'string') {
        return data;
    }
    if (typeof data === 'object' && data !== null) {
        if (typeof data.message === 'string') {
            return data.message;
        }
        if (data.message !== null && typeof data.message !== 'undefined') {
            return String(data.message);
        }
    }
    return fallback;
}

/**
 * Insert an admin notice whose body is plain text (e.g. localized strings only).
 *
 * @param {jQuery} $anchorEl insertBefore target
 * @param {string} progressDivIdSelector e.g. '#pt-search-progress'
 * @param {string} noticeClass e.g. 'notice-success'
 * @param {string} plainText
 * @return {void}
 */
function ptWucleanInsertPlainTextNoticeBefore($anchorEl, progressDivIdSelector, noticeClass, plainText) {
    var id = progressDivIdSelector.replace(/^#/, '') + '-success-message';
    var $notice = jQuery('<div>', { id: id, class: 'notice ' + noticeClass });
    $notice.append(jQuery('<p>').text(plainText));
    $notice.insertBefore($anchorEl);
}

/**
 * Set container HTML that was produced with wp_kses_post() on the server only.
 *
 * @param {jQuery} $container
 * @param {string} html
 * @return {void}
 */
function ptWucleanSetKsesTrustedNoticeHtml($container, html) {
    $container.empty().html(html).show();
}

window.ptWucleanEscapeHtml = ptWucleanEscapeHtml;
window.ptWucleanCoerceAjaxMessage = ptWucleanCoerceAjaxMessage;
window.ptWucleanInsertPlainTextNoticeBefore = ptWucleanInsertPlainTextNoticeBefore;
window.ptWucleanSetKsesTrustedNoticeHtml = ptWucleanSetKsesTrustedNoticeHtml;

// High-performance search progress handler
function initSearchProgress(config) {
    const {
        startButtonId,
        stopButtonId,
        progressDivId,
        progressBarId,
        progressTextId,
        ajaxAction,
        ajaxNonce,
        successMessage,
        redirectUrl,
        otherButtonSelectors,
        maxPolls = 300,
        pollInterval = 1000,
        useBatchProcessing = false  // New parameter for batch-by-batch processing
    } = config;

    // Match clear AJAX action + nonce to the scan that was started (avoid clearing wrong module progress).
    const clearProgressActions = {
        pt_wuclean_start_product_search: "pt_wuclean_clear_search_progress",
        pt_wuclean_start_orphaned_search: "pt_wuclean_clear_orphaned_search_progress",
        pt_wuclean_start_unused_attributes_search: "pt_wuclean_clear_unused_attributes_search_progress",
        pt_wuclean_start_order_search: "pt_wuclean_clear_order_scan_progress",
        pt_wuclean_start_orphaned_meta_scan: "pt_wuclean_clear_orphaned_meta_scan_progress",
        pt_wuclean_start_user_search: "pt_wuclean_clear_user_scan_progress",
        pt_wuclean_start_orphaned_customer_search: "pt_wuclean_clear_orphaned_customer_scan_progress"
    };
    const clearProgressAction = Object.prototype.hasOwnProperty.call(clearProgressActions, ajaxAction)
        ? clearProgressActions[ajaxAction]
        : "pt_wuclean_clear_search_progress";
    
    // Helper function to check if there are any results
    function checkForResults(progress) {
        // Check for product issues
        if (progress.issues_found !== undefined) {
            const newIssues = (progress.issues_found || 0) > 0;
            // Also check stored data count (may include issues from previous scans)
            const storedDataCount = (progress.stored_data_count || 0) > 0;
            return newIssues || storedDataCount;
        }
        
        // Check for orphaned data (products)
        if (progress.orphaned_meta_found !== undefined || progress.orphaned_variations_found !== undefined) {
            const orphanedMeta = (progress.orphaned_meta_found || 0) > 0;
            const orphanedVariations = (progress.orphaned_variations_found || 0) > 0;
            const orphanedComments = (progress.orphaned_comments_found || 0) > 0;
            const orphanedRelationships = (progress.orphaned_relationships_found || 0) > 0;
            const unusedTags = (progress.unused_tags_found || 0) > 0;
            const hasNewResults = orphanedMeta || orphanedVariations || orphanedComments || orphanedRelationships || unusedTags;
            
            // Also check stored data count (may include items from previous scans)
            const storedDataCount = (progress.stored_data_count || 0) > 0;
            
            return hasNewResults || storedDataCount;
        }
        
        // Check for unused attributes (products)
        if (progress.unused_attributes_found !== undefined) {
            const newAttributes = (progress.unused_attributes_found || 0) > 0;
            // Also check stored data count (may include attributes from previous scans)
            const storedDataCount = (progress.stored_data_count || 0) > 0;
            return newAttributes || storedDataCount;
        }
        
        // Check for flagged orders/users
        if (progress.flagged_count !== undefined) {
            const newFlags = (progress.flagged_count || 0) > 0;
            // Also check stored flagged count (may include orders/users from previous scans)
            const storedFlags = (progress.stored_flagged_count || 0) > 0;
            return newFlags || storedFlags;
        }
        
        // Check for orphaned order meta / orphaned customer data (uses total_found)
        if (progress.total_found !== undefined) {
            const totalFound = (progress.total_found || 0) > 0;
            // Also check stored_data_count for consistency (may include items from previous scans)
            const storedDataCount = (progress.stored_data_count || 0) > 0;
            return totalFound || storedDataCount;
        }
        
        // Default: assume there might be results if we can't determine
        return true;
    }
    
    let progressInterval;
    let pollCount = 0;
    let stopRequested = false;  // Flag to prevent race conditions
    
    // Cache DOM elements for performance
    const startButton = jQuery(startButtonId);
    const stopButton = jQuery(stopButtonId);
    const progressDiv = jQuery(progressDivId);
    const progressBar = jQuery(progressBarId);
    const progressText = jQuery(progressTextId);
    const otherButtons = otherButtonSelectors ? jQuery(otherButtonSelectors) : null;
    
    // Store original button text
    const originalButtonText = startButton.text() || ptWucleanGetString('searchNow', 'Search Now');
    
    // Start button functionality
    startButton.on("click", function() {
        // Reset counters and flags
        pollCount = 0;
        stopRequested = false;
        
        // Disable start button, enable and show stop button, and show progress
        startButton.prop("disabled", true).text(ptWucleanGetString('starting', 'Starting...'));
        stopButton.prop("disabled", false).text(ptWucleanGetString('stopScan', 'Stop Scan')).show();  // Reset stop button to enabled state
        progressDiv.show();
        progressBar.css("width", "0%").css("background", "#0073aa");
        progressText.text(ptWucleanGetString('initializingSearch', 'Initializing search...'));
        
        // Disable other search buttons
        if (otherButtons) {
            otherButtons.prop("disabled", true).addClass("disabled");
        }
        
        // Clear any existing messages
        jQuery(progressDivId + "-success-message, " + progressDivId + "-error-message").remove();
        
        // Start the search
        jQuery.ajax({
            url: ajaxurl,
            type: "POST",
            data: {
                action: ajaxAction,
                nonce: ajaxNonce
            },
            timeout: 30000,
            success: function(response) {
                if (response.success) {
                    // Check if we should use batch processing
                    if (useBatchProcessing) {
                        // Start batch-by-batch processing
                        processBatch();
                    } else {
                        // Start polling for progress (for background processes)
                        startProgressPolling();
                    }
                } else {
                    startButton.prop("disabled", false).text(originalButtonText);
                    stopButton.prop("disabled", false).hide();
                    progressText.text(ptWucleanGetString('errorStartingSearch', 'Error starting search.'));
                    progressBar.css("background", "#dc3232");
                    enableOtherButtons();
                }
            },
            error: function() {
                startButton.prop("disabled", false).text(originalButtonText);
                stopButton.prop("disabled", false).hide();
                progressText.text(ptWucleanGetString('errorStartingSearch', 'Error starting search.'));
                progressBar.css("background", "#dc3232");
                enableOtherButtons();
            }
        });
    });
    
    // Function to process batches one at a time
    function processBatch() {
        // Derive batch action from the start action
        // Examples: pt_start_XXX_search -> pt_process_XXX_batch
        const batchAction = ajaxAction.replace("start", "process").replace("search", "batch");
        
        jQuery.ajax({
            url: ajaxurl,
            type: "POST",
            data: {
                action: batchAction,
                nonce: ajaxNonce
            },
            timeout: 60000,  // 60 seconds for batch processing
            success: function(response) {
                if (response.success) {
                    const progress = response.data.progress || {};
                    
                    // Check if stop was requested or status is stopped
                    if (stopRequested || progress.status === 'stopped') {
                        startButton.prop("disabled", false).text(originalButtonText);
                        stopButton.prop("disabled", false).hide();
                        progressText.text(ptWucleanGetString('searchStoppedByUser', 'Search stopped by user.'));
                        progressBar.css("background", "#dc3232");
                        enableOtherButtons();
                        
                        // Clear progress data
                        jQuery.ajax({
                            url: ajaxurl,
                            type: "POST",
                            data: {
                                action: clearProgressAction,
                                nonce: ajaxNonce
                            },
                            timeout: 5000
                        });
                        return;
                    }
                    
                    // Update progress display
                    const totalItems = progress.total_items || 0;
                    const processed = progress.processed || 0;
                    
                    // Calculate percentage based on search type
                    let percent = 0;
                    
                    if (progress.current_step) {
                        // For multi-step searches (orphaned data), combine step progress with item progress
                        const steps = ['postmeta', 'variations', 'comments', 'term_relationships', 'tags', 'attributes', 'complete'];
                        const stepIndex = steps.indexOf(progress.current_step);
                        
                        // Base progress from which step we're on (14% per step)
                        const stepProgress = stepIndex >= 0 ? (stepIndex / steps.length) : 0;
                        
                        // Add micro-progress based on processed items within the step
                        // This gives smooth incremental progress even within a single step
                        const itemsInStep = progress.processed || 0;
                        const microProgress = itemsInStep > 0 ? Math.min(0.14, (itemsInStep / 1000) * 0.14) : 0;
                        
                        // Always show at least 1% when running to indicate activity
                        percent = Math.max(1, Math.round((stepProgress + microProgress) * 100));
                    } else if (progress.current_taxonomy_index !== undefined && progress.total_taxonomies > 0) {
                        // For taxonomy-based searches (unused attributes), show taxonomy progress
                        percent = Math.round((progress.current_taxonomy_index / progress.total_taxonomies) * 100);
                    } else if (totalItems > 0) {
                        // For simple item-based searches (products), use processed/total
                        percent = Math.round((processed / totalItems) * 100);
                    }
                    
                    // Clamp to avoid visual overflow past container width.
                    if ( !Number.isFinite( percent ) ) {
                        percent = 0;
                    }
                    percent = Math.min( 99, Math.max( 0, percent ) );
                    progressBar.css("width", percent + "%");
                    const statusText = progress.message || response.data.message || ptWucleanGetString('processing', 'Processing...');
                    progressText.text(statusText);
                    
                    // Check if completed
                    if (response.data.completed || progress.status === 'completed') {
                        startButton.prop("disabled", false).text(originalButtonText);
                        stopButton.prop("disabled", false).hide();
                        progressBar.css("background", "#46b450").css("width", "100%");
                        
                        enableOtherButtons();
                        
                        // Always redirect to the tab after search completes (user expects to see results tab)
                        // Check if there are any results for messaging purposes
                        const hasResults = checkForResults(progress);
                        
                        if (hasResults) {
                            progressText.text(ptWucleanGetString('searchCompletedRedirecting', 'Search completed! Redirecting...'));
                            
                            // Show success message
                            if (!jQuery(progressDivId + "-success-message").length) {
                                const message = successMessage(progress);
                                ptWucleanInsertPlainTextNoticeBefore(progressDiv, progressDivId, 'notice-success', message);
                            }
                        } else {
                            // No results found - still redirect but show different message
                            progressText.text(ptWucleanGetString('searchCompletedRedirecting', 'Search completed! Redirecting...'));
                            
                            // Show success message indicating no results
                            if (!jQuery(progressDivId + "-success-message").length) {
                                const message = successMessage(progress) + ' ' + ptWucleanGetString('noResultsFound', 'No results found.');
                                ptWucleanInsertPlainTextNoticeBefore(progressDiv, progressDivId, 'notice-info', message);
                            }
                        }
                        
                        // Clear progress data
                        jQuery.ajax({
                            url: ajaxurl,
                            type: "POST",
                            data: {
                                action: clearProgressAction,
                                nonce: ajaxNonce
                            },
                            timeout: 5000
                        });
                        
                        // Always redirect after countdown (user expects to see the tab they searched from)
                        if (redirectUrl) {
                            let countdown = 3;
                            const countdownInterval = setInterval(function() {
                                var countdownTemplate = countdown === 1
                                    ? ptWucleanGetString('redirectCountdownSingular', 'Redirecting in %d second...')
                                    : ptWucleanGetString('redirectCountdownPlural', 'Redirecting in %d seconds...');
                                progressText.text(ptWucleanFormat(countdownTemplate, countdown));
                                countdown--;
                                if (countdown < 0) {
                                    clearInterval(countdownInterval);
                                    setTimeout(function() {
                                        if (redirectUrl) {
                                            window.location.href = redirectUrl;
                                        }
                                    }, 100);
                                }
                            }, 1000);
                        }
                    } else {
                        // Check if stop was requested before processing next batch
                        if (stopRequested) {
                    startButton.prop("disabled", false).text(originalButtonText);
                    stopButton.prop("disabled", false).hide();
                    progressText.text(ptWucleanGetString('searchStoppedByUser', 'Search stopped by user.'));
                            progressBar.css("background", "#dc3232");
                            enableOtherButtons();
                            return;
                        }
                        
                        // Process next batch after a small delay
                        // This makes progress more visible and reduces server load
                        setTimeout(function() {
                            // Double-check stop wasn't requested during the delay
                            if (!stopRequested) {
                                processBatch();
                            }
                        }, 300);  // 300ms delay between batches
                    }
                } else {
                    // Check if error is because stop was requested
                    if (stopRequested) {
                        startButton.prop("disabled", false).text(originalButtonText);
                        stopButton.prop("disabled", false).hide();
                        progressText.text(ptWucleanGetString('searchStoppedByUser', 'Search stopped by user.'));
                        progressBar.css("background", "#dc3232");
                        enableOtherButtons();
                    } else {
                        startButton.prop("disabled", false).text(originalButtonText);
                        stopButton.prop("disabled", false).hide();
                        var batchErrorMessage = response.data ? response.data.message : ptWucleanGetString('unknownError', 'Unknown error');
                        progressText.text(ptWucleanFormat(ptWucleanGetString('errorProcessingBatchWithMessage', 'Error processing batch: %s'), batchErrorMessage));
                        progressBar.css("background", "#dc3232");
                        enableOtherButtons();
                    }
                }
            },
            error: function() {
                // Check if error is because stop was requested
                if (stopRequested) {
                    startButton.prop("disabled", false).text(originalButtonText);
                    stopButton.prop("disabled", false).hide();
                    progressText.text(ptWucleanGetString('searchStoppedByUser', 'Search stopped by user.'));
                    progressBar.css("background", "#dc3232");
                    enableOtherButtons();
                } else {
                    startButton.prop("disabled", false).text(originalButtonText);
                    stopButton.prop("disabled", false).hide();
                    progressText.text(ptWucleanGetString('errorProcessingBatch', 'Error processing batch.'));
                    progressBar.css("background", "#dc3232");
                    enableOtherButtons();
                }
            }
        });
    }
    
    // Function to start progress polling (for background processes)
    function startProgressPolling() {
                    progressInterval = setInterval(function() {
                        pollCount++;
                        
                        // Check timeout
                        if (pollCount > maxPolls) {
                            clearInterval(progressInterval);
                            startButton.prop("disabled", false).text(originalButtonText);
                            stopButton.prop("disabled", false).hide();
                            progressText.text(ptWucleanGetString('searchTimedOut', 'Search timed out after 5 minutes. Please try again.'));
                            progressBar.css("background", "#dc3232");
                            enableOtherButtons();
                            return;
                        }
                        
                        // Poll for progress
                        jQuery.ajax({
                            url: ajaxurl,
                            type: "POST",
                            data: {
                                action: ajaxAction.replace("start", "get") + "_progress",
                                nonce: ajaxNonce
                            },
                            timeout: 30000,
                            success: function(progressResponse) {
                                if (progressResponse.success) {
                                    const progress = progressResponse.data;
                                    
                                        const totalItems = progress.total_items || 0;
                                        let percent = 0;
                                        
                                        // Calculate percentage based on search type
                                        if (totalItems > 0) {
                                            percent = Math.round((progress.processed / totalItems) * 100);
                                        } else if (progress.percentage !== undefined) {
                                            // Some searches provide percentage directly
                                            percent = Math.round(progress.percentage);
                                        } else if (progress.status === 'completed') {
                                            // If completed but no progress data, show 100%
                                            percent = 100;
                                        }
                                        
                                        // Always show at least 1% when running to indicate activity
                                        if (progress.status === 'running' && percent === 0) {
                                            percent = 1;
                                        }
                                        
                                        // Clamp to avoid visual overflow past container width.
                                        if ( !Number.isFinite( percent ) ) {
                                            percent = 0;
                                        }
                                        percent = Math.min( 99, Math.max( 0, percent ) );
                                        // Update progress bar (minimal DOM manipulation)
                                        progressBar.css("width", percent + "%");
                                        
                                        // Update status text (use server message if available)
                                        const statusText = progress.message || getDefaultStatusText(progress);
                                        progressText.text(statusText.length > 100 ? statusText.substring(0, 97) + "..." : statusText);
                                    
                                    if (progress.status === "completed") {
                                        clearInterval(progressInterval);
                                        startButton.prop("disabled", false).text(originalButtonText);
                                        stopButton.prop("disabled", false).hide();
                                        progressBar.css("background", "#46b450");
                                        
                                        enableOtherButtons();
                                        
                                        // Always redirect to the tab after search completes (user expects to see results tab)
                                        // Check if there are any results for messaging purposes
                                        const hasResults = checkForResults(progress);
                                        
                                        if (hasResults) {
                                            progressText.text(ptWucleanGetString('searchCompletedRedirecting', 'Search completed! Redirecting...'));
                                            
                                            // Show success message
                                            if (!jQuery(progressDivId + "-success-message").length) {
                                                const message = successMessage(progress);
                                                ptWucleanInsertPlainTextNoticeBefore(progressDiv, progressDivId, 'notice-success', message);
                                            }
                                        } else {
                                            // No results found - still redirect but show different message
                                            progressText.text(ptWucleanGetString('searchCompletedRedirecting', 'Search completed! Redirecting...'));
                                            
                                            // Show success message indicating no results
                                            if (!jQuery(progressDivId + "-success-message").length) {
                                                const message = successMessage(progress) + ' ' + ptWucleanGetString('noResultsFound', 'No results found.');
                                                ptWucleanInsertPlainTextNoticeBefore(progressDiv, progressDivId, 'notice-info', message);
                                            }
                                        }
                                        
                                        // Clear progress data
                                        jQuery.ajax({
                                            url: ajaxurl,
                                            type: "POST",
                                            data: {
                                                action: clearProgressAction,
                                                nonce: ajaxNonce
                                            },
                                            timeout: 5000
                                        });
                                        
                                        // Always redirect after countdown (user expects to see the tab they searched from)
                                        if (redirectUrl) {
                                            let countdown = 3;
                                            const countdownInterval = setInterval(function() {
                                                var countdownTemplate = countdown === 1
                                                    ? ptWucleanGetString('redirectCountdownSingular', 'Redirecting in %d second...')
                                                    : ptWucleanGetString('redirectCountdownPlural', 'Redirecting in %d seconds...');
                                                progressText.text(ptWucleanFormat(countdownTemplate, countdown));
                                                countdown--;
                                                if (countdown < 0) {
                                                    clearInterval(countdownInterval);
                                                    setTimeout(function() {
                                                        if (redirectUrl) {
                                                            window.location.href = redirectUrl;
                                                        }
                                                    }, 100);
                                                }
                                            }, 1000);
                                        }
                                    }
                                }
                            },
                            error: function() {
                                clearInterval(progressInterval);
                                startButton.prop("disabled", false).text(originalButtonText);
                                stopButton.prop("disabled", false).hide();
                                progressText.text(ptWucleanGetString('errorCheckingProgress', 'Error checking progress.'));
                                progressBar.css("background", "#dc3232");
                                enableOtherButtons();
                            }
                        });
                    }, pollInterval);
    }
    
    // Stop button functionality
    stopButton.on("click", function() {
        // Set flag immediately to prevent race conditions
        stopRequested = true;
        
        // Update UI immediately
        stopButton.prop("disabled", true).text(ptWucleanGetString('stopping', 'Stopping...'));
        
        // Clear the interval
        if (progressInterval) {
            clearInterval(progressInterval);
        }
        
        // Derive stop action from the start action
        // Examples: pt_start_XXX_search -> pt_stop_XXX_search
        const stopAction = ajaxAction.replace("start", "stop");
        
        // Stop the search via AJAX
        jQuery.ajax({
            url: ajaxurl,
            type: "POST",
            data: {
                action: stopAction,
                nonce: ajaxNonce
            },
            success: function() {
                // Fully reset UI state
                startButton.prop("disabled", false).text(originalButtonText);
                stopButton.prop("disabled", false).hide();
                progressText.text(ptWucleanGetString('searchStoppedByUser', 'Search stopped by user.'));
                progressBar.css("background", "#dc3232");
                enableOtherButtons();
            },
            error: function() {
                // Fully reset UI state even on error
                startButton.prop("disabled", false).text(originalButtonText);
                stopButton.prop("disabled", false).hide();
                progressText.text(ptWucleanGetString('errorStoppingSearch', 'Error stopping search.'));
                progressBar.css("background", "#dc3232");
                enableOtherButtons();
            }
        });
    });
    
    // Helper function to enable other buttons
    function enableOtherButtons() {
        if (otherButtons) {
            otherButtons.prop("disabled", false).removeClass("disabled");
        }
    }
    
    // Helper function to get default status text (generic across all sections)
    function getDefaultStatusText(progress) {
        if (progress.issues_found !== undefined) {
            const totalItems = progress.total_items || 0;
            return ptWucleanFormat(
                ptWucleanGetString('processedItemsStatus', 'Processed %1$d / %2$d items. Issues: %3$d (%4$d/%5$d batches)'),
                progress.processed || 0,
                totalItems,
                progress.issues_found || 0,
                progress.current_batch || 0,
                progress.total_batches || 0
            );
        } else if (progress.orphaned_meta_found !== undefined) {
            return ptWucleanFormat(
                ptWucleanGetString('foundOrphanedMetaStatus', 'Found %1$d orphaned meta records and %2$d orphaned variations'),
                progress.orphaned_meta_found || 0,
                progress.orphaned_variations_found || 0
            );
        } else if (progress.unused_attributes_found !== undefined) {
            return ptWucleanFormat(
                ptWucleanGetString('foundUnusedAttributesStatus', 'Found %d unused attributes'),
                progress.unused_attributes_found || 0
            );
        }
        return ptWucleanGetString('processing', 'Processing...');
    }
}

// Form confirmation handler - replaces inline onclick confirm dialogs
(function($) {
    // Track which button was clicked
    var clickedSubmitButton = null;
    
    // Capture button click before form submission
    $(document).on('click', 'button[type="submit"][data-confirm-message]', function(e) {
        clickedSubmitButton = $(this);
    });
    
    // Handle form submission with confirmation
    $(document).on('submit', 'form', function(e) {
        if (clickedSubmitButton && clickedSubmitButton.length) {
            var confirmMessage = clickedSubmitButton.data('confirm-message');
            if (confirmMessage && !confirm(confirmMessage)) {
                e.preventDefault();
                clickedSubmitButton = null; // Reset
                return false;
            }
            clickedSubmitButton = null; // Reset after check
        }
    });
    
    // Handle page jump button clicks
    $(document).on('click', '.pt-wuclean-page-jump-btn', function(e) {
        e.preventDefault();
        var $button = $(this);
        var baseUrl = $button.data('base-url');
        var pageParam = $button.data('page-param');
        var maxPages = parseInt($button.data('max-pages'));
        var inputId = $button.data('input-id');
        var pageNum = parseInt($('#' + inputId).val());
        
        if (isNaN(pageNum) || pageNum < 1 || pageNum > maxPages) {
            alert('Please enter a valid page number between 1 and ' + maxPages);
            return;
        }
        
        // Properly build URL preserving all existing query parameters (including nonce)
        // Use current page origin as base for relative URLs, or use baseUrl directly if absolute
        var url = new URL(baseUrl, window.location.href);
        url.searchParams.set(pageParam, pageNum);
        window.location.href = url.href;
    });
})(jQuery);

// High-performance bulk selection handler
function initBulkSelection(config) {
    const { 
        selectAllId, 
        checkboxesSelector, 
        selectAllButtonId, 
        deselectAllButtonId, 
        selectedCountId 
    } = config;
    
    const selectAllCheckbox = document.getElementById(selectAllId);
    const checkboxes = document.querySelectorAll(checkboxesSelector);
    const selectAllButton = document.getElementById(selectAllButtonId);
    const deselectAllButton = document.getElementById(deselectAllButtonId);
    const selectedCountSpan = document.getElementById(selectedCountId);
    
    // Select All button functionality
    if (selectAllButton) {
        selectAllButton.addEventListener("click", function() {
            checkboxes.forEach(function(checkbox) {
                checkbox.checked = true;
            });
            if (selectAllCheckbox) {
                selectAllCheckbox.checked = true;
            }
            updateSelectedCount();
        });
    }
    
    // Deselect All button functionality
    if (deselectAllButton) {
        deselectAllButton.addEventListener("click", function() {
            checkboxes.forEach(function(checkbox) {
                checkbox.checked = false;
            });
            if (selectAllCheckbox) {
                selectAllCheckbox.checked = false;
            }
            updateSelectedCount();
        });
    }
    
    // Select All checkbox functionality
    if (selectAllCheckbox) {
        selectAllCheckbox.addEventListener("change", function() {
            checkboxes.forEach(function(checkbox) {
                checkbox.checked = selectAllCheckbox.checked;
            });
            updateSelectedCount();
        });
    }
    
    // Individual checkbox change tracking
    checkboxes.forEach(function(checkbox) {
        checkbox.addEventListener("change", function() {
            updateSelectedCount();
            updateSelectAllCheckbox();
        });
    });
    
    // Update selected count display
    function updateSelectedCount() {
        var selectedCount = 0;
        checkboxes.forEach(function(checkbox) {
            if (checkbox.checked) {
                selectedCount++;
            }
        });
        
        if (selectedCountSpan) {
            if (selectedCount > 0) {
                selectedCountSpan.textContent = ptWucleanFormat(
                    ptWucleanGetString('selectedCountText', '%d selected'),
                    selectedCount
                );
            } else {
                selectedCountSpan.textContent = "";
            }
        }
    }
    
    // Update Select All checkbox state
    function updateSelectAllCheckbox() {
        if (selectAllCheckbox) {
            var allChecked = true;
            checkboxes.forEach(function(checkbox) {
                if (!checkbox.checked) {
                    allChecked = false;
                }
            });
            selectAllCheckbox.checked = allChecked;
        }
    }
    
    // Initialize selected count
    updateSelectedCount();
}

// Utility function for page refresh after delay
function refreshPageAfterDelay(delay) {
    setTimeout(function(){ location.reload(); }, delay);
}

// Common AJAX handler for cleanup operations
function initCleanupButton(buttonId, ajaxAction, nonce, confirmMessage, successMessage, errorMessage) {
    const button = document.getElementById(buttonId);
    if (!button) return;
    
    button.addEventListener("click", function() {
        if (confirm(confirmMessage)) {
            this.disabled = true;
            this.value = ptWucleanGetString('running', 'Running...');
            
            // Create form data
            const formData = new FormData();
            formData.append("action", ajaxAction);
            formData.append("nonce", nonce);
            
            fetch(ajaxurl, {
                method: "POST",
                body: formData
            })
            .then(response => {
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                return response.json();
            })
            .then(data => {
                if (data.success) {
                    alert(successMessage(data.data));
                } else {
                    const errText = typeof ptWucleanCoerceAjaxMessage === 'function'
                        ? ptWucleanCoerceAjaxMessage(data.data, '')
                        : (typeof data.data === 'string' ? data.data : '');
                    alert(errorMessage + " " + (errText || ptWucleanGetString('unknownError', 'Unknown error')));
                }
            })
            .catch(error => {
                console.error("Fetch error:", error);
                alert(errorMessage + " " + ptWucleanGetString('consoleDetails', 'Please check the console for details.'));
            })
            .finally(() => {
                this.disabled = false;
                this.value = ptWucleanGetString('runSingleBatch', 'Run Single Batch');
            });
        }
    });
}
