/**
 * WUClean Image Health Scanner - JavaScript
 * Phase 1: Minimal Viable Scanner
 */

// Ensure shared helper exists even if the common script fails to load.
if (typeof window.ptWucleanGetString !== 'function') {
    window.ptWucleanGetString = function(key, fallback) {
        var sharedStrings = window.pt_wuclean_common_vars || {};
        return Object.prototype.hasOwnProperty.call(sharedStrings, key) ? sharedStrings[key] : fallback;
    };
}

jQuery(document).ready(function($) {
    // ========================================================================
    // HELPER FUNCTIONS
    // ========================================================================
    var imageStrings = window.pt_wuclean_images_vars || {};

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

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

    function replaceIndexedPlaceholders(template, values) {
        // Replace both %d (numeric) and %s (string) placeholders
        // First replace %s placeholders (strings)
        template = template.replace(/%(\d+)\$s/g, function(match, index) {
            var value = values[parseInt(index, 10) - 1];
            return typeof value !== "undefined" ? value : match;
        });
        // Then replace %d placeholders (numbers)
        return template.replace(/%(\d+)\$d/g, function(match, index) {
            var value = values[parseInt(index, 10) - 1];
            return typeof value !== "undefined" ? value : match;
        });
    }

    /**
     * Normalize wp_send_json_success/error payload `data` to a plain string for safe .text() display.
     *
     * @param {*} data
     * @param {string} fallback
     * @return {string}
     */
    function ptWucleanCoerceAjaxMessage(data, fallback) {
        if (typeof window !== 'undefined' && typeof window.ptWucleanCoerceAjaxMessage === 'function') {
            return window.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;
    }

    /**
     * Escape text for safe insertion into HTML (canonical implementation: assets/js/common.js).
     *
     * @param {*} str
     * @return {string}
     */
    function ptWucleanEscapeHtml(str) {
        if (typeof window !== 'undefined' && typeof window.ptWucleanEscapeHtml === 'function') {
            return window.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;');
    }
    
    // Update pagination count after deleting items
    function updatePaginationCount(itemsDeleted) {
        if (!itemsDeleted) {
            return;
        }
        $('.pt-wuclean-pagination').each(function() {
            var $el = $(this);
            var template = $el.data('template');
            var start = parseInt($el.data('start'), 10) || 0;
            var end = parseInt($el.data('end'), 10) || 0;
            var total = parseInt($el.data('total'), 10) || 0;

            var newEnd = Math.max(start, end - itemsDeleted);
            var newTotal = Math.max(0, total - itemsDeleted);

            $el.data('end', newEnd);
            $el.data('total', newTotal);

            if (template) {
                $el.text(replaceIndexedPlaceholders(template, [start, newEnd, newTotal]));
            }
        });
    }

    /**
     * Parent basenames that may appear on orphan rows (WebP/AVIF) for this Media Library file.
     * Siblings of the big-image original use data-parent-filename "img.jpg" while ML row uses "img-scaled.jpg".
     *
     * @param {string} mediaBasename data-filename from the Media Library row.
     * @return {string[]}
     */
    function ptWucleanMediaRelatedParentFilenames(mediaBasename) {
        var names = [];
        if (mediaBasename && typeof mediaBasename === 'string') {
            names.push(mediaBasename);
            var m = mediaBasename.match(/^(.*)-scaled(\.[^.]+)$/i);
            if (m && m[1] && m[2]) {
                names.push(m[1] + m[2]);
            }
        }
        var seen = {};
        return names.filter(function(n) {
            if (!n || seen[n]) {
                return false;
            }
            seen[n] = true;
            return true;
        });
    }

    /**
     * Remove tbody rows whose data-parent-filename is in the given list (scoped to one table).
     *
     * @param {jQuery} $table Closest results table.
     * @param {string[]} parentFilenames
     * @return {number} Rows removed.
     */
    function ptWucleanRemoveRowsByParentFilenames($table, parentFilenames) {
        if (!$table || !$table.length || !parentFilenames || !parentFilenames.length) {
            return 0;
        }
        var set = {};
        parentFilenames.forEach(function(p) {
            if (p) {
                set[p] = true;
            }
        });
        var $rows = $table.find('tbody tr').filter(function() {
            var pf = $(this).attr('data-parent-filename');
            return pf && Object.prototype.hasOwnProperty.call(set, pf);
        });
        var n = $rows.length;
        $rows.remove();
        return n;
    }

    /**
     * Basenames of WebP/AVIF files the plugin may have moved with this attachment (replaced + appended patterns).
     *
     * @param {string} mediaBasename e.g. aaagiant-scaled.jpg
     * @return {string[]}
     */
    function ptWucleanSidecarFilenamesForMediaBasename(mediaBasename) {
        var names = [];
        function addForBase(bn) {
            if (!bn || typeof bn !== 'string') {
                return;
            }
            var lastDot = bn.lastIndexOf('.');
            if (lastDot < 1) {
                return;
            }
            var stem = bn.substring(0, lastDot);
            ['webp', 'avif'].forEach(function(fmt) {
                names.push(stem + '.' + fmt);
                names.push(bn + '.' + fmt);
            });
        }
        addForBase(mediaBasename);
        var m = mediaBasename.match(/^(.*)-scaled(\.[^.]+)$/i);
        if (m && m[1] && m[2]) {
            addForBase(m[1] + m[2]);
        }
        var seen = {};
        return names.filter(function(n) {
            if (!n || seen[n]) {
                return false;
            }
            seen[n] = true;
            return true;
        });
    }

    /**
     * Remove rows (typically orphaned_file) whose data-filename is in the list.
     *
     * @param {jQuery} $table
     * @param {string[]} filenames
     * @return {number}
     */
    function ptWucleanRemoveRowsByDataFilenames($table, filenames) {
        if (!$table || !$table.length || !filenames || !filenames.length) {
            return 0;
        }
        var set = {};
        filenames.forEach(function(f) {
            if (f) {
                set[f] = true;
            }
        });
        var $rows = $table.find('tbody tr').filter(function() {
            var fn = $(this).attr('data-filename');
            return fn && Object.prototype.hasOwnProperty.call(set, fn);
        });
        var n = $rows.length;
        $rows.remove();
        return n;
    }
    
    // ========================================================================
    // SCANNER TAB - Progress Management
    // ========================================================================
    
    var scanInProgress = false;
    var stopRequested = false;
    
    var $quickStartButton = $('#pt-wuclean-start-image-scan-media-only');
    var $startButton = $('#pt-wuclean-start-image-scan');
    var $stopButton = $('#pt-wuclean-stop-image-scan');
    var $resumeButton = $('#pt-wuclean-resume-image-scan');
    var $progressDiv = $('#pt-wuclean-image-scan-progress');
    var $scanSteps = $('#pt-wuclean-image-scan-steps');
    var $scanStepItems = $scanSteps.find('.pt-wuclean-scan-step');
    var $progressBar = $('#pt-wuclean-image-progress-bar');
    var $progressText = $('#pt-wuclean-image-progress-text');
    var $progressDetails = $('#pt-wuclean-image-progress-details');
    var $progressWaiting = $('#pt-wuclean-image-progress-waiting');
    var currentScanScope = 'media_only';
    var scanBatchIndex = 0;

    function ptWucleanIsGatewayTimeout(xhr, status) {
        return status === 'timeout' || xhr.status === 502 || xhr.status === 503 || xhr.status === 504;
    }

    function ptWucleanConfigureScanSteps(scope) {
        currentScanScope = scope || ptWucleanDefaultImageScanScope();
        var isFullScan = currentScanScope === 'media_and_uploads';
        var $uploadsStep = $scanSteps.find('.pt-wuclean-scan-step-uploads');
        $scanSteps.toggleClass('is-two-steps', !isFullScan || !$uploadsStep.length);
        $scanStepItems.removeClass('is-done is-active is-pending');
        if ($uploadsStep.length) {
            $uploadsStep.toggleClass('is-hidden', !isFullScan);
        }
        $scanStepItems.filter('[data-step="media_library"]').addClass('is-active');
        $scanStepItems.not('.is-active').not('.is-hidden').addClass('is-pending');
    }

    function ptWucleanApplyScanStepsFromData(data) {
        if (!data || !data.steps || !data.steps.length) {
            return;
        }
        $scanStepItems.each(function() {
            var $step = $(this);
            var key = $step.data('step');
            var match = null;
            for (var i = 0; i < data.steps.length; i++) {
                if (data.steps[i].key === key) {
                    match = data.steps[i];
                    break;
                }
            }
            if (!match) {
                return;
            }
            $step.removeClass('is-done is-active is-pending');
            if (match.status === 'done') {
                $step.addClass('is-done');
            } else if (match.status === 'active') {
                $step.addClass('is-active');
            } else {
                $step.addClass('is-pending');
            }
        });
    }

    function ptWucleanMarkAllScanStepsDone() {
        $scanStepItems.filter(':visible').addClass('is-done').removeClass('is-active is-pending');
    }

    function ptWucleanApplyScanProgressUI(data) {
        if (!data) {
            return;
        }

        var percentage = parseInt(data.percentage, 10) || 0;
        $progressBar.css({
            'width': percentage + '%',
            'background': '#0073aa'
        });
        $progressText.text('');
        $progressWaiting.hide().empty();

        if (data.steps && data.steps.length) {
            ptWucleanApplyScanStepsFromData(data);
        }

        var message = data.message || imgString('scanning_label', 'Scanning...');
        var detailsHtml = ptWucleanEscapeHtml(message);
        detailsHtml += '<br>' + replaceIndexedPlaceholders(
            imgString('issues_found_template', 'Issues found: <strong>%1$d</strong>'),
            [data.issues_found || 0]
        );
        $progressDetails.html(detailsHtml);
    }

    function ptWucleanShowScanInterruptedUI(message) {
        scanInProgress = false;
        scanBatchIndex = 0;
        $progressWaiting.hide().empty();
        ptWucleanResetScanButtonsLabels();
        $stopButton.prop('disabled', false).text(ptWucleanGetString('stopScan', 'Stop & Reset')).show();
        $resumeButton.prop('disabled', false).text(ptWucleanGetString('resume', 'Resume Scan')).show();
        $progressBar.css('background', '#dc3232');
        $progressText.text(imgString('error_label', 'Error'));
        $progressDetails.text(message);
    }

    // Results-tab filter controls (declared early for scan redirect + session helpers).
    var $filterSafeSiblings = $('#pt-wuclean-filter-safe-siblings');
    var $filterThumbnails = $('#pt-wuclean-filter-thumbnails');
    var $filterJpg = $('#pt-wuclean-filter-jpg');
    var $filterPng = $('#pt-wuclean-filter-png');
    var $filterWebp = $('#pt-wuclean-filter-webp');
    var $filterAvif = $('#pt-wuclean-filter-avif');
    var $filterHideScaledOriginals = $('#pt-wuclean-filter-hide-scaled-originals');

    var PT_WUCLEAN_RESULTS_FILTER_STORAGE_KEY = 'pt_wuclean_image_results_filter_prefs_v1';
    var PT_WUCLEAN_RESULTS_PER_PAGE_ALLOWED = [25, 50, 100, 200];

    function ptWucleanNormalizeResultsPerPage(value) {
        var n = parseInt(value, 10);
        if (PT_WUCLEAN_RESULTS_PER_PAGE_ALLOWED.indexOf(n) !== -1) {
            return n;
        }
        return 25;
    }

    function ptWucleanReadResultsPrefsFromSession() {
        if (typeof sessionStorage === 'undefined') {
            return null;
        }
        try {
            var raw = sessionStorage.getItem(PT_WUCLEAN_RESULTS_FILTER_STORAGE_KEY);
            if (!raw) {
                return null;
            }
            var o = JSON.parse(raw);
            return (o && typeof o === 'object') ? o : null;
        } catch (e) {
            return null;
        }
    }

    function ptWucleanWriteResultsPrefsToSession(prefs) {
        if (typeof sessionStorage === 'undefined' || !prefs || typeof prefs !== 'object') {
            return;
        }
        try {
            sessionStorage.setItem(PT_WUCLEAN_RESULTS_FILTER_STORAGE_KEY, JSON.stringify(prefs));
        } catch (e) {
            // Ignore private mode / quota errors.
        }
    }

    function ptWucleanGetStoredResultsPerPage() {
        var prefs = ptWucleanReadResultsPrefsFromSession();
        if (!prefs || !Object.prototype.hasOwnProperty.call(prefs, 'per_page')) {
            return null;
        }
        return ptWucleanNormalizeResultsPerPage(prefs.per_page);
    }

    function ptWucleanSaveResultsPerPagePreference(perPage) {
        perPage = ptWucleanNormalizeResultsPerPage(perPage);
        var prefs = ptWucleanReadResultsPrefsFromSession() || {};
        prefs.per_page = perPage;
        ptWucleanWriteResultsPrefsToSession(prefs);

        var nonce = imageStrings.save_results_per_page_nonce;
        if (nonce && typeof ajaxurl !== 'undefined') {
            $.ajax({
                url: ajaxurl,
                type: 'POST',
                data: {
                    action: 'pt_wuclean_save_results_per_page',
                    per_page: perPage,
                    nonce: nonce
                }
            });
        }
    }

    /**
     * Apply current results-tab filter UI to a URLSearchParams instance (same keys as server-side).
     *
     * @param {URLSearchParams} searchParams
     * @return {void}
     */
    function ptWucleanResultsUploadsViewsAvailable() {
        return !!(pt_wuclean_images_vars && pt_wuclean_images_vars.results_uploads_views_available);
    }

    function ptWucleanApplyDomToResultsFilterSearchParams(searchParams) {
        var orphanFilter = 'hide_orphaned';
        if (ptWucleanResultsUploadsViewsAvailable()) {
            var $orphanChecked = $('input[name="orphan_filter"]:checked');
            if ($orphanChecked.length) {
                orphanFilter = $orphanChecked.val();
            }
        }
        searchParams.delete('hide_orphaned');
        searchParams.delete('show_orphans_only');
        searchParams.set('orphan_filter', orphanFilter);
        searchParams.delete('show_originals_only');

        if ($filterHideScaledOriginals.length && !$filterHideScaledOriginals.prop('disabled')) {
            if ($filterHideScaledOriginals.is(':checked')) {
                searchParams.set('hide_originals_of_scaled', '1');
            } else {
                searchParams.set('hide_originals_of_scaled', '0');
            }
        } else {
            searchParams.delete('hide_originals_of_scaled');
        }

        if ($filterSafeSiblings.length) {
            if ($filterSafeSiblings.is(':checked')) {
                searchParams.set('hide_safe_siblings', '1');
            } else {
                searchParams.set('hide_safe_siblings', '0');
            }
        } else {
            searchParams.delete('hide_safe_siblings');
        }
        if ($filterThumbnails.length) {
            if ($filterThumbnails.is(':checked')) {
                searchParams.set('hide_thumbnails', '1');
            } else {
                searchParams.set('hide_thumbnails', '0');
            }
        } else {
            searchParams.delete('hide_thumbnails');
        }
        if ($filterJpg.is(':checked')) {
            searchParams.set('hide_jpg', '1');
        } else {
            searchParams.delete('hide_jpg');
        }
        if ($filterPng.is(':checked')) {
            searchParams.set('hide_png', '1');
        } else {
            searchParams.delete('hide_png');
        }
        if ($filterWebp.is(':checked')) {
            searchParams.set('hide_webp', '1');
        } else {
            searchParams.delete('hide_webp');
        }
        if ($filterAvif.is(':checked')) {
            searchParams.set('hide_avif', '1');
        } else {
            searchParams.delete('hide_avif');
        }
    }

    function ptWucleanApplyResultsFilterPrefsFromParams(o, params) {
        var keys = ['orphan_filter', 'hide_originals_of_scaled', 'hide_safe_siblings', 'hide_thumbnails', 'hide_jpg', 'hide_png', 'hide_webp', 'hide_avif'];
        for (var i = 0; i < keys.length; i++) {
            var k = keys[i];
            if (params.has(k)) {
                o[k] = params.get(k);
            } else {
                delete o[k];
            }
        }
    }

    function ptWucleanSaveImageResultsFiltersToSession() {
        if (typeof sessionStorage === 'undefined' || typeof URLSearchParams === 'undefined') {
            return;
        }
        try {
            var sp = new URLSearchParams();
            ptWucleanApplyDomToResultsFilterSearchParams(sp);
            var o = ptWucleanReadResultsPrefsFromSession() || {};
            ptWucleanApplyResultsFilterPrefsFromParams(o, sp);
            var $perPageSelect = $('#pt-wuclean-results-per-page');
            if ($perPageSelect.length) {
                o.per_page = ptWucleanNormalizeResultsPerPage($perPageSelect.val());
            } else if (sp.has('per_page')) {
                o.per_page = ptWucleanNormalizeResultsPerPage(sp.get('per_page'));
            }
            if (Object.keys(o).length > 0) {
                ptWucleanWriteResultsPrefsToSession(o);
            }
        } catch (e) {
            // Ignore private mode / quota errors.
        }
    }

    function ptWucleanClearImageResultsFilterSession() {
        if (typeof sessionStorage === 'undefined') {
            return;
        }
        try {
            sessionStorage.removeItem(PT_WUCLEAN_RESULTS_FILTER_STORAGE_KEY);
        } catch (e) {
            // Ignore.
        }
    }

    function ptWucleanMergeStoredFiltersIntoResultsUrl(baseHref) {
        if (!baseHref) {
            return '?page=wuclean-images&tab=results';
        }
        if (typeof sessionStorage === 'undefined' || typeof URL === 'undefined') {
            return baseHref;
        }
        try {
            var raw = sessionStorage.getItem(PT_WUCLEAN_RESULTS_FILTER_STORAGE_KEY);
            if (!raw) {
                return baseHref;
            }
            var o = JSON.parse(raw);
            if (!o || typeof o !== 'object') {
                return baseHref;
            }
            var u = new URL(baseHref, window.location.href);
            var keys = ['orphan_filter', 'hide_originals_of_scaled', 'hide_safe_siblings', 'hide_thumbnails', 'hide_jpg', 'hide_png', 'hide_webp', 'hide_avif'];
            for (var j = 0; j < keys.length; j++) {
                var key = keys[j];
                // URL params win when present (e.g. user unchecked hide_jpg — param omitted, not restored from session).
                if (u.searchParams.has(key)) {
                    continue;
                }
                if (Object.prototype.hasOwnProperty.call(o, key) && o[key] !== null && o[key] !== '') {
                    u.searchParams.set(key, String(o[key]));
                }
            }
            if (Object.prototype.hasOwnProperty.call(o, 'per_page')) {
                u.searchParams.set('per_page', String(ptWucleanNormalizeResultsPerPage(o.per_page)));
            }
            if (!ptWucleanResultsUploadsViewsAvailable()) {
                var storedOrphan = u.searchParams.get('orphan_filter');
                if (storedOrphan && storedOrphan !== 'hide_orphaned') {
                    u.searchParams.set('orphan_filter', 'hide_orphaned');
                }
            }
            return u.toString();
        } catch (e) {
            return baseHref;
        }
    }

    function ptWucleanImagesCombinedScanAvailable() {
        return !!(imageStrings && imageStrings.combined_scan_available);
    }

    function ptWucleanDefaultImageScanScope() {
        return ptWucleanImagesCombinedScanAvailable() ? 'media_and_uploads' : 'media_only';
    }

    function ptWucleanSetScanButtonsStarting() {
        $quickStartButton.prop('disabled', true).text(ptWucleanGetString('starting', 'Starting...'));
        if ($startButton.length) {
            $startButton.prop('disabled', true).text(ptWucleanGetString('starting', 'Starting...'));
        }
    }

    function ptWucleanSetScanButtonsScanningLabels() {
        $quickStartButton.text(imgString('scanning_label', 'Scanning...'));
        if ($startButton.length) {
            $startButton.text(imgString('scanning_label', 'Scanning...'));
        }
    }

    function ptWucleanResetScanButtonsLabels() {
        $quickStartButton.prop('disabled', false).text('🔍 ' + imgString('quick_start_button_label', 'Media Library Scan'));
        if ($startButton.length) {
            $startButton.prop('disabled', false).text('🔍 ' + imgString('start_button_label', 'Media Library & Uploads Folder Scan'));
        }
    }

    function clearScanBatchRequestPending() {
        $progressBar.removeClass('pt-wuclean-progress-bar-pending');
    }

    function showScanBatchRequestPending() {
        if (!scanInProgress || stopRequested) {
            return;
        }
        if (scanBatchIndex <= 0) {
            return;
        }
        $progressBar.addClass('pt-wuclean-progress-bar-pending');
    }
    
    function startScan(scope) {
        if (scanInProgress) return;
        
        scanInProgress = true;
        stopRequested = false;
        scanBatchIndex = 0;
        clearScanBatchRequestPending();
        $progressWaiting.hide().empty();
        ptWucleanConfigureScanSteps(scope);

        // Update UI
        ptWucleanSetScanButtonsStarting();
        $stopButton.prop('disabled', false).text(ptWucleanGetString('stopScan', 'Stop & Reset')).show();
        $resumeButton.hide().prop('disabled', false);
        $progressDiv.show();

        // Show immediate feedback
        $progressBar.css({
            'width': '1%',
            'background': '#0073aa'
        });
        $progressText.text('');
        $progressDetails.text(ptWucleanGetString('initializingSearch', 'Initializing search...'));
        
        // Start scan via AJAX
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'pt_wuclean_start_image_scan',
                nonce: pt_wuclean_images_vars.image_scan_nonce || $('#pt-wuclean-image-scan-nonce').val(),
                scope: scope || ptWucleanDefaultImageScanScope()
            },
            timeout: 30000,
            success: function(response) {
                if (response.success) {
                    ptWucleanClearImageResultsFilterSession();
                    ptWucleanSetScanButtonsScanningLabels();

                    // Begin batch processing
                    processScanBatch();
                } else {
                    scanInProgress = false;
                    ptWucleanResetScanButtonsLabels();
                    $stopButton.prop('disabled', false).text(ptWucleanGetString('stopScan', 'Stop & Reset')).hide();
                    $resumeButton.hide().prop('disabled', false);
                    $progressBar.css('background', '#dc3232');
                    $progressText.text(imgString('error_label', 'Error'));
                    var startErr = ptWucleanCoerceAjaxMessage(response.data, imgString('failed_start', 'Failed to start scan'));
                    $progressDetails.text(startErr);
                    if (response.data && typeof response.data === 'object' && response.data.code === 'wuclean_scan_exists') {
                        $resumeButton.show();
                    }
                }
            },
            error: function(xhr, status, error) {
                console.error('Scan start error:', error);
                scanInProgress = false;
                ptWucleanResetScanButtonsLabels();
                $stopButton.prop('disabled', false).text(ptWucleanGetString('stopScan', 'Stop & Reset')).hide();
                $progressBar.css('background', '#dc3232');
                $progressText.text(imgString('error_label', 'Error'));
                $progressDetails.text(imgString('connection_error_detailed', 'Connection error. Please try again.'));
            }
        });
    }

    // Quick start scan button (media library only).
    $quickStartButton.on('click', function() {
        startScan('media_only');
    });

    
    
    // Stop scan button
    $stopButton.on('click', function() {
        stopRequested = true;
        scanInProgress = false;
        scanBatchIndex = 0;
        clearScanBatchRequestPending();
        $progressWaiting.hide().empty();
        $stopButton.prop('disabled', true).text(ptWucleanGetString('stopping', 'Stopping...'));
        
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'pt_wuclean_stop_image_scan',
                nonce: pt_wuclean_images_vars.image_scan_nonce || $('#pt-wuclean-image-scan-nonce').val()
            },
            success: function() {
                ptWucleanResetScanButtonsLabels();
                $stopButton.prop('disabled', false).text(ptWucleanGetString('stopScan', 'Stop & Reset')).hide();
                $resumeButton.hide().prop('disabled', false);
                $progressBar.css('background', '#dc3232');
                $progressText.text(imgString('stopped_label', 'Stopped'));
                $progressDetails.text(imgString('scan_stopped_message', 'Scan stopped by user. Partial results have been saved.'));
            }
        });
    });

    // Resume scan button
    $resumeButton.on('click', function() {
        if (scanInProgress) return;

        scanInProgress = true;
        stopRequested = false;
        scanBatchIndex = 0;
        clearScanBatchRequestPending();
        $progressWaiting.hide().empty();
        ptWucleanConfigureScanSteps(ptWucleanDefaultImageScanScope());

        $resumeButton.prop('disabled', true).text(ptWucleanGetString('resuming', 'Resuming...'));
        if ($startButton.length) {
            $startButton.prop('disabled', true).text(imgString('scanning_label', 'Scanning...'));
        }
        $stopButton.prop('disabled', false).text(ptWucleanGetString('stopScan', 'Stop & Reset')).show();
        $progressDiv.show();

        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'pt_wuclean_resume_image_scan',
                nonce: pt_wuclean_images_vars.image_scan_nonce || $('#pt-wuclean-image-scan-nonce').val()
            },
            timeout: 30000,
            success: function(response) {
                if (response.success) {
                    $resumeButton.hide().prop('disabled', false).text(ptWucleanGetString('resume', 'Resume Scan'));
                    processScanBatch();
                } else {
                    scanInProgress = false;
                    ptWucleanResetScanButtonsLabels();
                    $stopButton.hide().prop('disabled', false).text(ptWucleanGetString('stopScan', 'Stop & Reset'));
                    $resumeButton.prop('disabled', false).text(ptWucleanGetString('resume', 'Resume Scan')).show();
                    $progressBar.css('background', '#dc3232');
                    $progressText.text(imgString('error_label', 'Error'));
                    $progressDetails.text(ptWucleanCoerceAjaxMessage(response.data, imgString('unknown_error', 'Unknown error')));
                }
            },
            error: function(xhr, status) {
                var errMsg = ptWucleanIsGatewayTimeout(xhr, status)
                    ? imgString('request_timed_out', 'Request timed out. Try Resume Scan, or use Stop & Reset to cancel.')
                    : imgString('connection_error_detailed', 'Connection error. Please try again.');
                ptWucleanShowScanInterruptedUI(errMsg);
            }
        });
    });
    
    // Process scan batch (recursive)
    function processScanBatch() {
        if (!scanInProgress || stopRequested) {
            return;
        }
        
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'pt_wuclean_process_scan_batch',
                nonce: pt_wuclean_images_vars.image_scan_nonce || $('#pt-wuclean-image-scan-nonce').val()
            },
            timeout: 120000, // 2 minutes
            beforeSend: function() {
                showScanBatchRequestPending();
            },
            complete: function() {
                clearScanBatchRequestPending();
            },
            success: function(response) {
                if (!scanInProgress || stopRequested) {
                    return;
                }
                
                if (response.success) {
                    var data = response.data;

                    if (!data.completed) {
                        ptWucleanApplyScanProgressUI(data);
                    }

                    // Check if complete
                    if (data.completed) {
                        scanInProgress = false;
                        scanBatchIndex = 0;
                        ptWucleanMarkAllScanStepsDone();
                        $progressWaiting.hide().empty();
                        ptWucleanResetScanButtonsLabels();
                        $stopButton.prop('disabled', false).text(ptWucleanGetString('stopScan', 'Stop & Reset')).hide();
                        $progressBar.css({
                            'width': '100%',
                            'background': '#46b450'
                        });
                        $progressText.text('');
                        
                        // Show completion message with refinement info if available
                        var completionMsg = '<strong>' + imgString('scan_complete_heading', 'Scan complete!') + '</strong><br>' +
                            replaceIndexedPlaceholders(imgString('total_issues_template', 'Found <strong>%1$d</strong> issues.'), [data.total_issues || 0]);
                        if (data.refinement_count && data.refinement_count > 0) {
                            var refinementCount = data.refinement_count;
                            var refinementText = refinementCount === 1
                                ? formatString(imgString('verified_images_single', '%d image in use.'), refinementCount)
                                : formatString(imgString('verified_images_plural', '%d images in use.'), refinementCount);
                            completionMsg += '<br><em>' + refinementText + '</em>';
                        }
                        var orphanRefine = parseInt(data.orphaned_file_refinement_count, 10) || 0;
                        if (orphanRefine > 0) {
                            var orphanText = orphanRefine === 1
                                ? formatString(imgString('orphan_refinement_single', 'Removed %d uploads-folder result.'), orphanRefine)
                                : formatString(imgString('orphan_refinement_plural', 'Removed %d uploads-folder results.'), orphanRefine);
                            completionMsg += '<br><em>' + orphanText + '</em>';
                        }
                        completionMsg += '<br>' + imgString('redirecting_results', 'Redirecting to results...');
                        $progressDetails.html(completionMsg);
                        
                        // Redirect to results (3 second delay to match other scans)
                        setTimeout(function() {
                            var resultsUrl = imgString('results_url', '');
                            window.location.href = ptWucleanMergeStoredFiltersIntoResultsUrl(
                                resultsUrl || '?page=wuclean-images&tab=results'
                            );
                        }, 3000);
                    } else {
                        scanBatchIndex++;
                        // Process next batch
                        setTimeout(function() {
                            if (scanInProgress && !stopRequested) {
                                processScanBatch();
                            }
                        }, 100); // 100ms delay between batches
                    }
                } else {
                    // Error in batch processing
                    console.error('Batch error:', response);
                    ptWucleanShowScanInterruptedUI(
                        ptWucleanCoerceAjaxMessage(response.data, imgString('scan_failed_retry', 'Scan failed. Please try again.'))
                    );
                }
            },
            error: function(xhr, status, error) {
                console.error('Batch AJAX error:', error);
                var errMsg = ptWucleanIsGatewayTimeout(xhr, status)
                    ? imgString('request_timed_out', 'Request timed out. Try Resume Scan, or use Stop & Reset to cancel.')
                    : imgString('connection_timeout', 'Connection error. Please try again or use Stop & Reset.');
                ptWucleanShowScanInterruptedUI(errMsg);
            }
        });
    }

    if (pt_wuclean_images_vars && pt_wuclean_images_vars.manual_scan_resumable) {
        $progressDiv.show();
        $resumeButton.show().prop('disabled', false);
        $stopButton.show().prop('disabled', false).text(ptWucleanGetString('stopScan', 'Stop & Reset'));
        $progressBar.css('background', '#dc3232');
        $progressText.text(imgString('error_label', 'Error'));
        $progressDetails.text(imgString('scan_resume_prompt', 'Scan interrupted. Click Resume Scan to continue, or Stop & Reset to cancel.'));
    }
    
    // ========================================================================
    // RESULTS TAB - Bulk Selection Management
    // ========================================================================
    
    var $checkboxes = $('.pt-wuclean-image-checkbox');
    var $selectAllCheckbox = $('#pt-wuclean-select-all-checkbox');
    var $protectSelectedBtn = $('#pt-wuclean-protect-selected');
    var $trashSelectedBtn = $('#pt-wuclean-trash-selected');
    var $deleteSelectedBtn = $('#pt-wuclean-delete-selected');
    var $selectedCount = $('#pt-wuclean-selected-count');
    
    function updateSelectionState() {
        // Only count visible checkboxes
        var $visibleCheckboxes = $checkboxes.filter(function() {
            return $(this).closest('tr').is(':visible');
        });
        
        var selectedCount = $visibleCheckboxes.filter(':checked').length;
        var totalCount = $visibleCheckboxes.length;
        
        $protectSelectedBtn.prop('disabled', selectedCount === 0);
        $trashSelectedBtn.prop('disabled', selectedCount === 0);
        $deleteSelectedBtn.prop('disabled', selectedCount === 0);
        
        if (selectedCount > 0) {
            if (selectedCount === 1) {
                $selectedCount.text(formatString(imgString('selection_single', '%d image selected'), selectedCount));
            } else {
                $selectedCount.text(formatString(imgString('selection_plural', '%d images selected'), selectedCount));
            }
        } else {
            $selectedCount.text('');
        }
        
        // Update "select all" checkbox state
        if (selectedCount === totalCount && totalCount > 0) {
            $selectAllCheckbox.prop('checked', true).prop('indeterminate', false);
        } else if (selectedCount > 0) {
            $selectAllCheckbox.prop('checked', false).prop('indeterminate', true);
        } else {
            $selectAllCheckbox.prop('checked', false).prop('indeterminate', false);
        }
    }
    
    $checkboxes.on('change', updateSelectionState);
    
    $selectAllCheckbox.on('change', function() {
        // Only select/deselect visible checkboxes
        $checkboxes.filter(function() {
            return $(this).closest('tr').is(':visible');
        }).prop('checked', this.checked);
        updateSelectionState();
    });
    
    // ========================================================================
    // RESULTS TAB - Filter Controls (with sticky persistence)
    // ========================================================================

    // Function to update URL with filter parameters and reload
    function updateFiltersAndReload() {
        var url = new URL(window.location.href);
        var searchParams = url.searchParams;

        ptWucleanApplyDomToResultsFilterSearchParams(searchParams);

        var $perPageSelect = $('#pt-wuclean-results-per-page');
        if ($perPageSelect.length) {
            searchParams.set('per_page', String(ptWucleanNormalizeResultsPerPage($perPageSelect.val())));
        }

        // Reset to page 1 when filters change
        searchParams.delete('paged');

        ptWucleanSaveImageResultsFiltersToSession();

        // Update URL and reload
        window.location.href = url.toString();
    }
    
    if (ptWucleanResultsUploadsViewsAvailable()) {
        $('input[name="orphan_filter"]').on('change', function() {
            var orphanFilter = $(this).val();
            
            // Disable scaled-original filter only for Media Library-only (uploads + combined can use it when present).
            if ($filterHideScaledOriginals.length) {
                if (orphanFilter === 'hide_orphaned') {
                    $filterHideScaledOriginals.prop('disabled', true);
                } else {
                    $filterHideScaledOriginals.prop('disabled', false);
                }
            }
            
            updateFiltersAndReload();
        });
    }
    
    // Apply filters on checkbox change - update URL and reload
    if ($filterSafeSiblings.length) {
        $filterSafeSiblings.on('change', function() {
            updateFiltersAndReload();
        });
    }
    if ($filterThumbnails.length) {
        $filterThumbnails.on('change', function() {
            updateFiltersAndReload();
        });
    }
    $filterJpg.on('change', function() {
        updateFiltersAndReload();
    });
    $filterPng.on('change', function() {
        updateFiltersAndReload();
    });
    $filterWebp.on('change', function() {
        updateFiltersAndReload();
    });
    $filterAvif.on('change', function() {
        updateFiltersAndReload();
    });
    if ($filterHideScaledOriginals.length) {
        $filterHideScaledOriginals.on('change', function() {
            if (!$(this).prop('disabled')) {
                updateFiltersAndReload();
            }
        });
    }

    (function ptWucleanSyncImageResultsFilterSessionFromUrl() {
        if (typeof URL === 'undefined' || typeof sessionStorage === 'undefined') {
            return;
        }
        try {
            var u = new URL(window.location.href);
            if (u.searchParams.get('tab') !== 'results') {
                return;
            }
            var o = ptWucleanReadResultsPrefsFromSession() || {};
            ptWucleanApplyResultsFilterPrefsFromParams(o, u.searchParams);
            if (u.searchParams.has('per_page')) {
                o.per_page = ptWucleanNormalizeResultsPerPage(u.searchParams.get('per_page'));
            }
            if (Object.keys(o).length > 0) {
                ptWucleanWriteResultsPrefsToSession(o);
            }
        } catch (e) {
            // Ignore.
        }
    })();

    (function ptWucleanRestoreStoredResultsPreferencesOnLoad() {
        if (typeof URL === 'undefined') {
            return;
        }
        try {
            var u = new URL(window.location.href);
            if (u.searchParams.get('tab') !== 'results') {
                return;
            }
            var merged = ptWucleanMergeStoredFiltersIntoResultsUrl(u.toString());
            if (merged !== u.toString()) {
                window.location.replace(merged);
                return;
            }
            if (u.searchParams.has('per_page')) {
                ptWucleanSaveResultsPerPagePreference(u.searchParams.get('per_page'));
            }
        } catch (e) {
            // Ignore.
        }
    })();

    $(document).on('click', 'a[href*="page=wuclean-images"][href*="tab=results"]', function(e) {
        var href = $(this).attr('href');
        if (!href || href.indexOf('tab=results') === -1) {
            return;
        }
        var target = ptWucleanMergeStoredFiltersIntoResultsUrl(href);
        if (target !== href) {
            e.preventDefault();
            window.location.href = target;
        }
    });

    $('form').on('submit', function(e) {
        var $form = $(this);
        if (!$form.find('input[name="tab"][value="results"]').length) {
            return;
        }
        if (typeof URL === 'undefined') {
            return;
        }
        try {
            var action = $form.attr('action') || window.location.pathname + window.location.search;
            var url = new URL(action, window.location.href);
            var params = new URLSearchParams($form.serialize());
            params.forEach(function(value, key) {
                url.searchParams.set(key, value);
            });
            if ($('#pt-wuclean-filter-hide-scaled-originals').length) {
                ptWucleanApplyDomToResultsFilterSearchParams(url.searchParams);
            }
            url.searchParams.delete('paged');
            var prefsFromUrl = ptWucleanReadResultsPrefsFromSession() || {};
            ptWucleanApplyResultsFilterPrefsFromParams(prefsFromUrl, url.searchParams);
            if (url.searchParams.has('per_page')) {
                prefsFromUrl.per_page = ptWucleanNormalizeResultsPerPage(url.searchParams.get('per_page'));
            }
            ptWucleanWriteResultsPrefsToSession(prefsFromUrl);
            e.preventDefault();
            window.location.href = url.toString();
        } catch (err) {
            // Allow native submit if URL building fails.
        }
    });

    $('#pt-wuclean-results-per-page').on('change', function() {
        var perPage = ptWucleanNormalizeResultsPerPage($(this).val());
        ptWucleanSaveResultsPerPagePreference(perPage);

        var url = new URL(window.location.href);
        url.searchParams.set('per_page', String(perPage));
        url.searchParams.set('paged', '1');
        ptWucleanApplyDomToResultsFilterSearchParams(url.searchParams);
        window.location.href = url.toString();
    });

    $('.nav-tab-wrapper a.nav-tab').on('click', function() {
        var href = $(this).attr('href');
        if (!href || href.indexOf('tab=results') === -1) {
            return;
        }
        var target = ptWucleanMergeStoredFiltersIntoResultsUrl(href);
        if (target !== href) {
            window.location.href = target;
            return false;
        }
    });


    
    // ========================================================================
    // RESULTS TAB - Individual Action Buttons
    // ========================================================================
    

    
    // ========================================================================
    // PROTECTED TAB - selection helpers (free + premium; used by inline Trash/Delete on Protected tab)
    // ========================================================================
    var $protectedCheckboxes = $('.pt-wuclean-protected-checkbox');
    var $selectAllProtectedCheckbox = $('#pt-wuclean-select-all-protected-checkbox');
    var $unprotectSelectedBtn = $('#pt-wuclean-unprotect-selected');
    var $protectedSelectedCount = $('#pt-wuclean-protected-selected-count');

    function updateProtectedSelectionState() {
        var selectedCount = $protectedCheckboxes.filter(':checked').length;
        var totalCount = $protectedCheckboxes.length;

        $unprotectSelectedBtn.prop('disabled', selectedCount === 0);

        if (selectedCount > 0) {
            if (selectedCount === 1) {
                $protectedSelectedCount.text(formatString(imgString('selection_single', '%d image selected'), selectedCount));
            } else {
                $protectedSelectedCount.text(formatString(imgString('selection_plural', '%d images selected'), selectedCount));
            }
        } else {
            $protectedSelectedCount.text('');
        }

        if (selectedCount === totalCount && totalCount > 0) {
            $selectAllProtectedCheckbox.prop('checked', true).prop('indeterminate', false);
        } else if (selectedCount > 0) {
            $selectAllProtectedCheckbox.prop('checked', false).prop('indeterminate', true);
        } else {
            $selectAllProtectedCheckbox.prop('checked', false).prop('indeterminate', false);
        }
    }

    function updateProtectedBulkButtons() {
        var selectedCount = $protectedCheckboxes.filter(':checked').length;
        $unprotectSelectedBtn.prop('disabled', selectedCount === 0);
        if ($('#pt-wuclean-trash-selected-protected').length) {
            $('#pt-wuclean-trash-selected-protected').prop('disabled', selectedCount === 0);
        }
        if ($('#pt-wuclean-delete-selected-protected').length) {
            $('#pt-wuclean-delete-selected-protected').prop('disabled', selectedCount === 0);
        }
    }

    // Protect button
    $(document).on('click', '.pt-wuclean-protect-btn', function() {
        var $btn = $(this);
        var imageId = $btn.data('image-id');
        
        $btn.prop('disabled', true).html(imgString('protect_button_loading', '⏳ Protecting...'));
        
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'pt_wuclean_protect_image',
                image_id: imageId,
                nonce: pt_wuclean_images_vars.protect_image_nonce
            },
            success: function(response) {
                if (response.success) {
                    var $row = $btn.closest('tr');
                    var $table = $row.closest('table');
                    var filename = $row.data('filename');
                    var protectAttachmentId = parseInt($btn.data('image-id'), 10) || 0;
                    
                    // Remove the main row
                    $row.remove();
                    
                    // Remove sibling rows (WebP/AVIF, etc.) — include big-image original parent basename.
                    if (filename) {
                        ptWucleanRemoveRowsByParentFilenames($table, ptWucleanMediaRelatedParentFilenames(filename));
                        ptWucleanRemoveRowsByDataFilenames($table, ptWucleanSidecarFilenamesForMediaBasename(filename));
                    }
                    if (protectAttachmentId > 0) {
                        $table.find('tbody tr[data-sibling-id="' + String(protectAttachmentId) + '"]').remove();
                    }
                    
                    // Update selection state
                    $checkboxes = $('.pt-wuclean-image-checkbox');
                    updateSelectionState();
                    
                    // Check if table is now empty
                    if ($('table tbody tr').length === 0) {
                        location.reload();
                    }
                                        
                    // Show success message
                    showToast(response.data || imgString('protect_single_success', 'Image protected successfully'), 'success');
                } else {
                    $btn.prop('disabled', false).html(imgString('protect_button_label', '🛡️ Protect'));
                    showToast(response.data || imgString('protect_single_failed', 'Failed to protect image'), 'error');
                }
            },
            error: function() {
                $btn.prop('disabled', false).html(imgString('protect_button_label', '🛡️ Protect'));
                showToast(imgString('connection_error', 'Connection error'), 'error');
            }
        });
    });
    
    // Trash button (works for both results and protected tabs)
    $(document).on('click', '.pt-wuclean-trash-btn', function() {
        var $btn = $(this);
        var imageId = parseInt($btn.data('image-id'), 10) || 0;
        var $row = $btn.closest('tr');
        var isProtectedTab = ($row.find('.pt-wuclean-protected-checkbox').length > 0) ||
            ($row.closest('table[data-wuclean-images-tab="protected"]').length > 0);
        
        $btn.prop('disabled', true).html(imgString('trash_button_loading', '⏳ Trashing...'));
        
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'pt_wuclean_trash_image',
                image_id: imageId > 0 ? imageId : $btn.data('image-id'),
                nonce: pt_wuclean_images_vars.trash_image_nonce
            },
            success: function(response) {
                if (response.success) {
                    var $table = $row.closest('table');
                    var filename = $row.data('filename');
                    
                    // Remove the main row
                    $row.remove();
                    
                    // Count rows removed
                    var rowsRemoved = 1;
                    
                    // Remove sibling rows (only for results tab): match scaled + big-image original parent basenames.
                    if (!isProtectedTab) {
                        if (filename) {
                            rowsRemoved += ptWucleanRemoveRowsByParentFilenames($table, ptWucleanMediaRelatedParentFilenames(filename));
                            rowsRemoved += ptWucleanRemoveRowsByDataFilenames($table, ptWucleanSidecarFilenamesForMediaBasename(filename));
                        }
                        if (imageId > 0) {
                            var $bySib = $table.find('tbody tr[data-sibling-id="' + String(imageId) + '"]');
                            rowsRemoved += $bySib.length;
                            $bySib.remove();
                        }
                    }
                    
                    // Update selection state based on tab
                    if (isProtectedTab) {
                        $protectedCheckboxes = $('.pt-wuclean-protected-checkbox');
                        updateProtectedSelectionState();
                    } else {
                        $checkboxes = $('.pt-wuclean-image-checkbox');
                        updateSelectionState();
                    }
                    
                    // Check if table is now empty
                    if ($('table tbody tr').length === 0) {
                        location.reload();
                    } else {
                        // Update pagination text
                        updatePaginationCount(rowsRemoved);
                    }
                    
                    showToast(response.data || imgString('trash_single_success', 'Image moved to trash successfully'), 'success');
                } else {
                    $btn.prop('disabled', false).html(imgString('trash_button_label', '🗑️ Trash'));
                    showToast(response.data || imgString('trash_single_failed', 'Failed to trash image'), 'error');
                }
            },
            error: function() {
                $btn.prop('disabled', false).html(imgString('trash_button_label', '🗑️ Trash'));
                showToast(imgString('connection_error', 'Connection error'), 'error');
            }
        });
    });

    // Protected tab: keep selection + inline Unprotect working in free (uses free AJAX).
    $protectedCheckboxes.on('change', function() {
        updateProtectedSelectionState();
        updateProtectedBulkButtons();
    });

    $selectAllProtectedCheckbox.on('change', function() {
        $protectedCheckboxes.prop('checked', this.checked);
        updateProtectedSelectionState();
        updateProtectedBulkButtons();
    });

    $(document).on('click', '.pt-wuclean-unprotect-btn', function() {
        var $btn = $(this);
        var imageId = $btn.data('image-id');

        if (!confirm(imgString('confirm_unprotect_image', 'Unprotect this image? It will be included in future scans.'))) {
            return;
        }

        $btn.prop('disabled', true).text(imgString('unprotecting_label', 'Unprotecting...'));

        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'pt_wuclean_unprotect_image',
                image_id: imageId,
                nonce: pt_wuclean_images_vars.unprotect_image_nonce
            },
            success: function(response) {
                if (response.success) {
                    $btn.closest('tr').fadeOut(400, function() {
                        $(this).remove();

                        $protectedCheckboxes = $('.pt-wuclean-protected-checkbox');
                        updateProtectedSelectionState();

                        if ($('table tbody tr').length === 0) {
                            location.reload();
                        } else {
                            updatePaginationCount(1);
                        }
                    });

                    showToast(imgString('unprotect_success', 'Image unprotected successfully'), 'success');
                } else {
                    $btn.prop('disabled', false).text(imgString('unprotect_button_label', '🔓 Unprotect'));
                    showToast(response.data || imgString('unprotect_failed', 'Failed to unprotect image'), 'error');
                }
            },
            error: function() {
                $btn.prop('disabled', false).text(imgString('unprotect_button_label', '🔓 Unprotect'));
                showToast(imgString('connection_error', 'Connection error'), 'error');
            }
        });
    });


    // Delete button (Media Library images - works for both results and protected tabs)
    $(document).on('click', '.pt-wuclean-delete-btn', function() {
        var $btn = $(this);
        var imageId = $btn.data('image-id');
        var $row = $btn.closest('tr');
        var isProtectedTab = ($row.find('.pt-wuclean-protected-checkbox').length > 0) ||
            ($row.closest('table[data-wuclean-images-tab="protected"]').length > 0);
        
        if (!confirm(imgString('confirm_delete_image', '⚠️ PERMANENTLY DELETE this image? This action CANNOT be undone!'))) {
            return;
        }
        
        $btn.prop('disabled', true).html('<span style="filter: brightness(0) invert(1);">⏳</span> ' + imgString('delete_file_loading', 'Deleting...'));
        
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'pt_wuclean_delete_image',
                image_id: imageId,
                nonce: pt_wuclean_images_vars.delete_image_nonce
            },
            success: function(response) {
                if (response.success) {
                    var $table = $row.closest('table');
                    var filename = $row.data('filename');
                    
                    // Remove the main row.
                    $row.remove();
                    
                    // Count rows removed.
                    var rowsRemoved = 1;
                    
                    // Remove any related rows (only for results tab).
                    if (!isProtectedTab && filename) {
                        // Permanent delete: WordPress removes JPEG/PNG originals + sizes but leaves WebP/AVIF on disk.
                        // Do not strip WebP/AVIF (or sibling_id-linked) rows — they should stay visible until rescan.
                        // If this is a WordPress scaled filename (e.g. "image-scaled.jpg"),
                        // remove the "scaled_original" row for the original file (e.g. "image.jpg") — that file was deleted.
                        var scaledIndex = filename.indexOf('-scaled.');
                        if (scaledIndex !== -1) {
                            var ext = filename.substring(filename.lastIndexOf('.') + 1);
                            var base = filename.substring(0, filename.lastIndexOf('.'));
                            var originalBase = base.replace('-scaled', '');
                            var originalFilename = originalBase + '.' + ext;

                            var originals = $table.find('tbody tr[data-filename="' + originalFilename + '"]');
                            rowsRemoved += originals.length;
                            originals.remove();
                        }
                    }
                    
                    // Update selection state based on tab
                    if (isProtectedTab) {
                        $protectedCheckboxes = $('.pt-wuclean-protected-checkbox');
                        updateProtectedSelectionState();
                    } else {
                        $checkboxes = $('.pt-wuclean-image-checkbox');
                        updateSelectionState();
                    }
                    
                    // Check if table is now empty
                    if ($('table tbody tr').length === 0) {
                        location.reload();
                    } else {
                        // Update pagination text
                        updatePaginationCount(rowsRemoved);
                    }
                    
                    showToast(response.data || imgString('image_deleted_success', 'Image deleted permanently'), 'success');
                } else {
                    $btn.prop('disabled', false).html('<span style="filter: brightness(0) invert(1);">❌</span> ' + imgString('delete_image_button', 'Delete Permanently'));
                    showToast(response.data || imgString('image_deleted_failed', 'Failed to delete image'), 'error');
                }
            },
            error: function() {
                $btn.prop('disabled', false).html('<span style="filter: brightness(0) invert(1);">❌</span> ' + imgString('delete_image_button', 'Delete Permanently'));
                showToast(imgString('connection_error', 'Connection error'), 'error');
            }
        });
    });
    
    // ========================================================================
    // TRASH TAB - Selection Management
    // ========================================================================
    
    var $trashCheckboxes = $('.pt-wuclean-trash-checkbox');
    var $selectAllTrashCheckbox = $('#pt-wuclean-select-all-trash-checkbox');
    var $restoreSelectedBtn = $('#pt-wuclean-restore-selected');
    var $deletePermanentSelectedBtn = $('#pt-wuclean-delete-permanent-selected');
    var $restoreAllBtn = $('#pt-wuclean-restore-all');
    var $deleteAllBtn = $('#pt-wuclean-delete-all');
    var $trashSelectedCount = $('#pt-wuclean-trash-selected-count');

    function ptWucleanGetTrashBulkAllIds() {
        var raw = document.getElementById('pt-wuclean-trash-bulk-all-ids');
        if (!raw || !raw.textContent) {
            return [];
        }
        try {
            var ids = JSON.parse(raw.textContent);
            return Array.isArray(ids) ? ids : [];
        } catch (e) {
            return [];
        }
    }

    function ptWucleanDisableTrashBulkToolbar() {
        $restoreSelectedBtn.prop('disabled', true);
        $deletePermanentSelectedBtn.prop('disabled', true);
        $restoreAllBtn.prop('disabled', true);
        $deleteAllBtn.prop('disabled', true);
    }
    
    function updateTrashSelectionState() {
        // Refresh checkbox collection to exclude removed rows
        $trashCheckboxes = $('.pt-wuclean-trash-checkbox');
        
        var selectedCount = $trashCheckboxes.filter(':checked').length;
        var totalCount = $trashCheckboxes.length;
        
        $restoreSelectedBtn.prop('disabled', selectedCount === 0);
        $deletePermanentSelectedBtn.prop('disabled', selectedCount === 0);
        
        if (selectedCount > 0) {
            $trashSelectedCount.text(selectedCount + ' ' + (selectedCount === 1 ? 'image selected' : 'images selected'));
        } else {
            $trashSelectedCount.text('');
        }
        
        // Update "select all" checkbox state
        if (selectedCount === totalCount && totalCount > 0) {
            $selectAllTrashCheckbox.prop('checked', true).prop('indeterminate', false);
        } else if (selectedCount > 0) {
            $selectAllTrashCheckbox.prop('checked', false).prop('indeterminate', true);
        } else {
            $selectAllTrashCheckbox.prop('checked', false).prop('indeterminate', false);
        }
    }
    
    // Use event delegation for checkboxes (handles dynamically removed rows)
    $(document).on('change', '.pt-wuclean-trash-checkbox', updateTrashSelectionState);
    
    $selectAllTrashCheckbox.on('change', function() {
        $('.pt-wuclean-trash-checkbox').prop('checked', this.checked);
        updateTrashSelectionState();
    });
    
    // Bulk restore
    $restoreSelectedBtn.on('click', function() {
        // Refresh checkbox collection
        var selectedIds = $('.pt-wuclean-trash-checkbox:checked').map(function() {
            return parseInt($(this).val());
        }).get();
        
        if (selectedIds.length === 0) return;
        
        $restoreSelectedBtn.prop('disabled', true).html('<span style="filter: brightness(0) invert(1);">⏳</span> ' + imgString('restoring_label', 'Restoring...'));
        ptWucleanDisableTrashBulkToolbar();
        
        // Restore images one by one
        var successCount = 0;
        var failCount = 0;
        var totalCount = selectedIds.length;
        
        function restoreNext(index) {
            var processedCount = successCount + failCount;
            var progressMsg = replaceIndexedPlaceholders(
                imgString('restore_selected_progress', 'Restoring... %1$d/%2$d'),
                [processedCount, totalCount]
            );
            $restoreSelectedBtn.html('<span style="filter: brightness(0) invert(1);">⏳</span> ' + progressMsg);
            
            if (index >= selectedIds.length) {
                // All done
                showToast(successCount + ' image(s) restored successfully', 'success');
                // Reload page to show updated list
                location.reload();
                return;
            }
            
            $.ajax({
                url: ajaxurl,
                type: 'POST',
                data: {
                    action: 'pt_wuclean_restore_image',
                    image_id: selectedIds[index],
                    nonce: pt_wuclean_images_vars.restore_image_nonce
                },
                success: function(response) {
                    if (response.success) {
                        successCount++;
                    } else {
                        failCount++;
                    }
                    restoreNext(index + 1);
                },
                error: function() {
                    failCount++;
                    restoreNext(index + 1);
                }
            });
        }
        
        restoreNext(0);
    });
    
    
    
    // ========================================================================
    // TRASH TAB - Individual Action Buttons
    // ========================================================================
    
    // Restore button
    $(document).on('click', '.pt-wuclean-restore-btn', function() {
        var $btn = $(this);
        var imageId = $btn.data('image-id');
        
        if (!confirm(imgString('confirm_restore_image', 'Restore image? It will not immediately be visible on the results tab but will be detected with the next image scan.'))) {
            return;
        }
        
        $btn.prop('disabled', true).text(imgString('restoring_label', 'Restoring...'));
        
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'pt_wuclean_restore_image',
                image_id: imageId,
                nonce: pt_wuclean_images_vars.restore_image_nonce
            },
            success: function(response) {
                if (response.success) {
                    // Remove the row from the table
                    $btn.closest('tr').fadeOut(400, function() {
                        $(this).remove();
                        
                        // Check if table is now empty
                        if ($('table tbody tr').length === 0) {
                            location.reload();
                        } else {
                            // Update pagination text
                            updatePaginationCount(1);
                        }
                    });
                    
                    showToast(imgString('restore_success', 'Image restored successfully'), 'success');
                } else {
                    $btn.prop('disabled', false).text(imgString('restore_button_label', '♻️ Restore'));
                    showToast(response.data || imgString('restore_failed', 'Failed to restore image'), 'error');
                }
            },
            error: function() {
                $btn.prop('disabled', false).text(imgString('restore_button_label', '♻️ Restore'));
                showToast(imgString('connection_error', 'Connection error'), 'error');
            }
        });
    });

    // Trash tab: permanently delete one trashed Media Library attachment (row action).
    $(document).on('click', '.pt-wuclean-delete-permanent-btn', function() {
        var $btn = $(this);
        var imageId = $btn.data('image-id');

        if (!confirm(imgString('confirm_delete_image', '⚠️ PERMANENTLY DELETE this image? This action CANNOT be undone!'))) {
            return;
        }

        $btn.prop('disabled', true).html('<span style="filter: brightness(0) invert(1);">⏳</span> ' + imgString('delete_file_loading', 'Deleting...'));

        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'pt_wuclean_delete_image',
                image_id: imageId,
                nonce: pt_wuclean_images_vars.delete_image_nonce
            },
            success: function(response) {
                if (response.success) {
                    $btn.closest('tr').fadeOut(400, function() {
                        $(this).remove();

                        if ($('table tbody tr').length === 0) {
                            location.reload();
                        } else {
                            updatePaginationCount(1);
                        }
                    });

                    showToast(imgString('image_deleted_success', 'Image deleted permanently'), 'success');
                } else {
                    $btn.prop('disabled', false).html('<span style="filter: brightness(0) invert(1);">❌</span> ' + imgString('delete_image_button', 'Delete Permanently'));
                    showToast(response.data || imgString('image_deleted_failed', 'Failed to delete image'), 'error');
                }
            },
            error: function() {
                $btn.prop('disabled', false).html('<span style="filter: brightness(0) invert(1);">❌</span> ' + imgString('delete_image_button', 'Delete Permanently'));
                showToast(imgString('connection_error', 'Connection error'), 'error');
            }
        });
    });

    // Delete orphaned files from plugin trash (attachment record missing).
    $(document).on('click', '.pt-wuclean-delete-trash-orphan-btn', function() {
        var $btn = $(this);
        var attachmentId = parseInt($btn.data('attachment-id'), 10) || 0;
        var $row = $btn.closest('tr');

        if (!attachmentId) {
            showToast(imgString('unknown_error', 'Unknown error'), 'error');
            return;
        }

        if (!confirm(imgString('confirm_delete_trash_orphan', '⚠️ PERMANENTLY DELETE these trashed files? This action CANNOT be undone!'))) {
            return;
        }

        $btn.prop('disabled', true).html('<span style="filter: brightness(0) invert(1);">⏳</span> ' + imgString('delete_file_loading', 'Deleting...'));

        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'pt_wuclean_delete_trash_orphan',
                attachment_id: attachmentId,
                nonce: (pt_wuclean_images_vars && pt_wuclean_images_vars.delete_trash_orphan_nonce) ? pt_wuclean_images_vars.delete_trash_orphan_nonce : ''
            },
            success: function(response) {
                if (response.success) {
                    $row.fadeOut(300, function() {
                        $(this).remove();
                        showToast(ptWucleanCoerceAjaxMessage(response.data, imgString('image_deleted_success', 'Deleted')), 'success');
                    });
                } else {
                    $btn.prop('disabled', false).html('<span style="filter: brightness(0) invert(1);">❌</span> ' + imgString('delete_image_button', 'Delete Permanently'));
                    showToast(ptWucleanCoerceAjaxMessage(response.data, imgString('image_deleted_failed', 'Failed to delete')), 'error');
                }
            },
            error: function() {
                $btn.prop('disabled', false).html('<span style="filter: brightness(0) invert(1);">❌</span> ' + imgString('delete_image_button', 'Delete Permanently'));
                showToast(imgString('connection_error', 'Connection error'), 'error');
            }
        });
    });

    // Download the best orphan trash file (single file).
    $(document).on('click', '.pt-wuclean-download-trash-orphan-btn', function() {
        var $btn = $(this);
        var attachmentId = parseInt($btn.data('attachment-id'), 10) || 0;

        if (!attachmentId) {
            showToast(imgString('unknown_error', 'Unknown error'), 'error');
            return;
        }

        var nonce = (pt_wuclean_images_vars && pt_wuclean_images_vars.download_trash_orphan_nonce)
            ? pt_wuclean_images_vars.download_trash_orphan_nonce
            : '';

        if (!nonce) {
            showToast(imgString('unknown_error', 'Unknown error'), 'error');
            return;
        }

        // Trigger a real browser download by navigating to admin-ajax.php with nonce.
        // Using $.ajax would not prompt a download reliably.
        var url = ajaxurl + '?action=pt_wuclean_download_trash_orphan'
            + '&attachment_id=' + encodeURIComponent(String(attachmentId))
            + '&_wpnonce=' + encodeURIComponent(String(nonce));

        $btn.prop('disabled', true).text(imgString('download_button_label', '⬇ Download'));
        window.location.href = url;

        // Re-enable shortly after so the user can download again if needed.
        setTimeout(function() {
            $btn.prop('disabled', false).text(imgString('download_button_label', '⬇ Download'));
        }, 1500);
    });
    
    // Simple toast notification
    function showToast(message, type) {
        var bgColor = type === 'success' ? '#46b450' : '#dc3232';
        var $toast = $('<div>')
            .css({
                position: 'fixed',
                top: '32px',
                right: '20px',
                background: bgColor,
                color: '#fff',
                padding: '12px 20px',
                borderRadius: '4px',
                boxShadow: '0 2px 5px rgba(0,0,0,0.2)',
                zIndex: 100000,
                fontSize: '14px'
            })
            .text(message)
            .appendTo('body');
        
        setTimeout(function() {
            $toast.fadeOut(400, function() {
                $(this).remove();
            });
        }, 3000);
    }
});
