/**
 * SEO Intelligence Page JavaScript
 *
 * @package Wisewand
 * @since 1.0.0
 */

jQuery(document).ready(function ($) {

    /**
     * Build market <option> elements from wisewandSEO.markets
     */
    function buildMarketOptions(selectedValue) {
        var markets = (typeof wisewandSEO !== 'undefined' && wisewandSEO.markets) ? wisewandSEO.markets : {
            'fr:2250': '🇫🇷 France (French)',
            'en:2840': '🇺🇸 United States (English)',
            'de:2276': '🇩🇪 Germany (German)',
            'es:2724': '🇪🇸 Spain (Spanish)'
        };
        var html = '';
        Object.keys(markets).forEach(function (value) {
            var sel = (value === selectedValue) ? ' selected' : '';
            html += '<option value="' + value + '"' + sel + '>' + markets[value] + '</option>';
        });
        return html;
    }

    // Modal Helper Functions
    function showModal(title, body, confirmText, confirmCallback) {
        $('#modal-title').text(title);
        $('#modal-body').html(body);
        $('#modal-confirm')
            .show()  // Always show button when opening modal
            .text(confirmText || 'Confirm')
            .prop('disabled', false)  // Reset button state when opening modal
            .off('click')
            .on('click', function () {
                if (confirmCallback) confirmCallback();
            });
        $('#wisewand-modal').fadeIn(200);
    }

    function closeModal() {
        $('#wisewand-modal').fadeOut(200);
    }

    function showSuccessModal(title, message) {
        showModal(title, '<div class="modal-success">' + message + '</div>', 'Close', closeModal);
    }

    function showErrorModal(title, message) {
        showModal(title, '<div class="modal-error">' + message + '</div>', 'Close', closeModal);
    }

    $('.modal-close, .modal-overlay').on('click', closeModal);

    // =========================================================================
    // DataForSEO Balance — fetch on page load
    // =========================================================================
    function fetchDataForSEOBalance() {
        if (!wisewandSEO.dataForSEOConfigured) return;
        $.post(wisewandSEO.ajaxUrl, {
            action: 'wisewand_get_dataforseo_balance',
            nonce: wisewandSEO.nonce
        }, function (response) {
            if (response.success && response.data) {
                var balance = parseFloat(response.data.balance);
                var $badge = $('#dataforseo-balance-badge');
                var $value = $('#dataforseo-balance-value');
                $value.text('$' + balance.toFixed(2));
                $badge.removeClass('balance-low balance-empty').show();
                if (balance <= 0) {
                    $badge.addClass('balance-empty');
                } else if (balance < 5) {
                    $badge.addClass('balance-low');
                }
                window.wisewandDataForSEOBalance = balance;
            }
        });
    }
    fetchDataForSEOBalance();

    /**
     * Pre-flight balance check before expensive DataForSEO operations.
     * Warns but always allows the user to proceed.
     */
    function checkBalanceBeforeAction(callback) {
        var balance = window.wisewandDataForSEOBalance;
        if (typeof balance === 'number' && balance <= 0) {
            showModal(
                'Insufficient DataForSEO Credits',
                '<div class="modal-error">Your DataForSEO balance is $' + balance.toFixed(2) +
                '.<br>This operation requires API credits. <a href="https://app.dataforseo.com/api-access" target="_blank" rel="noopener noreferrer">Top up your balance</a>.</div>',
                'Proceed Anyway',
                function () { closeModal(); callback(); }
            );
            return;
        }
        if (typeof balance === 'number' && balance < 5) {
            showModal(
                'Low DataForSEO Credits',
                '<div class="modal-warning" style="padding:12px;background:rgba(245,158,11,0.15);border-radius:8px;border:1px solid rgba(245,158,11,0.3);">Your DataForSEO balance is $' + balance.toFixed(2) +
                '. This operation uses API credits.</div>',
                'Continue',
                function () { closeModal(); callback(); }
            );
            return;
        }
        callback();
    }

    /**
     * Map DataForSEO error responses to actionable user messages.
     */
    function getDataForSEOErrorMessage(response) {
        var msg = (response.data && response.data.message) ? response.data.message : 'Unknown error';
        if (msg.indexOf('Insufficient') !== -1 || msg.indexOf('credits') !== -1) {
            return msg + ' <a href="https://app.dataforseo.com/api-access" target="_blank" rel="noopener noreferrer">Top up balance</a>';
        }
        if (msg.indexOf('authentication') !== -1 || msg.indexOf('credentials') !== -1) {
            return msg + ' <a href="' + wisewandSEO.settingsUrl + '">Check Settings</a>';
        }
        return msg;
    }

    // Compact card: Run Analysis (with pre-flight balance check)
    $('#run-analysis-card, #run-analysis').on('click', function () {
        checkBalanceBeforeAction(function () {
            runRealAnalysis();
        });
    });

    // Compact card: Add Keywords Modal
    $('#open-add-keywords-modal').on('click', function () {
        // Auto-detect language from current market selector
        const currentMarket = $('#market-selector').val();
        const [defaultLanguage, defaultLocation] = currentMarket ? currentMarket.split(':') : ['en', '2840'];

        const modalBody = `
                    <div class="modal-form-group">
                        <label>🌍 Language / Market</label>
                        <select id="modal-add-language" class="modal-select">
                            ${buildMarketOptions(currentMarket)}
                        </select>
                        <p style="font-size: 11px; color: var(--brand-gray-light); margin-top: 6px;">
                            Auto-detected from current market. All keywords will be enriched for this language/location.
                        </p>
                    </div>
                    <div class="modal-form-group">
                        <label>💾 Paste Keywords (one per line or comma-separated)</label>
                        <textarea id="modal-add-keywords" class="modal-textarea" rows="6" placeholder="wordpress seo\ncontent marketing\nblogging tips\nbest wordpress plugins"></textarea>
                    </div>
                    <div class="modal-form-group" style="padding: 12px; background: rgba(139, 92, 246, 0.05); border-radius: 8px; border: 1px solid rgba(139, 92, 246, 0.2);">
                        <label style="font-weight: 600; margin-bottom: 10px; display: block;">⚙️ Processing Options</label>
                        <div style="display: flex; flex-direction: column; gap: 8px;">
                            <label style="display: flex; align-items: center; cursor: pointer; font-size: 13px;">
                                <input type="checkbox" id="modal-skip-duplicates" checked style="margin-right: 8px;">
                                <span>Skip duplicate keywords (recommended for large batches)</span>
                            </label>
                            <label style="display: flex; align-items: center; cursor: pointer; font-size: 13px;">
                                <input type="checkbox" id="modal-auto-enrich" checked style="margin-right: 8px;">
                                <span>Auto-enrich with SEO data (volume, CPC, competition)</span>
                            </label>
                        </div>
                        ${!wisewandSEO.dataForSEOConfigured ? '<p style="font-size: 11px; color: var(--brand-warning); margin-top: 8px; margin-bottom: 0;">⚠️ DataForSEO not configured - enrichment will be skipped. <a href="' + wisewandSEO.settingsUrl + '" style="color: var(--brand-primary);">Configure now</a></p>' : ''}
                    </div>
                    <div id="modal-add-feedback"></div>
                `;

        showModal('💾 Add Keywords to Library', modalBody, '💾 Save & Enrich with SEO Data', function () {
            const keywordsText = $('#modal-add-keywords').val().trim();
            const [language, location] = $('#modal-add-language').val().split(':');

            if (!keywordsText) {
                $('#modal-add-feedback').html('<div class="modal-error">Please enter at least one keyword</div>');
                return;
            }

            // Parse keywords into array
            const keywordsArray = keywordsText.split(/[\r\n,]+/).map(k => k.trim()).filter(k => k.length > 0);

            if (keywordsArray.length === 0) {
                $('#modal-add-feedback').html('<div class="modal-error">Please enter at least one keyword</div>');
                return;
            }

            // Extract checkbox values
            const skipDuplicates = $('#modal-skip-duplicates').is(':checked') ? 1 : 0;
            const autoEnrich = $('#modal-auto-enrich').is(':checked') ? 1 : 0;

            // If less than 50 keywords, use simple processing (no progress bar needed)
            if (keywordsArray.length < 50) {
                $('#modal-confirm').prop('disabled', true).text('💾 Saving & Enriching...');
                $('#modal-add-feedback').html('<div class="modal-info">⏳ Saving ' + keywordsArray.length + ' keywords for ' + $('#modal-add-language option:selected').text() + '...</div>');

                $.ajax({
                    url: wisewandSEO.ajaxUrl,
                    type: 'POST',
                    data: {
                        action: 'wisewand_save_keywords_to_library',
                        keywords: keywordsText,
                        language_code: language,
                        location_code: parseInt(location),
                        skip_duplicates: skipDuplicates,
                        auto_enrich: autoEnrich,
                        nonce: wisewandSEO.nonce
                    },
                    success: function (response) {
                        if (response.success) {
                            const msg = `
                                    <strong>✅ Keywords Saved!</strong><br><br>
                                    💾 Saved: ${response.data.saved_count}<br>
                                    ⏭️ Skipped (duplicates): ${response.data.skipped_count}<br><br>
                                    Keywords will appear in the table below.
                                `;
                            $('#modal-add-feedback').html('<div class="modal-success">' + msg + '</div>');
                            $('#modal-confirm').text('✅ Done').prop('disabled', false);
                            $('#modal-add-keywords').val('');

                            // Update saved keywords count if element exists
                            if (response.data.list_html) {
                                $('.saved-keywords-count-display').html(response.data.list_html);
                            }

                            setTimeout(function () {
                                closeModal();
                                loadLatestSnapshot();
                            }, 2000);
                        } else {
                            $('#modal-add-feedback').html('<div class="modal-error">❌ ' + (response.data?.message || 'Failed') + '</div>');
                            $('#modal-confirm').prop('disabled', false).text('💾 Retry');
                        }
                    },
                    error: function (xhr, status, error) {
                        console.error('Add Keywords AJAX Error:', {
                            status: xhr.status,
                            statusText: xhr.statusText,
                            responseText: xhr.responseText,
                            error: error
                        });
                        let errorMsg = 'Connection error';
                        try {
                            const response = JSON.parse(xhr.responseText);
                            errorMsg = response.data?.message || response.message || errorMsg;
                        } catch (e) {
                            if (xhr.responseText) {
                                errorMsg = xhr.responseText.substring(0, 200);
                            }
                        }
                        $('#modal-add-feedback').html('<div class="modal-error">❌ ' + errorMsg + '<br><small>Check browser console (F12) for details</small></div>');
                        $('#modal-confirm').prop('disabled', false).text('💾 Retry');
                    }
                });
            } else {
                // Use batch processing with progress bar for 50+ keywords
                $('#modal-confirm').prop('disabled', true).text('💾 Processing...');

                const processor = new KeywordsBatchProcessor(keywordsArray, language, parseInt(location), skipDuplicates, autoEnrich);
                $('#modal-add-feedback').html(processor.getHTML());

                processor.start();
            }
        });
    });

    // Select all keywords in table
    $(document).on('change', '#select-all-keywords', function () {
        const isChecked = $(this).is(':checked');
        // CRITICAL FIX: Only select VISIBLE checkboxes (respects filters and search)
        $('.select-keyword-row:visible').prop('checked', isChecked);
        updateBulkActionsBar();
    });

    // Individual checkbox change
    $(document).on('change', '.select-keyword-row', function () {
        updateBulkActionsBar();
    });

    function updateBulkActionsBar() {
        // Count only VISIBLE checked boxes to match what user sees
        const selectedCount = $('.select-keyword-row:visible:checked').length;

        // Update both count displays
        $('.selected-count-display').text(selectedCount);

        if (selectedCount > 0) {
            $('#bulk-actions-top, #bulk-actions-bottom').slideDown(200);
        } else {
            $('#bulk-actions-top, #bulk-actions-bottom').slideUp(200);
        }
    }

    // Search functionality
    $('#keyword-search').on('keyup', function () {
        const searchTerm = $(this).val().toLowerCase();
        const $rows = $('.seo-table tbody tr');

        $rows.each(function () {
            const keyword = $(this).find('.col-keyword strong').text().toLowerCase();
            if (keyword.indexOf(searchTerm) > -1) {
                $(this).show();
            } else {
                $(this).hide();
            }
        });
    });

    // Bulk Enrich (works from both top and bottom bars) - WITH PROGRESS BAR
    $(document).on('click', '.bulk-enrich-btn', function () {
        // CRITICAL FIX: Only collect VISIBLE checked keywords (respects filters)
        const selected = $('.select-keyword-row:visible:checked').map(function () {
            return $(this).val();
        }).get();

        if (selected.length === 0) {
            alert('Please select keywords to enrich');
            return;
        }

        // Create processor first to get the HTML
        const processor = new EnrichmentBatchProcessor(selected);

        // Show modal with progress UI already embedded
        const modalBody = `
                    <div style="text-align: center; color: var(--brand-white); margin-bottom: 16px;">
                        <div style="font-size: 48px; margin-bottom: 12px;">📊</div>
                        <div style="font-size: 16px; font-weight: 600; margin-bottom: 8px;">Enriching ${selected.length} Keywords</div>
                        <div style="font-size: 13px; color: var(--brand-gray-light);">
                            Please keep this window open while enrichment is in progress...
                        </div>
                    </div>
                    ${processor.getHTML()}
                `;

        // Open modal and hide confirm button immediately, then start
        $('#modal-title').text('📊 Enriching Keywords');
        $('#modal-body').html(modalBody);
        $('#modal-confirm').hide(); // Hide the button completely
        $('#wisewand-modal').fadeIn(200);

        // Start processing after modal is visible
        setTimeout(function () {
            processor.start();
        }, 300);
    });

    // Bulk Schedule (works from both bars)
    $(document).on('click', '.bulk-schedule-btn', function () {
        // CRITICAL FIX: Only collect VISIBLE checked keywords (respects filters)
        const selected = $('.select-keyword-row:visible:checked').map(function () {
            return $(this).val();
        }).get();

        if (selected.length === 0) return;

        const modalBody = `
                    <div class="modal-info">
                        📅 Schedule ${selected.length} keyword(s) for publication?<br><br>
                        Keywords will be added to the Editorial Calendar with smart priority-based scheduling (1 per day).
                    </div>
                `;

        showModal('📅 Schedule Keywords', modalBody, '📅 Schedule ' + selected.length, function () {
            $('#modal-confirm').prop('disabled', true).text('📅 Scheduling...');

            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_schedule_saved_keywords',
                    keyword_ids: selected,
                    nonce: wisewandSEO.nonce
                },
                success: function (response) {
                    if (response.success) {
                        showSuccessModal('✅ Scheduled', response.data.scheduled + ' keyword(s) scheduled! View them in the Editorial Calendar.');
                        $('.select-keyword-row:visible:checked').prop('checked', false);
                        updateBulkActionsBar();
                    } else {
                        showErrorModal('❌ Scheduling Failed', response.data?.message || 'Failed');
                    }
                }
            });
        });
    });

    // Bulk Delete (works from both bars)
    $(document).on('click', '.bulk-delete-btn', function () {
        // CRITICAL FIX: Only collect VISIBLE checked keywords (respects filters)
        const selected = $('.select-keyword-row:visible:checked').map(function () {
            return $(this).val();
        }).get();

        if (selected.length === 0) return;

        let warningText = '';
        if (selected.length > 1000) {
            warningText = '<div class="modal-info"><strong>⚠️ Large Operation:</strong><br>Deleting ' + selected.length + ' keywords will be processed in chunks to prevent timeouts.</div>';
        }

        const modalBody = `
                    ${warningText}
                    <div class="modal-error">
                        🗑️ Delete ${selected.length} keyword(s) from library?<br><br>
                        <strong>This action cannot be undone.</strong><br><br>
                        Scheduled publications for these keywords will NOT be affected.
                    </div>
                    <div id="delete-progress" style="display: none;">
                        <div style="background: #f3f4f6; border-radius: 8px; height: 8px; margin: 16px 0;">
                            <div id="delete-progress-bar" style="background: #ef4444; height: 100%; border-radius: 8px; width: 0%; transition: width 0.3s;"></div>
                        </div>
                        <div id="delete-status">Starting deletion...</div>
                    </div>
                `;

        showModal('🗑️ Delete Keywords', modalBody, '🗑️ Delete ' + selected.length, function () {
            $('#modal-confirm').prop('disabled', true);
            $('#delete-progress').show();

            if (selected.length <= 100) {
                // Small batch - delete directly
                deleteKeywordsBatch(selected, 0, selected.length);
            } else {
                // Large batch - process in chunks
                deleteKeywordsInChunks(selected);
            }
        });
    });

    function deleteKeywordsBatch(allIds, processed, total) {
        const chunkSize = 100;
        const chunk = allIds.slice(processed, processed + chunkSize);

        if (chunk.length === 0) {
            // All done
            showSuccessModal('✅ Deleted', 'All ' + total + ' keyword(s) deleted successfully');
            setTimeout(() => location.reload(), 1500);
            return;
        }

        const progress = Math.round((processed / total) * 100);
        $('#delete-progress-bar').css('width', progress + '%');
        $('#delete-status').text('Deleting ' + (processed + 1) + '-' + Math.min(processed + chunkSize, total) + ' of ' + total + '...');

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_bulk_delete_saved_keywords',
                keyword_ids: chunk,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    // Continue with next chunk
                    setTimeout(() => {
                        deleteKeywordsBatch(allIds, processed + chunkSize, total);
                    }, 500);
                } else {
                    showErrorModal('❌ Delete Failed', 'Failed at batch ' + (Math.floor(processed / chunkSize) + 1));
                }
            },
            error: function (xhr) {
                console.error('Delete error:', xhr);
                showErrorModal('❌ Delete Error', 'HTTP ' + xhr.status + ' - Check server logs');
            }
        });
    }

    function deleteKeywordsInChunks(allIds) {
        deleteKeywordsBatch(allIds, 0, allIds.length);
    }

    // Delete individual keyword
    $(document).on('click', '.btn-delete-keyword', function () {
        const keywordId = $(this).data('keyword-id');
        const keyword = $(this).data('keyword');

        const modalBody = `
                    <div class="modal-error">
                        Delete keyword: <strong>"${keyword}"</strong>?<br><br>
                        This will remove it from your saved library.
                    </div>
                `;

        showModal('🗑️ Delete Keyword', modalBody, '🗑️ Delete', function () {
            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_delete_saved_keyword',
                    keyword_id: keywordId,
                    nonce: wisewandSEO.nonce
                },
                success: function (response) {
                    if (response.success) {
                        closeModal();
                        $('[data-keyword-id="' + keywordId + '"]').fadeOut();
                        setTimeout(() => loadLatestSnapshot(), 500);
                    }
                }
            });
        });
    });

    // Edit keyword inline
    $(document).on('click', '.btn-edit', function () {
        const keywordId = $(this).data('keyword-id');
        const $row = $(this).closest('tr');

        // Get current values
        const currentKeyword = $row.find('.col-keyword strong').text();
        const currentVolume = $row.find('.col-volume').data('volume') || 0;
        const currentDifficulty = $row.find('.col-difficulty').data('difficulty') || '';

        const modalBody = `
                    <div class="modal-form-group">
                        <label>Keyword</label>
                        <input type="text" id="edit-keyword" class="modal-input" value="${currentKeyword}">
                    </div>
                    <div class="modal-form-group">
                        <label>Search Volume</label>
                        <input type="number" id="edit-volume" class="modal-input" value="${currentVolume}">
                    </div>
                    <div class="modal-form-group">
                        <label>Difficulty (0-100)</label>
                        <input type="number" id="edit-difficulty" class="modal-input" value="${currentDifficulty}" min="0" max="100">
                    </div>
                `;

        showModal('✏️ Edit Keyword', modalBody, '💾 Save Changes', function () {
            const updates = {
                keyword: $('#edit-keyword').val(),
                search_volume: parseInt($('#edit-volume').val()) || 0,
                difficulty: parseInt($('#edit-difficulty').val()) || null,
            };

            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_update_saved_keyword',
                    keyword_id: keywordId,
                    updates: updates,
                    nonce: wisewandSEO.nonce
                },
                success: function (response) {
                    if (response.success) {
                        showSuccessModal('✅ Updated', 'Keyword updated successfully');
                        setTimeout(() => location.reload(), 1000);
                    } else {
                        showErrorModal('❌ Update Failed', response.data?.message || 'Failed');
                    }
                }
            });
        });
    });

    function runRealAnalysis() {
        const [language, location] = $('#market-selector').val().split(':');
        const $btn = $('#run-analysis');

        $btn.prop('disabled', true).text('🔄 Analyzing...');
        $('#analysis-status').show();

        updateProgress(10, 'Fetching current rankings...');

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_run_real_analysis',
                domain: wisewandSEO.domain,
                language_code: language,
                location_code: parseInt(location),
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    updateProgress(100, 'Analysis complete!');
                    displayResults(response.data);
                    updateMetrics(response.data.metrics);
                } else {
                    let errorMsg = getDataForSEOErrorMessage(response);
                    if (response.data?.debug) {
                        console.log('Debug info:', response.data.debug);
                        if (!response.data.debug.credentials_configured) {
                            errorMsg = 'Please configure your DataForSEO credentials in Settings';
                        }
                    }
                    updateProgress(0, 'Analysis failed: ' + errorMsg);
                }
            },
            error: function (xhr, status, error) {
                console.error('AJAX error:', xhr.responseText);
                let errorMsg = 'Connection error';
                if (xhr.status === 403) {
                    errorMsg = 'Permission denied - please check your user permissions';
                } else if (xhr.status === 500) {
                    errorMsg = 'Server error - check the logs for details';
                } else if (error) {
                    errorMsg += ': ' + error;
                }
                updateProgress(0, errorMsg);
            },
            complete: function () {
                $btn.prop('disabled', false).text('🚀 Run SEO Analysis');
                setTimeout(() => $('#analysis-status').hide(), 3000);
                fetchDataForSEOBalance(); // Refresh balance after API usage
            }
        });
    }

    function updateProgress(percentage, text) {
        $('#progress-fill').css('width', percentage + '%');
        $('#status-text').text(text);
    }

    function displayResults(data) {
        $('#results-content').html(data.html);
    }

    function updateMetrics(metrics) {
        $('#current-rankings').text(metrics.current_rankings || 0);
        $('#new-opportunities').text(metrics.new_opportunities || 0);
        $('#quick-wins').text(metrics.quick_wins || 0);
        $('#top-performers').text(metrics.top_performers || 0);
    }

    // Auto-load latest snapshot on page load
    loadLatestSnapshot();

    function loadLatestSnapshot() {
        const [language, location] = $('#market-selector').val().split(':');

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_load_latest_snapshot',
                domain: wisewandSEO.domain,
                language_code: language,
                location_code: parseInt(location),
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    // If show_empty flag is set, keep the empty state visible
                    if (response.data.show_empty) {
                        $('#initial-empty-state').show();
                        return;
                    }

                    // If we have data, display it
                    if (response.data.html) {
                        $('#initial-empty-state').hide();
                        displayResults(response.data);
                        updateMetrics(response.data.metrics);
                    }
                }
            }
        });
    }

    // Sortable table headers
    $(document).on('click', '.seo-table th.sortable', function () {
        const $this = $(this);
        const sortBy = $this.data('sort');
        const $table = $this.closest('table');
        const $tbody = $table.find('tbody');
        const $rows = $tbody.find('tr').toArray();

        // Toggle sort direction
        const isAsc = $this.hasClass('sort-asc');
        $table.find('th').removeClass('sort-asc sort-desc');
        $this.addClass(isAsc ? 'sort-desc' : 'sort-asc');

        // Sort rows
        $rows.sort(function (a, b) {
            let aVal, bVal;

            switch (sortBy) {
                case 'keyword':
                    aVal = $(a).find('.col-keyword strong').text().toLowerCase();
                    bVal = $(b).find('.col-keyword strong').text().toLowerCase();
                    break;
                case 'categories':
                    // Sort by categories (empty first when ascending, last when descending)
                    const aCatIds = $(a).find('.col-categories .open-category-modal').data('category-ids');
                    const bCatIds = $(b).find('.col-categories .open-category-modal').data('category-ids');

                    // Check if empty
                    const aIsEmpty = !aCatIds || aCatIds.length === 0 ||
                        (Array.isArray(aCatIds) && aCatIds.length === 0) ||
                        aCatIds === '[]';
                    const bIsEmpty = !bCatIds || bCatIds.length === 0 ||
                        (Array.isArray(bCatIds) && bCatIds.length === 0) ||
                        bCatIds === '[]';

                    // Empty sorting logic
                    if (aIsEmpty && !bIsEmpty) return isAsc ? -1 : 1; // Empty first when ascending
                    if (!aIsEmpty && bIsEmpty) return isAsc ? 1 : -1;
                    if (aIsEmpty && bIsEmpty) return 0; // Both empty

                    // Both have categories - sort by first category name alphabetically
                    const aText = $(a).find('.col-categories span').first().text().toLowerCase() || '';
                    const bText = $(b).find('.col-categories span').first().text().toLowerCase() || '';

                    aVal = aText;
                    bVal = bText;
                    break;
                case 'position':
                    aVal = parseInt($(a).find('.col-position').data('position')) || 999;
                    bVal = parseInt($(b).find('.col-position').data('position')) || 999;
                    break;
                case 'volume':
                    aVal = parseInt($(a).find('.col-volume').data('volume')) || 0;
                    bVal = parseInt($(b).find('.col-volume').data('volume')) || 0;
                    break;
                case 'difficulty':
                    aVal = parseInt($(a).find('.col-difficulty').data('difficulty')) || 0;
                    bVal = parseInt($(b).find('.col-difficulty').data('difficulty')) || 0;
                    break;
                case 'priority':
                    aVal = parseInt($(a).find('.col-priority').data('priority')) || 0;
                    bVal = parseInt($(b).find('.col-priority').data('priority')) || 0;
                    break;
                default:
                    return 0;
            }

            if (aVal < bVal) return isAsc ? 1 : -1;
            if (aVal > bVal) return isAsc ? -1 : 1;
            return 0;
        });

        // Reattach rows
        $.each($rows, function (index, row) {
            $tbody.append(row);
        });

        // Update sort arrow
        $table.find('.sort-arrow').text('');
        $this.find('.sort-arrow').text(isAsc ? ' ▼' : ' ▲');
    });

    // Saved Keywords: Save to library
    $('#save-keywords, #save-and-enrich').on('click', function () {
        const $btn = $(this);
        const keywords = $('#saved-keywords-input').val().trim();
        const autoEnrich = $btn.attr('id') === 'save-and-enrich';

        if (!keywords) {
            alert('Please enter at least one keyword');
            return;
        }

        $btn.prop('disabled', true).text(autoEnrich ? '📊 Saving & Enriching...' : '💾 Saving...');

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_save_keywords_to_library',
                keywords: keywords,
                auto_enrich: autoEnrich ? 1 : 0,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    $('#saved-keywords-input').val('');
                    $('#saved-keywords-feedback').html(
                        '<div class="feedback-success">✅ Saved ' + response.data.saved_count + ' keyword(s). ' +
                        (response.data.skipped_count > 0 ? response.data.skipped_count + ' skipped (duplicates).' : '') +
                        '</div>'
                    );
                    $('#saved-keywords-list').html(response.data.list_html);

                    // Refresh results if analysis is showing
                    if ($('#results-content table').length > 0) {
                        loadLatestSnapshot();
                    }
                } else {
                    $('#saved-keywords-feedback').html('<div class="feedback-error">❌ ' + (response.data?.message || 'Failed') + '</div>');
                }
            },
            error: function () {
                $('#saved-keywords-feedback').html('<div class="feedback-error">❌ Connection error</div>');
            },
            complete: function () {
                $btn.prop('disabled', false).text(autoEnrich ? '📊 Save & Enrich with SEO Data' : '💾 Save to Library');
            }
        });
    });

    // Select all saved keywords (use event delegation since table is dynamically loaded)
    $(document).on('change', '#select-all-saved', function () {
        const isChecked = $(this).is(':checked');
        $('.select-saved-keyword').prop('checked', isChecked);
        console.log('Select all toggled:', isChecked, 'Found checkboxes:', $('.select-saved-keyword').length);
    });

    // Schedule single saved keyword
    $(document).on('click', '.btn-schedule-saved', function () {
        const keywordId = $(this).data('keyword-id');
        scheduleStyledKeyword(keywordId, $(this));
    });

    // Delete single saved keyword
    $(document).on('click', '.btn-delete-saved', function () {
        const keywordId = $(this).data('keyword-id');

        if (!confirm('Delete this saved keyword?')) return;

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_delete_saved_keyword',
                keyword_id: keywordId,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    $('[data-keyword-id="' + keywordId + '"]').fadeOut();
                    setTimeout(() => location.reload(), 500);
                }
            }
        });
    });

    // Enrichment Batch Processor for Saved Keywords (Global Scope - defined here before use)
    class EnrichmentBatchProcessor {
        constructor(keywordIds) {
            this.keywordIds = keywordIds;
            this.batchSize = 10; // Process 10 keywords per batch (enrichment involves API calls)
            this.currentBatch = 0;
            this.totalBatches = Math.ceil(keywordIds.length / this.batchSize);
            this.totalEnriched = 0;
            this.totalFailed = 0;
        }

        getHTML() {
            return `
                        <div id="enrich-progress-container" style="margin-top: 12px;">
                            <div style="background: rgba(10, 14, 39, 0.6); border: 1px solid rgba(16, 185, 129, 0.2); border-radius: 16px; padding: 20px; backdrop-filter: blur(10px);">
                                <!-- Progress Bar -->
                                <div style="margin-bottom: 20px;">
                                    <div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
                                        <span style="font-size: 13px; font-weight: 600; color: var(--brand-white); letter-spacing: 0.05em; text-transform: uppercase;">Enrichment Progress</span>
                                        <span id="enrich-progress-text" style="font-size: 13px; color: var(--brand-success); font-weight: 600;">0 / ${this.keywordIds.length} keywords</span>
                                    </div>
                                    <div style="background: rgba(160, 168, 184, 0.15); border-radius: 12px; height: 10px; overflow: hidden; border: 1px solid rgba(16, 185, 129, 0.2);">
                                        <div id="enrich-progress-bar" style="background: linear-gradient(90deg, var(--brand-success) 0%, var(--brand-primary) 100%); height: 100%; width: 0%; transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 0 12px rgba(16, 185, 129, 0.5);"></div>
                                    </div>
                                </div>

                                <!-- Current Status -->
                                <div id="enrich-current-status" style="background: rgba(16, 185, 129, 0.1); border-radius: 12px; padding: 16px; margin-bottom: 16px; border-left: 4px solid var(--brand-success); backdrop-filter: blur(10px);">
                                    <div style="font-weight: 600; color: var(--brand-white); margin-bottom: 6px; font-size: 15px;">Starting...</div>
                                    <div id="enrich-status-detail" style="font-size: 13px; color: var(--brand-gray-light);"></div>
                                </div>

                                <!-- Progress Steps Log -->
                                <div id="enrich-progress-steps" style="height: 290px; overflow-y: auto; font-size: 12px; font-family: 'Consolas', 'Monaco', monospace; background: #0A0E27; color: #E2E8F0; padding: 16px; border-radius: 12px; line-height: 1.8; border: 1px solid rgba(16, 185, 129, 0.3); box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.3);">
                                    <div style="color: var(--brand-success);">● Initializing enrichment process...</div>
                                    <div style="color: var(--brand-gray-light);">→ Total keywords: ${this.keywordIds.length}</div>
                                    <div style="color: var(--brand-gray-light);">→ Batch size: ${this.batchSize} keywords per batch</div>
                                    <div style="color: var(--brand-gray-light);">→ Total batches: ${this.totalBatches}</div>
                                    <div style="color: var(--brand-gray-light);">→ Fetching: search volume, difficulty, priority, intent...</div>
                                </div>
                            </div>

                            <!-- Warning at Bottom -->
                            <div style="margin-top: 12px; padding: 10px 14px; background: rgba(245, 158, 11, 0.15); border-left: 3px solid var(--brand-warning); border-radius: 8px; font-size: 11px; color: var(--brand-white); line-height: 1.5; backdrop-filter: blur(10px); border: 1px solid rgba(245, 158, 11, 0.3);">
                                ⚠️ <strong style="color: var(--brand-warning);">Keep window open</strong> - Enriching ${this.keywordIds.length} keywords with DataForSEO metrics (${this.totalBatches} batches)
                            </div>
                        </div>
                    `;
        }

        start() {
            this.processNextBatch();
        }

        processNextBatch() {
            if (this.currentBatch >= this.totalBatches) {
                this.showComplete();
                return;
            }

            const batchNumber = this.currentBatch + 1;
            const startIdx = this.currentBatch * this.batchSize;
            const endIdx = Math.min(startIdx + this.batchSize, this.keywordIds.length);
            const batchIds = this.keywordIds.slice(startIdx, endIdx);

            const progress = Math.round((startIdx / this.keywordIds.length) * 100);

            $('#enrich-progress-bar').css('width', progress + '%');
            $('#enrich-progress-text').text(`${startIdx} / ${this.keywordIds.length} keywords`);
            $('#enrich-current-status div:first').html(`Processing batch ${batchNumber} of ${this.totalBatches}...`);
            $('#enrich-status-detail').html(`Enriching keywords ${startIdx + 1} to ${endIdx} with SEO metrics...`);

            this.addLog(`<span style="color: var(--brand-primary);">● Batch ${batchNumber}/${this.totalBatches}</span> - Enriching ${batchIds.length} keywords...`);

            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_enrich_saved_keywords',
                    keyword_ids: batchIds,
                    nonce: wisewandSEO.nonce
                },
                success: (response) => {
                    if (response.success) {
                        const enriched = response.data.enriched || 0;
                        const failed = batchIds.length - enriched;

                        this.totalEnriched += enriched;
                        this.totalFailed += failed;

                        if (failed > 0) {
                            this.addLog(`  <span style="color: var(--brand-warning);">⚠ Batch ${batchNumber}:</span> ${enriched} enriched, ${failed} failed (may already be enriched)`);
                        } else {
                            this.addLog(`  <span style="color: var(--brand-success);">✓ Batch ${batchNumber} complete:</span> ${enriched} keywords enriched successfully`);
                        }

                        this.currentBatch++;
                        setTimeout(() => this.processNextBatch(), 500); // 500ms delay between batches
                    } else {
                        this.addLog(`  <span style="color: var(--brand-error);">✗ Batch ${batchNumber} failed:</span> ${response.data?.message || 'Unknown error'}`);
                        this.showError(response.data?.message || 'Failed to enrich batch');
                    }
                },
                error: (xhr, status, error) => {
                    console.error('Batch enrichment error:', xhr, error);
                    this.addLog(`  <span style="color: var(--brand-error);">✗ Batch ${batchNumber} error:</span> ${error}`);
                    this.showError('Network error. Please try again.');
                }
            });
        }

        addLog(message) {
            const $log = $('#enrich-progress-steps');
            $log.append('<div>' + message + '</div>');
            $log.scrollTop($log[0].scrollHeight);
        }

        showComplete() {
            $('#enrich-progress-bar').css('width', '100%').css('box-shadow', '0 0 20px rgba(16, 185, 129, 0.6)');
            $('#enrich-progress-text').text(`${this.keywordIds.length} / ${this.keywordIds.length} keywords`);
            $('#enrich-current-status div:first').html('✅ Enrichment Complete!');
            $('#enrich-status-detail').html(`Total: ${this.totalEnriched} enriched successfully`);

            this.addLog('');
            this.addLog('<span style="color: var(--brand-success); font-weight: 600;">✅ ENRICHMENT COMPLETE!</span>');
            this.addLog(`<span style="color: var(--brand-white);">→ Total Processed:</span> ${this.keywordIds.length} keywords`);
            this.addLog(`<span style="color: var(--brand-success);">→ Successfully Enriched:</span> ${this.totalEnriched}`);

            if (this.totalFailed > 0) {
                this.addLog(`<span style="color: var(--brand-warning);">→ Failed/Already Enriched:</span> ${this.totalFailed}`);
            }

            $('#modal-confirm').text('✅ Done').prop('disabled', false);

            // Reload page to show updated data
            setTimeout(function () {
                location.reload();
            }, 2000);
        }

        showError(message) {
            $('#enrich-current-status').html(`
                        <div style="font-weight: 600; color: var(--brand-error); margin-bottom: 6px; font-size: 15px;">❌ Error</div>
                        <div style="font-size: 13px; color: var(--brand-gray-light);">${message}</div>
                    `);
            $('#modal-confirm').text('❌ Failed').prop('disabled', false);
        }
    }

    // Schedule selected keywords
    $('#schedule-selected').on('click', function () {
        const selected = $('.select-saved-keyword:checked').map(function () {
            return $(this).val();
        }).get();

        if (selected.length === 0) {
            alert('Please select keywords to schedule');
            return;
        }

        if (!confirm('📅 Schedule ' + selected.length + ' keyword(s) for publication?')) {
            return;
        }

        const $btn = $(this);
        $btn.prop('disabled', true).text('📅 Scheduling...');

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_schedule_saved_keywords',
                keyword_ids: selected,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    alert('✅ Scheduled ' + response.data.scheduled + ' keyword(s)!\n\nView them in the Editorial Calendar.');
                } else {
                    alert('❌ ' + (response.data?.message || 'Failed'));
                }
            },
            complete: function () {
                $btn.prop('disabled', false).text('📅 Schedule Selected');
            }
        });
    });

    // Delete selected keywords
    $('#delete-selected').on('click', function () {
        const selected = $('.select-saved-keyword:checked').map(function () {
            return $(this).val();
        }).get();

        if (selected.length === 0) {
            alert('Please select keywords to delete');
            return;
        }

        if (!confirm('🗑️ Delete ' + selected.length + ' keyword(s)?\n\nThis action cannot be undone.')) {
            return;
        }

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_bulk_delete_saved_keywords',
                keyword_ids: selected,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    alert('✅ Deleted ' + response.data.deleted + ' keyword(s)');
                    location.reload();
                }
            }
        });
    });

    function scheduleStyledKeyword(keywordId, $btn) {
        // First, get the keyword text
        const keyword = $btn.closest('tr').find('.col-keyword strong').text();

        $btn.prop('disabled', true).text('⏳');

        // Check for cannibalization before scheduling
        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_check_cannibalization',
                keyword: keyword,
                keyword_id: keywordId,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success && response.data.has_warnings) {
                    // Show warning modal
                    showCannibalizationWarning(keyword, keywordId, response.data.warnings, $btn);
                } else {
                    // No warnings, proceed directly
                    proceedWithScheduling(keywordId, $btn);
                }
            },
            error: function () {
                // If check fails, proceed anyway (don't block user)
                proceedWithScheduling(keywordId, $btn);
            }
        });
    }

    function proceedWithScheduling(keywordId, $btn) {
        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_schedule_saved_keyword',
                keyword_id: keywordId,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    $btn.text('✓').css('background', '#6b7280');
                    alert('✅ Scheduled for ' + response.data.publication_date);
                } else {
                    alert('❌ ' + (response.data?.message || 'Failed'));
                    $btn.prop('disabled', false).text('📅');
                }
            },
            error: function () {
                $btn.prop('disabled', false).text('📅');
            }
        });
    }

    function showCannibalizationWarning(keyword, keywordId, warnings, $originalBtn) {
        const calendarWarnings = warnings.calendar || [];
        const postsWarnings = warnings.posts || [];
        const clustersWarnings = warnings.clusters || [];

        let warningsHTML = '';

        // Calendar conflicts
        if (calendarWarnings.length > 0) {
            warningsHTML += '<div style="margin-bottom: 16px;"><div style="font-weight: 600; color: var(--brand-warning); margin-bottom: 8px;">📅 Similar Keywords in Calendar:</div>';
            calendarWarnings.forEach(w => {
                warningsHTML += `
                            <div style="padding: 8px 12px; background: rgba(245, 158, 11, 0.1); border-left: 3px solid var(--brand-warning); border-radius: 6px; margin-bottom: 6px;">
                                <div style="font-size: 13px; color: var(--brand-white);">"${escapeHtml(w.keyword)}"</div>
                                <div style="font-size: 11px; color: var(--brand-gray-light); margin-top: 2px;">
                                    ${w.similarity}% similar | Scheduled: ${w.date} | Status: ${w.status}
                                </div>
                            </div>
                        `;
            });
            warningsHTML += '</div>';
        }

        // Published posts conflicts
        if (postsWarnings.length > 0) {
            warningsHTML += '<div style="margin-bottom: 16px;"><div style="font-weight: 600; color: var(--brand-error); margin-bottom: 8px;">📝 Similar Keywords in Published Posts:</div>';
            postsWarnings.forEach(w => {
                warningsHTML += `
                            <div style="padding: 8px 12px; background: rgba(239, 68, 68, 0.1); border-left: 3px solid var(--brand-error); border-radius: 6px; margin-bottom: 6px;">
                                <div style="font-size: 13px; color: var(--brand-white);">"${escapeHtml(w.title)}"</div>
                                <div style="font-size: 11px; color: var(--brand-gray-light); margin-top: 2px;">
                                    ${w.similarity}% similar | Published: ${w.date.substring(0, 10)} | <a href="${w.edit_url}" target="_blank" style="color: var(--brand-primary);">Edit Post →</a>
                                </div>
                            </div>
                        `;
            });
            warningsHTML += '</div>';
        }

        // Cluster conflicts
        if (clustersWarnings.length > 0) {
            warningsHTML += '<div style="margin-bottom: 16px;"><div style="font-weight: 600; color: var(--brand-purple); margin-bottom: 8px;">🔗 Part of Keyword Cluster:</div>';
            clustersWarnings.forEach(w => {
                warningsHTML += `
                            <div style="padding: 8px 12px; background: rgba(139, 92, 246, 0.1); border-left: 3px solid var(--brand-purple); border-radius: 6px;">
                                <div style="font-size: 13px; color: var(--brand-white);">Primary: "${escapeHtml(w.primary_keyword)}"</div>
                                <div style="font-size: 11px; color: var(--brand-gray-light); margin-top: 2px;">
                                    ${w.variant_count} variants in cluster
                                </div>
                            </div>
                        `;
            });
            warningsHTML += '</div>';
        }

        const modalBody = `
                    <div style="text-align: center; color: var(--brand-white); margin-bottom: 20px;">
                        <div style="font-size: 48px; margin-bottom: 12px;">⚠️</div>
                        <div style="font-size: 18px; font-weight: 700; margin-bottom: 8px;">Cannibalization Risk Detected</div>
                        <div style="font-size: 13px; color: var(--brand-gray-light);">
                            Scheduling "${keyword}" may compete with existing content
                        </div>
                    </div>

                    ${warningsHTML}

                    <div style="background: rgba(0, 188, 212, 0.1); padding: 12px; border-radius: 8px; border-left: 3px solid var(--brand-primary); margin-top: 16px;">
                        <div style="font-size: 12px; color: var(--brand-white); font-weight: 600; margin-bottom: 4px;">💡 Recommendation:</div>
                        <div style="font-size: 11px; color: var(--brand-gray-light); line-height: 1.6;">
                            Consider reviewing similar keywords before scheduling to avoid content cannibalization.
                            You can still proceed if this keyword targets a different intent or angle.
                        </div>
                    </div>
                `;

        showModal('⚠️ Cannibalization Warning', modalBody, 'Schedule Anyway', function () {
            // User confirmed, proceed with scheduling
            proceedWithScheduling(keywordId, $originalBtn);
            closeModal();
        });
    }

    // Combined filter functionality
    function applyKeywordFilters() {
        const sourceFilter = $('#keyword-filter').val();
        const languageFilter = $('#language-filter').val();
        const $rows = $('.seo-table tbody tr');

        $rows.each(function () {
            const $row = $(this);
            let show = true;

            // Source filter
            if (sourceFilter !== 'all') {
                switch (sourceFilter) {
                    case 'current':
                    case 'opportunities':
                    case 'saved':
                    case 'seed':
                    case 'ideas':
                    case 'competitor_spy':
                        if ($row.attr('data-type') !== sourceFilter) show = false;
                        break;
                    case 'quick-wins':
                        const pos = parseInt($row.find('[data-position]').data('position')) || 999;
                        if (pos < 11 || pos > 20) show = false;
                        break;
                    case 'high-volume':
                        const vol = parseInt($row.find('[data-volume]').data('volume')) || 0;
                        if (vol < 1000) show = false;
                        break;
                }
            }

            // Language filter
            if (languageFilter !== 'all' && show) {
                const rowLang = $row.attr('data-language') || 'en';
                if (rowLang !== languageFilter) show = false;
            }

            $row.toggle(show);
        });
    }

    $('#keyword-filter').on('change', applyKeywordFilters);
    $('#language-filter').on('change', applyKeywordFilters);

    // Discover keywords button (with pre-flight balance check)
    $('#discover-keywords').on('click', function () {
        const $btn = $(this);
        checkBalanceBeforeAction(function () {
            discoverKeywords($btn);
        });
    });

    function discoverKeywords($btn) {
        const [language, location] = $('#market-selector').val().split(':');

        $btn.prop('disabled', true).text('🔍 Discovering...');
        $('#discovery-results').html('<div class="loading">Loading new keyword opportunities...</div>');

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_discover_keywords',
                domain: wisewandSEO.domain,
                language_code: language,
                location_code: parseInt(location),
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    $('#discovery-results').html(response.data.html);
                } else {
                    $('#discovery-results').html('<div class="error-message">❌ ' + (response.data?.message || 'Discovery failed') + '</div>');
                }
            },
            error: function () {
                $('#discovery-results').html('<div class="error-message">❌ Connection error</div>');
            },
            complete: function () {
                $btn.prop('disabled', false).text('🔍 Find New Keywords');
            }
        });
    }

    // Add discovered keyword to calendar
    $(document).on('click', '.btn-add-discovery', function () {
        const $btn = $(this);
        const keywordData = JSON.parse($btn.attr('data-keyword'));

        $btn.prop('disabled', true).text('Adding...');

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_schedule_keyword',
                keyword_data: keywordData,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    $btn.text('✓ Added').css('background', '#6b7280');
                    alert('✅ Scheduled for ' + response.data.publication_date);
                } else {
                    alert('❌ ' + (response.data?.message || 'Failed'));
                    $btn.prop('disabled', false).text('➕ Add');
                }
            },
            error: function () {
                $btn.prop('disabled', false).text('➕ Add');
            }
        });
    });

    // Keyword Ideas Progress Manager (Global Scope)
    class KeywordIdeasProgress {
        constructor(totalSeeds, seedsText, language, location) {
            this.totalSeeds = totalSeeds;
            this.seedsText = seedsText;
            this.language = language;
            this.location = location;
            this.currentSeed = 0;
            this.stats = {
                totalIdeas: 0,
                totalEnriched: 0,
                totalSaved: 0,
                totalSkipped: 0
            };
        }

        getHTML() {
            return `
                            <div id="ideas-progress-container" style="margin-top: 12px;">
                                <div style="background: rgba(10, 14, 39, 0.6); border: 1px solid rgba(0, 188, 212, 0.2); border-radius: 16px; padding: 20px; backdrop-filter: blur(10px);">
                                    <!-- Progress Bar -->
                                    <div style="margin-bottom: 20px;">
                                        <div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
                                            <span style="font-size: 13px; font-weight: 600; color: var(--brand-white); letter-spacing: 0.05em; text-transform: uppercase;">Overall Progress</span>
                                            <span id="overall-progress-text" style="font-size: 13px; color: var(--brand-primary); font-weight: 600;">0 / ${this.totalSeeds} seeds</span>
                                        </div>
                                        <div style="background: rgba(160, 168, 184, 0.15); border-radius: 12px; height: 10px; overflow: hidden; border: 1px solid rgba(0, 188, 212, 0.2);">
                                            <div id="ideas-progress-bar" style="background: linear-gradient(90deg, var(--brand-primary) 0%, var(--brand-success) 100%); height: 100%; width: 0%; transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 0 12px rgba(0, 188, 212, 0.5);"></div>
                                        </div>
                                    </div>

                                    <!-- Current Status -->
                                    <div id="current-status" style="background: rgba(0, 188, 212, 0.1); border-radius: 12px; padding: 16px; margin-bottom: 16px; border-left: 4px solid var(--brand-primary); backdrop-filter: blur(10px);">
                                        <div style="font-weight: 600; color: var(--brand-white); margin-bottom: 6px; font-size: 15px;">Starting process...</div>
                                        <div id="status-detail" style="font-size: 13px; color: var(--brand-gray-light);"></div>
                                    </div>

                                    <!-- Progress Steps Log -->
                                    <div id="progress-steps" style="height: 290px; overflow-y: auto; font-size: 12px; font-family: 'Consolas', 'Monaco', monospace; background: #0A0E27; color: #E2E8F0; padding: 16px; border-radius: 12px; line-height: 1.8; border: 1px solid rgba(0, 188, 212, 0.3); box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.3);">
                                        <div style="color: var(--brand-primary);">● Initializing keyword enrichment...</div>
                                    </div>
                                </div>

                                <!-- Discreet Warning at Bottom -->
                                <div style="margin-top: 12px; padding: 10px 14px; background: rgba(245, 158, 11, 0.15); border-left: 3px solid var(--brand-warning); border-radius: 8px; font-size: 11px; color: var(--brand-white); line-height: 1.5; backdrop-filter: blur(10px); border: 1px solid rgba(245, 158, 11, 0.3);">
                                    ⚠️ <strong style="color: var(--brand-warning);">Keep window open</strong> - Enriching keywords with DataForSEO volume, difficulty & priority metrics
                                </div>
                            </div>
                        `;
        }

        start() {
            this.processNextSeed();
        }

        processNextSeed() {
            if (this.currentSeed >= this.totalSeeds) {
                this.showComplete();
                return;
            }

            const seedNumber = this.currentSeed + 1;
            const progress = Math.round((this.currentSeed / this.totalSeeds) * 100);

            $('#ideas-progress-bar').css('width', progress + '%');
            $('#overall-progress-text').text(`${seedNumber} / ${this.totalSeeds} seeds`);

            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_get_keyword_ideas',
                    seeds: this.seedsText,
                    seed_index: this.currentSeed,
                    language_code: this.language,
                    location_code: this.location,
                    nonce: wisewandSEO.nonce
                },
                success: (response) => {
                    if (response.success) {
                        this.updateProgress(response.data);
                        this.stats.totalIdeas += response.data.ideas_found || 0;
                        this.stats.totalEnriched += response.data.ideas_enriched || 0;
                        this.stats.totalSaved += response.data.ideas_saved || 0;
                        this.stats.totalSkipped += response.data.ideas_skipped || 0;

                        this.currentSeed++;
                        setTimeout(() => this.processNextSeed(), 500);
                    } else {
                        this.showError(response.data?.message || 'Unknown error');
                    }
                },
                error: (xhr) => {
                    this.showError('HTTP ' + xhr.status + ' - Connection failed');
                }
            });
        }

        updateProgress(data) {
            const seed = data.seed || 'unknown';
            const seedNum = data.seed_number || 0;

            // Update current status
            $('#current-status').html(`
                            <div style="font-weight: 600; color: var(--brand-white); margin-bottom: 6px; font-size: 15px;">
                                Seed ${seedNum}/${data.total_seeds}: <span style="color: var(--brand-primary);">${this.escapeHtml(seed)}</span>
                            </div>
                            <div style="font-size: 13px; color: var(--brand-gray-light);">
                                <span style="color: var(--brand-primary); font-weight: 600;">${data.ideas_found}</span> ideas found •
                                <span style="color: var(--brand-success); font-weight: 600;">${data.ideas_enriched}</span> enriched •
                                <span style="color: var(--brand-purple); font-weight: 600;">${data.ideas_saved}</span> saved
                            </div>
                        `);

            // Append detailed steps to log
            if (data.steps && Array.isArray(data.steps)) {
                const $log = $('#progress-steps');
                if ($log.length && $log[0]) {
                    const logWasAtBottom = $log[0].scrollHeight - $log.scrollTop() <= $log.outerHeight() + 50;

                    data.steps.forEach(step => {
                        const logEntry = this.formatStepLog(step, seedNum);
                        $log.append(logEntry);
                    });

                    // Auto-scroll to bottom if user was already there
                    if (logWasAtBottom) {
                        $log.scrollTop($log[0].scrollHeight);
                    }
                }
            }
        }

        formatStepLog(step, seedNum) {
            const icons = {
                started: '▸',
                processing: '⋯',
                success: '✓',
                error: '✗',
                warning: '⚠',
                skipped: '○'
            };

            const colors = {
                started: '#00BCD4',
                processing: '#F59E0B',
                success: '#10B981',
                error: '#EF4444',
                warning: '#F59E0B',
                skipped: '#A0A8B8'
            };

            const icon = icons[step.status] || '●';
            const color = colors[step.status] || '#E2E8F0';

            let message = step.message;

            // Add endpoint info if available
            if (step.endpoint) {
                message += ` <span style="color: #8B5CF6; font-size: 10px;">[${step.endpoint}]</span>`;
            }

            // Add progress info for enrich steps
            if (step.progress) {
                message += ` <span style="color: #A0A8B8;">(${step.progress.current}/${step.progress.total})</span>`;
            }

            return `<div style="color: ${color};">${icon} ${this.escapeHtml(message)}</div>`;
        }

        showComplete() {
            $('#ideas-progress-bar').css('width', '100%').css('box-shadow', '0 0 20px rgba(16, 185, 129, 0.6)');
            $('#overall-progress-text').text(`${this.totalSeeds} / ${this.totalSeeds} seeds completed`);

            $('#current-status').html(`
                            <div style="font-weight: 600; color: var(--brand-success); margin-bottom: 8px; font-size: 16px;">✅ All Keywords Enriched!</div>
                            <div style="font-size: 13px; color: var(--brand-white);">
                                <span style="color: var(--brand-primary); font-weight: 600;">📊 ${this.stats.totalIdeas}</span> ideas found •
                                <span style="color: var(--brand-success); font-weight: 600;">✓ ${this.stats.totalEnriched}</span> enriched •
                                <span style="color: var(--brand-purple); font-weight: 600;">💾 ${this.stats.totalSaved}</span> saved •
                                <span style="color: var(--brand-gray-light);">○ ${this.stats.totalSkipped}</span> duplicates
                            </div>
                        `).css('border-left-color', 'var(--brand-success)');

            const $log = $('#progress-steps');
            if ($log.length && $log[0]) {
                $log.append(`<div style="color: var(--brand-success); margin-top: 14px; padding-top: 14px; border-top: 1px solid rgba(0, 188, 212, 0.3); font-weight: 600;">✓ Process completed - All keywords enriched with volume, difficulty & priority data!</div>`);
                $log.scrollTop($log[0].scrollHeight);
            }

            $('#modal-confirm').text('✅ Done').prop('disabled', false);

            setTimeout(() => {
                closeModal();
                loadLatestSnapshot();
            }, 2500);
        }

        showError(message) {
            $('#current-status').html(`
                            <div style="font-weight: 600; color: var(--brand-error); margin-bottom: 6px; font-size: 15px;">❌ Error Occurred</div>
                            <div style="font-size: 13px; color: var(--brand-white);">${this.escapeHtml(message)}</div>
                        `).css('border-left-color', 'var(--brand-error)');

            const $log = $('#progress-steps');
            if ($log.length && $log[0]) {
                $log.append(`<div style="color: var(--brand-error); font-weight: 600;">✗ ERROR: ${this.escapeHtml(message)}</div>`);
                $log.scrollTop($log[0].scrollHeight);
            }

            $('#modal-confirm').prop('disabled', false).text('🔍 Retry');
        }

        escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }
    }

    // Get Keyword Ideas - Show Modal
    $('#get-keyword-ideas, #get-keyword-ideas-empty').on('click', function () {
        const defaultSeeds = $('#keyword-ideas-seeds').val() || '';

        const modalBody = `
                    <div class="modal-form-group">
                        <label>🔍 Enter Main Topics (one per line or comma-separated)</label>
                        <textarea id="modal-keyword-seeds" class="modal-textarea" rows="3" placeholder="wordpress seo\ncontent marketing\nblogging tips">${defaultSeeds}</textarea>
                        <p style="font-size: 11px; color: #94a3b8; margin-top: 6px;">
                            Each seed fetches 10 best ideas. Processed sequentially with real-time progress.
                        </p>
                    </div>
                    <div class="modal-form-group">
                        <label>🌍 Target Market</label>
                        <select id="modal-keyword-location" class="modal-select">
                            ${buildMarketOptions('en:2840')}
                        </select>
                    </div>
                    <div id="modal-feedback"></div>
                `;

        showModal('🔍 Get Keyword Ideas', modalBody, '🔍 Fetch Keyword Ideas', function () {
            const seeds = $('#modal-keyword-seeds').val().trim();
            const [language, location] = $('#modal-keyword-location').val().split(':');

            if (!seeds) {
                $('#modal-feedback').html('<div class="modal-error">Please enter at least one seed keyword</div>');
                return;
            }

            const seedArray = seeds.split(/[\r\n,]+/).map(s => s.trim()).filter(s => s);

            $('#modal-confirm').prop('disabled', true).text('🔍 Processing...');

            const progressUI = new KeywordIdeasProgress(seedArray.length, seeds, language, parseInt(location));
            $('#modal-feedback').html(progressUI.getHTML());

            progressUI.start();
        });
    });

    // Keywords Batch Processor for Add to Library (Global Scope)
    class KeywordsBatchProcessor {
        constructor(keywordsArray, language, location, skipDuplicates, autoEnrich) {
            this.keywordsArray = keywordsArray;
            this.language = language;
            this.location = location;
            this.skipDuplicates = skipDuplicates;
            this.autoEnrich = autoEnrich;
            this.batchSize = 50; // Process 50 keywords per batch
            this.currentBatch = 0;
            this.totalBatches = Math.ceil(keywordsArray.length / this.batchSize);
            this.totalSaved = 0;
            this.totalSkipped = 0;
            this.totalFailed = 0;
        }

        getHTML() {
            return `
                        <div id="batch-progress-container" style="margin-top: 12px;">
                            <div style="background: rgba(10, 14, 39, 0.6); border: 1px solid rgba(139, 92, 246, 0.2); border-radius: 16px; padding: 20px; backdrop-filter: blur(10px);">
                                <!-- Progress Bar -->
                                <div style="margin-bottom: 20px;">
                                    <div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
                                        <span style="font-size: 13px; font-weight: 600; color: var(--brand-white); letter-spacing: 0.05em; text-transform: uppercase;">Saving Progress</span>
                                        <span id="batch-progress-text" style="font-size: 13px; color: var(--brand-purple); font-weight: 600;">0 / ${this.keywordsArray.length} keywords</span>
                                    </div>
                                    <div style="background: rgba(160, 168, 184, 0.15); border-radius: 12px; height: 10px; overflow: hidden; border: 1px solid rgba(139, 92, 246, 0.2);">
                                        <div id="batch-progress-bar" style="background: linear-gradient(90deg, var(--brand-purple) 0%, var(--brand-primary) 100%); height: 100%; width: 0%; transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 0 12px rgba(139, 92, 246, 0.5);"></div>
                                    </div>
                                </div>

                                <!-- Current Status -->
                                <div id="batch-current-status" style="background: rgba(139, 92, 246, 0.1); border-radius: 12px; padding: 16px; margin-bottom: 16px; border-left: 4px solid var(--brand-purple); backdrop-filter: blur(10px);">
                                    <div style="font-weight: 600; color: var(--brand-white); margin-bottom: 6px; font-size: 15px;">Starting...</div>
                                    <div id="batch-status-detail" style="font-size: 13px; color: var(--brand-gray-light);"></div>
                                </div>

                                <!-- Progress Steps Log -->
                                <div id="batch-progress-steps" style="height: 290px; overflow-y: auto; font-size: 12px; font-family: 'Consolas', 'Monaco', monospace; background: #0A0E27; color: #E2E8F0; padding: 16px; border-radius: 12px; line-height: 1.8; border: 1px solid rgba(139, 92, 246, 0.3); box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.3);">
                                    <div style="color: var(--brand-purple);">● Initializing batch processing...</div>
                                    <div style="color: var(--brand-gray-light);">→ Total keywords: ${this.keywordsArray.length}</div>
                                    <div style="color: var(--brand-gray-light);">→ Batch size: ${this.batchSize} keywords per batch</div>
                                    <div style="color: var(--brand-gray-light);">→ Total batches: ${this.totalBatches}</div>
                                </div>
                            </div>

                            <!-- Warning at Bottom -->
                            <div style="margin-top: 12px; padding: 10px 14px; background: rgba(245, 158, 11, 0.15); border-left: 3px solid var(--brand-warning); border-radius: 8px; font-size: 11px; color: var(--brand-white); line-height: 1.5; backdrop-filter: blur(10px); border: 1px solid rgba(245, 158, 11, 0.3);">
                                ⚠️ <strong style="color: var(--brand-warning);">Keep window open</strong> - Processing ${this.keywordsArray.length} keywords in ${this.totalBatches} batches
                            </div>
                        </div>
                    `;
        }

        start() {
            this.processNextBatch();
        }

        processNextBatch() {
            if (this.currentBatch >= this.totalBatches) {
                this.showComplete();
                return;
            }

            const batchNumber = this.currentBatch + 1;
            const startIdx = this.currentBatch * this.batchSize;
            const endIdx = Math.min(startIdx + this.batchSize, this.keywordsArray.length);
            const batchKeywords = this.keywordsArray.slice(startIdx, endIdx);

            const progress = Math.round((startIdx / this.keywordsArray.length) * 100);

            $('#batch-progress-bar').css('width', progress + '%');
            $('#batch-progress-text').text(`${startIdx} / ${this.keywordsArray.length} keywords`);
            $('#batch-current-status div:first').html(`Processing batch ${batchNumber} of ${this.totalBatches}...`);
            $('#batch-status-detail').html(`Saving keywords ${startIdx + 1} to ${endIdx}...`);

            this.addLog(`<span style="color: var(--brand-primary);">● Batch ${batchNumber}/${this.totalBatches}</span> - Processing ${batchKeywords.length} keywords...`);

            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_save_keywords_to_library',
                    keywords: batchKeywords.join('\n'),
                    language_code: this.language,
                    location_code: this.location,
                    skip_duplicates: this.skipDuplicates,
                    auto_enrich: this.autoEnrich,
                    nonce: wisewandSEO.nonce
                },
                success: (response) => {
                    // Validate response structure
                    if (!response || typeof response !== 'object') {
                        console.error('Invalid response format:', response);
                        this.addLog(`  <span style="color: var(--brand-error);">✗ Batch ${batchNumber} error:</span> Invalid response format`);
                        this.showError('Invalid server response. Please try again.');
                        return;
                    }

                    if (response.success) {
                        // Validate response.data exists and has required fields
                        if (!response.data || typeof response.data !== 'object') {
                            console.error('Response missing data object:', response);
                            this.addLog(`  <span style="color: var(--brand-error);">✗ Batch ${batchNumber} error:</span> Invalid response data`);
                            this.showError('Invalid server response data. Please try again.');
                            return;
                        }

                        const savedCount = parseInt(response.data.saved_count) || 0;
                        const skippedCount = parseInt(response.data.skipped_count) || 0;
                        const failedCount = parseInt(response.data.failed_count) || 0;

                        this.totalSaved += savedCount;
                        this.totalSkipped += skippedCount;
                        this.totalFailed += failedCount;

                        // Log with failure count if any
                        if (failedCount > 0) {
                            this.addLog(`  <span style="color: var(--brand-warning);">⚠ Batch ${batchNumber} complete:</span> ${savedCount} saved, ${skippedCount} skipped, ${failedCount} failed`);
                        } else {
                            this.addLog(`  <span style="color: var(--brand-success);">✓ Batch ${batchNumber} complete:</span> ${savedCount} saved, ${skippedCount} skipped`);
                        }

                        this.currentBatch++;
                        setTimeout(() => this.processNextBatch(), 300);
                    } else {
                        const errorMessage = (response.data && response.data.message) || 'Unknown error';
                        this.addLog(`  <span style="color: var(--brand-error);">✗ Batch ${batchNumber} failed:</span> ${errorMessage}`);
                        this.showError(errorMessage);
                    }
                },
                error: (xhr, status, error) => {
                    console.error('Batch save error:', xhr, error);
                    this.addLog(`  <span style="color: var(--brand-error);">✗ Batch ${batchNumber} error:</span> ${error}`);
                    this.showError('Network error. Please try again.');
                }
            });
        }

        addLog(message) {
            const $log = $('#batch-progress-steps');
            $log.append('<div>' + message + '</div>');
            $log.scrollTop($log[0].scrollHeight);
        }

        showComplete() {
            $('#batch-progress-bar').css('width', '100%').css('box-shadow', '0 0 20px rgba(139, 92, 246, 0.6)');
            $('#batch-progress-text').text(`${this.keywordsArray.length} / ${this.keywordsArray.length} keywords`);
            $('#batch-current-status div:first').html('✅ All Batches Complete!');
            $('#batch-status-detail').html(`Total: ${this.totalSaved} saved, ${this.totalSkipped} skipped (duplicates), ${this.totalFailed} failed`);

            this.addLog('');
            this.addLog('<span style="color: var(--brand-success); font-weight: 600;">✅ COMPLETE!</span>');
            this.addLog(`<span style="color: var(--brand-white);">→ Total Processed:</span> ${this.keywordsArray.length} keywords`);
            this.addLog(`<span style="color: var(--brand-success);">→ Successfully Saved:</span> ${this.totalSaved}`);
            this.addLog(`<span style="color: var(--brand-warning);">→ Skipped (duplicates):</span> ${this.totalSkipped}`);
            if (this.totalFailed > 0) {
                this.addLog(`<span style="color: var(--brand-error);">→ Failed:</span> ${this.totalFailed}`);
            }

            $('#modal-confirm').text('✅ Done').prop('disabled', false);

            // Refresh the keywords list
            setTimeout(function () {
                loadLatestSnapshot();
            }, 1500);

            setTimeout(function () {
                closeModal();
            }, 3000);
        }

        showError(message) {
            $('#batch-current-status').html(`
                        <div style="font-weight: 600; color: var(--brand-error); margin-bottom: 6px; font-size: 15px;">❌ Error</div>
                        <div style="font-size: 13px; color: var(--brand-gray-light);">${message}</div>
                    `);
            $('#modal-confirm').text('❌ Failed').prop('disabled', false);
        }
    }

    // Competitor Spy Progress Manager (Global Scope)
    class CompetitorSpyProgress {
        constructor(competitors, analysisType, language, location, filters, userDomain) {
            this.competitors = competitors;
            this.analysisType = analysisType;
            this.language = language;
            this.location = location;
            this.filters = filters;
            this.userDomain = userDomain;
            this.currentStep = 0;
            this.totalSteps = 0;
            this.results = null;
        }

        getHTML() {
            return `
                            <div id="spy-progress-container" style="margin-top: 12px;">
                                <div style="background: rgba(10, 14, 39, 0.6); border: 1px solid rgba(0, 188, 212, 0.2); border-radius: 16px; padding: 20px; backdrop-filter: blur(10px);">
                                    <!-- Progress Bar -->
                                    <div style="margin-bottom: 20px;">
                                        <div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
                                            <span style="font-size: 13px; font-weight: 600; color: var(--brand-white); letter-spacing: 0.05em; text-transform: uppercase;">Analysis Progress</span>
                                            <span id="spy-progress-text" style="font-size: 13px; color: var(--brand-primary); font-weight: 600;">Initializing...</span>
                                        </div>
                                        <div style="background: rgba(160, 168, 184, 0.15); border-radius: 12px; height: 10px; overflow: hidden; border: 1px solid rgba(0, 188, 212, 0.2);">
                                            <div id="spy-progress-bar" style="background: linear-gradient(90deg, var(--brand-primary) 0%, var(--brand-purple) 100%); height: 100%; width: 0%; transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 0 12px rgba(139, 92, 246, 0.5);"></div>
                                        </div>
                                    </div>

                                    <!-- Current Status -->
                                    <div id="spy-current-status" style="background: rgba(139, 92, 246, 0.1); border-radius: 12px; padding: 16px; margin-bottom: 16px; border-left: 4px solid var(--brand-purple); backdrop-filter: blur(10px);">
                                        <div style="font-weight: 600; color: var(--brand-white); margin-bottom: 6px; font-size: 15px;">Starting analysis...</div>
                                        <div id="spy-status-detail" style="font-size: 13px; color: var(--brand-gray-light);"></div>
                                    </div>

                                    <!-- Progress Steps Log -->
                                    <div id="spy-progress-steps" style="height: 290px; overflow-y: auto; font-size: 12px; font-family: 'Consolas', 'Monaco', monospace; background: #0A0E27; color: #E2E8F0; padding: 16px; border-radius: 12px; line-height: 1.8; border: 1px solid rgba(139, 92, 246, 0.3); box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.3);">
                                        <div style="color: var(--brand-purple);">● Initializing competitor analysis...</div>
                                    </div>
                                </div>

                                <!-- Discreet Warning -->
                                <div style="margin-top: 12px; padding: 10px 14px; background: rgba(139, 92, 246, 0.15); border-left: 3px solid var(--brand-purple); border-radius: 8px; font-size: 11px; color: var(--brand-white); line-height: 1.5; backdrop-filter: blur(10px); border: 1px solid rgba(139, 92, 246, 0.3);">
                                    🕵️ <strong style="color: var(--brand-purple);">Keep window open</strong> - Analyzing ${this.competitors.length} competitor(s) with DataForSEO
                                </div>
                            </div>
                        `;
        }

        start() {
            this.analyzeCompetitors();
        }

        analyzeCompetitors() {
            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                dataType: 'json',
                data: {
                    action: 'wisewand_spy_competitors',
                    competitors: JSON.stringify(this.competitors),
                    analysis_type: this.analysisType,
                    language_code: this.language,
                    location_code: this.location,
                    filters: JSON.stringify(this.filters),
                    user_domain: this.userDomain,
                    nonce: wisewandSEO.nonce
                },
                success: (response) => {
                    console.log('Competitor spy response:', response);

                    if (response && response.success) {
                        this.handleProgress(response.data);
                    } else {
                        this.showError(response?.data?.message || 'Analysis failed');
                    }
                },
                error: (xhr, status, error) => {
                    console.error('Competitor spy AJAX error:', xhr.responseText);

                    // Try to parse error response
                    let errorMsg = 'Connection failed';
                    try {
                        const response = JSON.parse(xhr.responseText);
                        errorMsg = response.data?.message || response.message || errorMsg;
                    } catch (e) {
                        errorMsg = 'HTTP ' + xhr.status + ': ' + (error || 'Unknown error');
                    }

                    this.showError(errorMsg);
                }
            });
        }

        handleProgress(data) {
            const progress = data.progress || {};
            const steps = data.steps || [];

            // Update progress bar
            if (progress.percent !== undefined) {
                $('#spy-progress-bar').css('width', progress.percent + '%');
                $('#spy-progress-text').text(progress.text || 'Processing...');
            }

            // Update current status
            if (progress.current_task) {
                $('#spy-current-status').html(`
                                <div style="font-weight: 600; color: var(--brand-white); margin-bottom: 6px; font-size: 15px;">
                                    ${this.escapeHtml(progress.current_task)}
                                </div>
                                <div style="font-size: 13px; color: var(--brand-gray-light);">
                                    ${this.escapeHtml(progress.detail || '')}
                                </div>
                            `);
            }

            // Append steps to log
            const $log = $('#spy-progress-steps');
            steps.forEach(step => {
                $log.append(this.formatStepLog(step));
            });
            $log.scrollTop($log[0].scrollHeight);

            // Check if complete
            if (data.completed) {
                this.showResults(data.results);
            }
        }

        formatStepLog(step) {
            const icons = {
                started: '▸',
                processing: '⋯',
                success: '✓',
                error: '✗',
                info: '●'
            };

            const colors = {
                started: '#8B5CF6',
                processing: '#F59E0B',
                success: '#10B981',
                error: '#EF4444',
                info: '#00BCD4'
            };

            const icon = icons[step.status] || '●';
            const color = colors[step.status] || '#E2E8F0';
            let message = step.message;

            if (step.endpoint) {
                message += ` <span style="color: #8B5CF6; font-size: 10px;">[${step.endpoint}]</span>`;
            }

            if (step.count !== undefined) {
                message += ` <span style="color: #A0A8B8;">(${step.count})</span>`;
            }

            return `<div style="color: ${color};">${icon} ${this.escapeHtml(message)}</div>`;
        }

        showResults(results) {
            $('#spy-progress-bar').css('width', '100%').css('box-shadow', '0 0 20px rgba(139, 92, 246, 0.6)');
            $('#spy-progress-text').text('Analysis Complete');

            const keywords = results.keywords || [];
            const totalFound = results.total_found || 0;

            $('#spy-current-status').html(`
                            <div style="font-weight: 600; color: var(--brand-success); margin-bottom: 8px; font-size: 16px;">✅ Analysis Complete!</div>
                            <div style="font-size: 13px; color: var(--brand-white);">
                                <span style="color: var(--brand-primary); font-weight: 600;">🔍 ${totalFound}</span> keywords found •
                                <span style="color: var(--brand-purple); font-weight: 600;">📊 ${keywords.length}</span> top opportunities •
                                <span style="color: var(--brand-success); font-weight: 600;">🎯 ${results.competitors_analyzed}</span> competitors analyzed
                            </div>
                        `).css('border-left-color', 'var(--brand-success)');

            // Show results table
            const resultsHTML = this.buildResultsTable(keywords);
            $('#spy-modal-feedback').html(resultsHTML);

            $('#modal-confirm').text('💾 Save All to Library').prop('disabled', false).off('click').on('click', () => {
                this.saveKeywordsToLibrary(keywords, results.analysis_id);
            });
        }

        buildResultsTable(keywords) {
            if (keywords.length === 0) {
                return `
                                <div class="modal-info" style="margin-top: 20px;">
                                    <strong>⚠️ No Keywords Found</strong><br><br>
                                    <div style="background: rgba(245, 158, 11, 0.2); padding: 12px; border-radius: 8px; border-left: 3px solid var(--brand-warning); margin: 12px 0;">
                                        <strong style="color: var(--brand-warning);">⚠️ MOST COMMON ISSUE: Language/Country Mismatch!</strong><br><br>
                                        <strong>Examples:</strong><br>
                                        • meshistoiresdusoir.fr (French site) → Select "🇫🇷 France (French)"<br>
                                        • nytimes.com (US site) → Select "🇺🇸 United States (English)"<br>
                                        • bild.de (German site) → Select "🇩🇪 Germany (German)"
                                    </div>
                                    <strong>Other possible reasons:</strong><br>
                                    • Filters too restrictive (default: volume ≥100, difficulty ≤50)<br>
                                    • Competitor has very low traffic or is too new<br>
                                    • Domain not in DataForSEO database yet<br><br>
                                    <strong>Quick Fixes:</strong><br>
                                    1. <strong>Close this modal and retry with correct language/country</strong><br>
                                    2. Open "Advanced Filters" → Set Min Volume to <strong>0</strong><br>
                                    3. Set Max Difficulty to <strong>70-80</strong><br>
                                    4. Try "Best Performers" instead of "Gap Analysis"<br>
                                    5. Test with a well-known competitor first (e.g., nytimes.com for US English)<br><br>
                                    <strong>Debug:</strong> Press F12 → Console tab to see detailed DataForSEO API responses.
                                </div>
                            `;
            }

            let html = `
                            <div style="margin-top: 20px; max-height: 400px; overflow-y: auto;">
                                <h4 style="color: var(--brand-white); margin-bottom: 12px;">🎯 Top ${keywords.length} Keywords</h4>
                                <table style="width: 100%; font-size: 12px; border-collapse: collapse;">
                                    <thead>
                                        <tr style="background: rgba(0, 188, 212, 0.1); border-bottom: 2px solid rgba(0, 188, 212, 0.3);">
                                            <th style="padding: 8px; text-align: left; color: var(--brand-white); font-weight: 600;">Keyword</th>
                                            <th style="padding: 8px; text-align: center; color: var(--brand-white); font-weight: 600;">Volume</th>
                                            <th style="padding: 8px; text-align: center; color: var(--brand-white); font-weight: 600;">Diff</th>
                                            <th style="padding: 8px; text-align: center; color: var(--brand-white); font-weight: 600;">Comp Pos</th>
                                            <th style="padding: 8px; text-align: center; color: var(--brand-white); font-weight: 600;">Priority</th>
                                        </tr>
                                    </thead>
                                    <tbody>
                        `;

            keywords.slice(0, 50).forEach(kw => {
                const priorityColor = kw.priority_score >= 70 ? '#10B981' : kw.priority_score >= 50 ? '#F59E0B' : '#A0A8B8';
                html += `
                                <tr style="border-bottom: 1px solid rgba(0, 188, 212, 0.1);">
                                    <td style="padding: 8px; color: var(--brand-white);">${this.escapeHtml(kw.keyword)}</td>
                                    <td style="padding: 8px; text-align: center; color: var(--brand-primary); font-weight: 600;">${this.formatNumber(kw.search_volume)}</td>
                                    <td style="padding: 8px; text-align: center; color: var(--brand-gray-light);">${kw.difficulty || 'N/A'}</td>
                                    <td style="padding: 8px; text-align: center; color: var(--brand-purple); font-weight: 600;">#${kw.competitor_position || 'N/A'}</td>
                                    <td style="padding: 8px; text-align: center; color: ${priorityColor}; font-weight: 700;">${Math.round(kw.priority_score)}</td>
                                </tr>
                            `;
            });

            html += `
                                    </tbody>
                                </table>
                                ${keywords.length > 50 ? `<p style="text-align: center; color: var(--brand-gray-light); margin-top: 12px; font-size: 11px;">Showing top 50 of ${keywords.length} keywords</p>` : ''}
                            </div>
                        `;

            return html;
        }

        saveKeywordsToLibrary(keywords, analysisId) {
            $('#modal-confirm').prop('disabled', true).text('💾 Saving...');

            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_save_spy_keywords',
                    keywords: JSON.stringify(keywords),
                    analysis_id: analysisId,
                    language_code: this.language,
                    location_code: this.location,
                    nonce: wisewandSEO.nonce
                },
                success: (response) => {
                    if (response.success) {
                        $('#spy-modal-feedback').html(`
                                        <div class="modal-success">
                                            ✅ <strong>Saved ${response.data.saved} keywords to library!</strong><br><br>
                                            Skipped ${response.data.skipped} duplicates.<br>
                                            Keywords are now available in the table below.
                                        </div>
                                    `);

                        setTimeout(() => {
                            closeModal();
                            loadLatestSnapshot();
                        }, 2000);
                    } else {
                        alert('Failed to save: ' + (response.data?.message || 'Unknown error'));
                        $('#modal-confirm').prop('disabled', false).text('💾 Retry Save');
                    }
                },
                error: () => {
                    alert('Connection error while saving');
                    $('#modal-confirm').prop('disabled', false).text('💾 Retry Save');
                }
            });
        }

        showError(message) {
            $('#spy-current-status').html(`
                            <div style="font-weight: 600; color: var(--brand-error); margin-bottom: 6px; font-size: 15px;">❌ Error Occurred</div>
                            <div style="font-size: 13px; color: var(--brand-white);">${this.escapeHtml(message)}</div>
                        `).css('border-left-color', 'var(--brand-error)');

            const $log = $('#spy-progress-steps');
            $log.append(`<div style="color: var(--brand-error); font-weight: 600;">✗ ERROR: ${this.escapeHtml(message)}</div>`);

            $('#modal-confirm').prop('disabled', false).text('🕵️ Retry');
        }

        escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }

        formatNumber(num) {
            if (num >= 1000) {
                return (num / 1000).toFixed(1) + 'K';
            }
            return num.toString();
        }
    }

    // Competitor Spy - Show Modal (with pre-flight balance check)
    $('#spy-competitors').on('click', function () {
        checkBalanceBeforeAction(function () { showCompetitorSpyModal(); });
    });

    function showCompetitorSpyModal() {
        const modalBody = `
                    <div class="modal-form-group">
                        <label>🎯 Analysis Type</label>
                        <select id="spy-analysis-type" class="modal-select">
                            <option value="hybrid" selected>🔄 Hybrid (Gap + Best Performers)</option>
                            <option value="gap">🔍 Gap Analysis Only (They rank, you don't)</option>
                            <option value="best_performers">⭐ Best Performers Only (Their top keywords)</option>
                        </select>
                        <p style="font-size: 11px; color: var(--brand-gray-light); margin-top: 6px;">
                            Hybrid mode combines both strategies for maximum keyword discovery.
                        </p>
                    </div>

                    <div class="modal-form-group">
                        <label>🕵️ Competitor Domains (1-3)</label>
                        <input type="text" id="spy-competitor-1" class="modal-input" placeholder="competitor1.com" />
                        <input type="text" id="spy-competitor-2" class="modal-input" placeholder="competitor2.com (optional)" style="margin-top: 8px;" />
                        <input type="text" id="spy-competitor-3" class="modal-input" placeholder="competitor3.com (optional)" style="margin-top: 8px;" />
                        <p style="font-size: 11px; color: var(--brand-gray-light); margin-top: 6px;">
                            Enter without http:// or www. Example: nytimes.com
                        </p>
                    </div>

                    <div class="modal-form-group">
                        <label>🌍 Target Market</label>
                        <select id="spy-market" class="modal-select">
                            ${buildMarketOptions('en:2840')}
                        </select>
                    </div>

                    <details style="margin-top: 12px;">
                        <summary style="cursor: pointer; color: var(--brand-primary); font-weight: 600; font-size: 13px; margin-bottom: 12px;">⚙️ Advanced Filters (Optional)</summary>
                        <div style="padding: 12px; background: rgba(0, 188, 212, 0.05); border-radius: 8px; margin-top: 8px;">
                            <div class="modal-form-group">
                                <label>Min Search Volume: <span id="vol-value">100</span>/month</label>
                                <input type="range" id="spy-min-volume" min="0" max="5000" value="100" step="50" style="width: 100%;" />
                            </div>
                            <div class="modal-form-group">
                                <label>Max Difficulty: <span id="diff-value">50</span>/100</label>
                                <input type="range" id="spy-max-difficulty" min="0" max="100" value="50" step="5" style="width: 100%;" />
                            </div>
                            <div class="modal-form-group">
                                <label>Competitor Position Range</label>
                                <div style="display: flex; gap: 12px;">
                                    <input type="number" id="spy-pos-min" class="modal-input" value="1" min="1" max="100" style="width: 80px;" />
                                    <span style="color: var(--brand-white); align-self: center;">to</span>
                                    <input type="number" id="spy-pos-max" class="modal-input" value="50" min="1" max="100" style="width: 80px;" />
                                </div>
                            </div>
                            <div class="modal-form-group">
                                <label style="display: flex; align-items: center; gap: 8px; cursor: pointer; text-transform: none;">
                                    <input type="checkbox" id="spy-exclude-branded" checked style="width: auto;" />
                                    <span>Exclude competitor branded terms</span>
                                </label>
                            </div>
                        </div>
                    </details>

                    <div id="spy-modal-feedback"></div>
                `;

        showModal('🕵️ Competitor Spy', modalBody, '🕵️ Start Analysis', function () {
            const competitors = [
                $('#spy-competitor-1').val().trim(),
                $('#spy-competitor-2').val().trim(),
                $('#spy-competitor-3').val().trim()
            ].filter(c => c);

            if (competitors.length === 0) {
                $('#spy-modal-feedback').html('<div class="modal-error">Please enter at least one competitor domain</div>');
                return;
            }

            const analysisType = $('#spy-analysis-type').val();
            const [language, location] = $('#spy-market').val().split(':');
            const filters = {
                min_volume: parseInt($('#spy-min-volume').val()),
                max_difficulty: parseInt($('#spy-max-difficulty').val()),
                position_min: parseInt($('#spy-pos-min').val()),
                position_max: parseInt($('#spy-pos-max').val()),
                exclude_branded: $('#spy-exclude-branded').is(':checked')
            };

            $('#modal-confirm').prop('disabled', true).text('🕵️ Analyzing...');

            const spyProgress = new CompetitorSpyProgress(
                competitors,
                analysisType,
                language,
                parseInt(location),
                filters,
                wisewandSEO.domain
            );

            $('#spy-modal-feedback').html(spyProgress.getHTML());
            spyProgress.start();
        });

        // Update slider values in real-time
        $('#spy-min-volume').on('input', function () {
            $('#vol-value').text($(this).val());
        });

        $('#spy-max-difficulty').on('input', function () {
            $('#diff-value').text($(this).val());
        });
    }

    // Deduplication - Open Scanner
    $('#open-deduplication').on('click', function () {
        openDeduplicationScanner();
    });

    // AI Match Categories - Open Matcher
    $('#ai-match-categories').on('click', function () {
        // Check if OpenAI is configured via quick AJAX check
        $.ajax({
            url: wisewandSEO.settingsUrl,
            type: 'HEAD',
            complete: function () {
                // Just trigger the modal - backend will check API key
                openAICategoryMatcher();
            }
        });
    });

    function openAICategoryMatcher() {
        const modalBody = `
                    <div style="text-align: center; color: var(--brand-white); margin-bottom: 20px;">
                        <div style="font-size: 56px; margin-bottom: 16px;">🤖</div>
                        <div style="font-size: 18px; font-weight: 700; margin-bottom: 8px;">AI Category Matching</div>
                        <div style="font-size: 13px; color: var(--brand-gray-light); max-width: 500px; margin: 0 auto; line-height: 1.6;">
                            GPT-4o-mini will analyze your keywords and intelligently match them to WordPress categories.
                            This helps organize content and improve SEO structure.
                        </div>
                    </div>

                    <div class="modal-form-group" style="margin-bottom: 20px;">
                        <label style="display: block; margin-bottom: 10px; color: var(--brand-white); font-weight: 600; font-size: 14px;">📋 Keywords to Process</label>
                        <select id="ai-keyword-filter" class="modal-select" style="width: 100%; padding: 10px 14px; border: 1px solid rgba(16, 185, 129, 0.3); border-radius: 8px; background: rgba(10, 14, 39, 0.8); color: var(--brand-white); font-size: 14px;">
                            <option value="uncategorized">🎯 Only Uncategorized Keywords (Recommended)</option>
                            <option value="all">📚 All Keywords (Re-match Everything)</option>
                            <option value="exclude_ranking">🚫 Exclude Already Ranking Keywords</option>
                            <option value="only_ranking">✅ Only Ranking Keywords (Auto-detect from URLs)</option>
                            <option value="without_position">🔍 Only Keywords Without Position Data</option>
                        </select>
                        <p style="font-size: 11px; color: var(--brand-gray-light); margin-top: 8px; line-height: 1.5;">
                            💡 <strong>Recommended:</strong> Use "Only Uncategorized" for normal matching. Use "Exclude Ranking" if you have many positioned keywords and want to focus on new opportunities.
                        </p>
                    </div>

                    <div style="background: rgba(10, 14, 39, 0.6); border: 1px solid rgba(16, 185, 129, 0.3); border-radius: 12px; padding: 20px; margin-bottom: 20px; backdrop-filter: blur(10px);">
                        <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 16px;">
                            <div style="text-align: center;">
                                <div style="font-size: 32px; font-weight: 700; color: var(--brand-success);" id="ai-total-keywords">-</div>
                                <div style="font-size: 12px; color: var(--brand-gray-light);">Keywords to Process</div>
                            </div>
                            <div style="text-align: center;">
                                <div style="font-size: 32px; font-weight: 700; color: var(--brand-primary);" id="ai-categories-count">-</div>
                                <div style="font-size: 12px; color: var(--brand-gray-light);">WP Categories</div>
                            </div>
                            <div style="text-align: center;">
                                <div style="font-size: 32px; font-weight: 700; color: var(--brand-warning);" id="ai-estimated-cost">-</div>
                                <div style="font-size: 12px; color: var(--brand-gray-light);">Est. Cost (USD)</div>
                            </div>
                        </div>
                    </div>

                    <div id="ai-match-feedback"></div>
                `;

        showModal('🤖 AI Category Matching', modalBody, '🤖 Start AI Matching', function () {
            startAICategoryMatching();
        });

        // Load stats
        loadAIMatchingStats();

        // Update stats when filter changes
        $('#ai-keyword-filter').on('change', function () {
            loadAIMatchingStats();
        });
    }

    function loadAIMatchingStats() {
        const filterMode = $('#ai-keyword-filter').val() || 'uncategorized';
        const totalCategories = wisewandSEO.totalCategories || 0;

        // Show loading state
        $('#ai-total-keywords').text('...');
        $('#ai-estimated-cost').text('...');

        // Use AJAX for server-side counting (more accurate for ranking filters)
        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_count_keywords_for_matching',
                nonce: wisewandSEO.nonce,
                filter_mode: filterMode
            },
            success: function (response) {
                if (response.success && response.data) {
                    const keywordCount = response.data.total_keywords || 0;
                    const autoMatchable = response.data.auto_matchable || 0;
                    const aiNeeded = response.data.ai_needed || 0;

                    // Estimate cost (GPT-4o-mini pricing: ~$0.25 per 1000 keywords)
                    const estimatedCost = (aiNeeded * 0.00025).toFixed(3);

                    // Debug logging
                    console.log('🤖 AI Matching Stats:', {
                        filterMode: filterMode,
                        keywordCount: keywordCount,
                        autoMatchable: autoMatchable,
                        aiNeeded: aiNeeded,
                        totalCategories: totalCategories,
                        estimatedCost: estimatedCost
                    });

                    $('#ai-total-keywords').text(keywordCount);
                    $('#ai-categories-count').text(totalCategories);
                    $('#ai-estimated-cost').text('$' + estimatedCost);

                    // Show helpful message based on count and filter
                    if (keywordCount === 0) {
                        $('#ai-match-feedback').html(`
                                    <div style="padding: 12px; background: rgba(16, 185, 129, 0.15); border-left: 3px solid var(--brand-success); border-radius: 8px; font-size: 12px; color: var(--brand-white);">
                                        ✅ <strong>No keywords match this filter!</strong><br>
                                        Try a different filter option.
                                    </div>
                                `);
                    } else if (autoMatchable > 0 && filterMode === 'only_ranking') {
                        $('#ai-match-feedback').html(`
                                    <div style="padding: 12px; background: rgba(59, 130, 246, 0.15); border-left: 3px solid var(--brand-primary); border-radius: 8px; font-size: 12px; color: var(--brand-white);">
                                        🔗 <strong>${autoMatchable} keywords have ranking URLs</strong><br>
                                        Categories will be auto-detected from existing posts! Save ~$${(autoMatchable * 0.00025).toFixed(3)}
                                    </div>
                                `);
                    } else if (autoMatchable > 0) {
                        $('#ai-match-feedback').html(`
                                    <div style="padding: 12px; background: rgba(59, 130, 246, 0.15); border-left: 3px solid var(--brand-primary); border-radius: 8px; font-size: 12px; color: var(--brand-white);">
                                        🔗 <strong>${autoMatchable} keywords will be auto-matched from URLs</strong><br>
                                        Only ${aiNeeded} keywords need AI processing. Saving ~$${(autoMatchable * 0.00025).toFixed(3)}
                                    </div>
                                `);
                    } else {
                        $('#ai-match-feedback').html('');
                    }
                } else {
                    // Fallback to client-side counting for backward compatibility
                    $('#ai-total-keywords').text('?');
                    $('#ai-estimated-cost').text('?');
                }
            },
            error: function () {
                $('#ai-total-keywords').text('?');
                $('#ai-estimated-cost').text('?');
            }
        });
    }

    function startAICategoryMatching() {
        const filterMode = $('#ai-keyword-filter').val() || 'uncategorized';

        console.log('🤖 Starting AI matching with filter:', filterMode);

        $('#modal-confirm').prop('disabled', true).text('🤖 Matching...');

        const progressUI = new AICategoryMatcherProgress(filterMode);
        $('#ai-match-feedback').html(progressUI.getHTML());

        progressUI.start();
    }

    function openDeduplicationScanner() {
        const modalBody = `
                    <div style="text-align: center; color: var(--brand-white); margin-bottom: 20px;">
                        <div style="font-size: 56px; margin-bottom: 16px;">🔗</div>
                        <div style="font-size: 18px; font-weight: 700; margin-bottom: 8px;">Keyword Deduplication Scanner</div>
                        <div style="font-size: 13px; color: var(--brand-gray-light); max-width: 500px; margin: 0 auto; line-height: 1.6;">
                            Detect and group similar keywords to prevent content cannibalization.
                            The scanner uses multi-algorithm fuzzy matching to find duplicates, reorders, and singular/plural variants.
                        </div>
                    </div>

                    <!-- Threshold Configuration -->
                    <div style="background: rgba(10, 14, 39, 0.6); border: 1px solid rgba(139, 92, 246, 0.3); border-radius: 12px; padding: 20px; margin-bottom: 20px; backdrop-filter: blur(10px);">
                        <div style="font-size: 14px; font-weight: 600; color: var(--brand-white); margin-bottom: 12px; display: flex; align-items: center; gap: 8px;">
                            ⚙️ Similarity Thresholds
                            <span style="font-size: 11px; color: var(--brand-gray-light); font-weight: 400;">(Per-scan only, not saved)</span>
                        </div>
                        <div style="font-size: 11px; color: var(--brand-gray-light); margin-bottom: 16px; line-height: 1.5;">
                            Adjust how strict the deduplication is. Higher values find fewer, more precise matches. Lower values find more matches but may include false positives.
                        </div>

                        <!-- Semantic Duplicate Threshold -->
                        <div style="margin-bottom: 16px;">
                            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px;">
                                <label style="font-size: 12px; color: var(--brand-gray-light); font-weight: 500;">
                                    🎯 Semantic Duplicate (AI)
                                </label>
                                <span id="threshold-semantic-duplicate-value" style="font-size: 13px; font-weight: 600; color: var(--brand-purple); min-width: 45px; text-align: right;">0.85</span>
                            </div>
                            <input type="range" id="threshold-semantic-duplicate" min="0.70" max="0.95" step="0.01" value="0.85"
                                style="width: 100%; height: 6px; border-radius: 3px; background: rgba(139, 92, 246, 0.2); outline: none; -webkit-appearance: none;" />
                            <div style="font-size: 10px; color: var(--brand-gray-light); margin-top: 4px;">
                                Exact matches only (0.95) ← Moderate (0.85) → Loose matching (0.70)
                            </div>
                        </div>

                        <!-- Semantic Related Threshold -->
                        <div style="margin-bottom: 16px;">
                            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px;">
                                <label style="font-size: 12px; color: var(--brand-gray-light); font-weight: 500;">
                                    🔗 Semantic Related (AI)
                                </label>
                                <span id="threshold-semantic-related-value" style="font-size: 13px; font-weight: 600; color: var(--brand-success); min-width: 45px; text-align: right;">0.85</span>
                            </div>
                            <input type="range" id="threshold-semantic-related" min="0.70" max="0.95" step="0.01" value="0.85"
                                style="width: 100%; height: 6px; border-radius: 3px; background: rgba(16, 185, 129, 0.2); outline: none; -webkit-appearance: none;" />
                            <div style="font-size: 10px; color: var(--brand-gray-light); margin-top: 4px;">
                                Very similar topics (0.95) ← Related topics (0.85) → Broadly related (0.70)
                            </div>
                        </div>

                        <!-- Fuzzy Similarity Threshold -->
                        <div style="margin-bottom: 0;">
                            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px;">
                                <label style="font-size: 12px; color: var(--brand-gray-light); font-weight: 500;">
                                    📝 Fuzzy String Matching
                                </label>
                                <span id="threshold-fuzzy-value" style="font-size: 13px; font-weight: 600; color: var(--brand-primary); min-width: 45px; text-align: right;">0.85</span>
                            </div>
                            <input type="range" id="threshold-fuzzy" min="0.70" max="0.95" step="0.01" value="0.85"
                                style="width: 100%; height: 6px; border-radius: 3px; background: rgba(59, 130, 246, 0.2); outline: none; -webkit-appearance: none;" />
                            <div style="font-size: 10px; color: var(--brand-gray-light); margin-top: 4px;">
                                Character-perfect (0.95) ← Good match (0.85) → Allow typos (0.70)
                            </div>
                        </div>
                    </div>

                    <div style="background: rgba(10, 14, 39, 0.6); border: 1px solid rgba(139, 92, 246, 0.3); border-radius: 12px; padding: 20px; margin-bottom: 20px; backdrop-filter: blur(10px);">
                        <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 16px;">
                            <div style="text-align: center;">
                                <div style="font-size: 32px; font-weight: 700; color: var(--brand-purple);" id="dedup-total-keywords">-</div>
                                <div style="font-size: 12px; color: var(--brand-gray-light);">Total Keywords</div>
                            </div>
                            <div style="text-align: center;">
                                <div style="font-size: 32px; font-weight: 700; color: var(--brand-success);" id="dedup-clusters-count">-</div>
                                <div style="font-size: 12px; color: var(--brand-gray-light);">Clusters Found</div>
                            </div>
                            <div style="text-align: center;">
                                <div style="font-size: 32px; font-weight: 700; color: var(--brand-primary);" id="dedup-variants-count">-</div>
                                <div style="font-size: 12px; color: var(--brand-gray-light);">Variants Detected</div>
                            </div>
                        </div>
                    </div>

                    <div id="dedup-scanner-feedback"></div>
                `;

        showModal('🔗 Keyword Deduplication', modalBody, '🔍 Start Scan', function () {
            startDeduplicationScan();
        });

        // Add real-time slider value updates
        $('#threshold-semantic-duplicate').on('input', function () {
            $('#threshold-semantic-duplicate-value').text(parseFloat($(this).val()).toFixed(2));
        });

        $('#threshold-semantic-related').on('input', function () {
            $('#threshold-semantic-related-value').text(parseFloat($(this).val()).toFixed(2));
        });

        $('#threshold-fuzzy').on('input', function () {
            $('#threshold-fuzzy-value').text(parseFloat($(this).val()).toFixed(2));
        });

        // Load current stats
        loadDeduplicationStats();
    }

    function loadDeduplicationStats() {
        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_get_clusters',
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success && response.data.stats) {
                    $('#dedup-total-keywords').text(response.data.stats.total_keywords || 0);
                    $('#dedup-clusters-count').text(response.data.stats.total_clusters || 0);
                    $('#dedup-variants-count').text(response.data.stats.total_variants || 0);
                }
            }
        });
    }

    function startDeduplicationScan() {
        $('#modal-confirm').prop('disabled', true).text('🔍 Scanning...');

        const progressUI = new DeduplicationScanner();
        $('#dedup-scanner-feedback').html(progressUI.getHTML());

        progressUI.start();
    }

    // Deduplication Scanner Progress Manager (Global Scope)
    class DeduplicationScanner {
        constructor() {
            this.startTime = Date.now();
        }

        getHTML() {
            return `
                        <div id="dedup-progress-container" style="margin-top: 12px;">
                            <div style="background: rgba(10, 14, 39, 0.6); border: 1px solid rgba(139, 92, 246, 0.2); border-radius: 16px; padding: 20px; backdrop-filter: blur(10px);">
                                <!-- Progress Bar -->
                                <div style="margin-bottom: 20px;">
                                    <div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
                                        <span style="font-size: 13px; font-weight: 600; color: var(--brand-white); letter-spacing: 0.05em; text-transform: uppercase;">Scan Progress</span>
                                        <span id="dedup-progress-text" style="font-size: 13px; color: var(--brand-purple); font-weight: 600;">Initializing...</span>
                                    </div>
                                    <div style="background: rgba(160, 168, 184, 0.15); border-radius: 12px; height: 10px; overflow: hidden; border: 1px solid rgba(139, 92, 246, 0.2);">
                                        <div id="dedup-progress-bar" style="background: linear-gradient(90deg, var(--brand-purple) 0%, var(--brand-primary) 100%); height: 100%; width: 0%; transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 0 12px rgba(139, 92, 246, 0.5);"></div>
                                    </div>
                                </div>

                                <!-- Current Status -->
                                <div id="dedup-current-status" style="background: rgba(139, 92, 246, 0.1); border-radius: 12px; padding: 16px; margin-bottom: 16px; border-left: 4px solid var(--brand-purple); backdrop-filter: blur(10px);">
                                    <div style="font-weight: 600; color: var(--brand-white); margin-bottom: 6px; font-size: 15px;">Preparing scan...</div>
                                    <div id="dedup-status-detail" style="font-size: 13px; color: var(--brand-gray-light);"></div>
                                </div>

                                <!-- Progress Steps Log -->
                                <div id="dedup-progress-steps" style="height: 290px; overflow-y: auto; font-size: 12px; font-family: 'Consolas', 'Monaco', monospace; background: #0A0E27; color: #E2E8F0; padding: 16px; border-radius: 12px; line-height: 1.8; border: 1px solid rgba(139, 92, 246, 0.3); box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.3);">
                                    <div style="color: var(--brand-purple);">● Initializing deduplication scanner...</div>
                                    <div style="color: var(--brand-gray-light);">→ Loading keyword library...</div>
                                </div>
                            </div>

                            <!-- Warning at Bottom -->
                            <div style="margin-top: 12px; padding: 10px 14px; background: rgba(245, 158, 11, 0.15); border-left: 3px solid var(--brand-warning); border-radius: 8px; font-size: 11px; color: var(--brand-white); line-height: 1.5; backdrop-filter: blur(10px); border: 1px solid rgba(245, 158, 11, 0.3);">
                                ⚠️ <strong style="color: var(--brand-warning);">Keep window open</strong> - Thorough scanning may take 15-30 seconds for large libraries
                            </div>
                        </div>
                    `;
        }

        start() {
            this.addLog(' ');
            this.runScan();
        }

        runScan() {
            $('#dedup-progress-bar').css('width', '5%');
            $('#dedup-progress-text').text('Checking enrichment...');
            $('#dedup-current-status div:first').html('🔍 Preparing scan...');
            $('#dedup-status-detail').html('Checking keyword enrichment status...');

            this.addLog('<span style="color: var(--brand-primary);">● Preparation:</span> Checking enrichment status...');

            // Step 1: Check if enrichment is needed
            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_scan_duplicates',
                    nonce: wisewandSEO.nonce
                },
                success: (response) => {
                    if (response.success) {
                        if (response.data.needs_enrichment) {
                            // Need to enrich first
                            this.addLog(`<span style="color: var(--brand-warning);">  ⚠ Found ${response.data.unenriched_count} unenriched keywords</span>`);
                            this.addLog(' ');
                            this.enrichKeywords(response.data.unenriched_ids);
                        } else {
                            // Already enriched, proceed to clustering
                            this.addLog('<span style="color: var(--brand-success);">  ✓ All keywords enriched</span>');
                            this.addLog(' ');
                            this.runClustering();
                        }
                    } else {
                        this.showError(response.data.message || 'Scan failed');
                    }
                },
                error: (xhr) => {
                    this.handleAjaxError(xhr, 'Scan preparation failed');
                }
            });
        }

        enrichKeywords(keywordIds) {
            this.totalEnrich = keywordIds.length;
            this.currentEnrich = 0;
            this.batchSize = 10; // DataForSEO safe batch size

            $('#dedup-progress-bar').css('width', '10%');
            $('#dedup-current-status div:first').html('📊 Enriching Keywords...');

            this.addLog('<span style="color: var(--brand-success);">● PHASE 1: ENRICHMENT</span>');
            this.addLog(`<span style="color: var(--brand-gray-light);">  → Enriching ${this.totalEnrich} keywords with SEO data...</span>`);
            this.addLog(`<span style="color: var(--brand-gray-light);">  → Batch size: 10 keywords (DataForSEO optimized)</span>`);
            this.addLog(`<span style="color: var(--brand-gray-light);">  → Delay: 500ms between batches (rate limit safe)</span>`);
            this.addLog(' ');

            this.enrichNextBatch(keywordIds);
        }

        enrichNextBatch(keywordIds) {
            const batchNumber = Math.floor(this.currentEnrich / this.batchSize) + 1;
            const totalBatches = Math.ceil(this.totalEnrich / this.batchSize);
            const startIdx = this.currentEnrich;
            const endIdx = Math.min(startIdx + this.batchSize, this.totalEnrich);
            const batchIds = keywordIds.slice(startIdx, endIdx);

            if (batchIds.length === 0) {
                // Enrichment complete, proceed to clustering
                this.addLog('<span style="color: var(--brand-success);">  ✅ Enrichment complete!</span>');
                this.addLog(' ');
                this.runClustering();
                return;
            }

            const enrichProgress = Math.round((this.currentEnrich / this.totalEnrich) * 40); // 40% of total
            $('#dedup-progress-bar').css('width', (10 + enrichProgress) + '%');
            $('#dedup-progress-text').text(`Enriching ${this.currentEnrich}/${this.totalEnrich}...`);
            $('#dedup-status-detail').html(`Batch ${batchNumber}/${totalBatches} - Fetching SEO metrics...`);

            this.addLog(`<span style="color: var(--brand-primary);">  ● Batch ${batchNumber}/${totalBatches}:</span> Enriching ${batchIds.length} keywords...`);

            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_enrich_saved_keywords',
                    keyword_ids: batchIds,
                    nonce: wisewandSEO.nonce
                },
                success: (response) => {
                    if (response.success) {
                        this.addLog(`<span style="color: var(--brand-success);">    ✓ Enriched ${response.data.enriched || batchIds.length} keywords</span>`);
                        this.currentEnrich += batchIds.length;

                        // Continue with next batch after delay (DataForSEO rate limit safe)
                        setTimeout(() => this.enrichNextBatch(keywordIds), 500);
                    } else {
                        this.addLog(`<span style="color: var(--brand-warning);">    ⚠ Batch ${batchNumber} had issues, continuing...</span>`);
                        this.currentEnrich += batchIds.length;
                        setTimeout(() => this.enrichNextBatch(keywordIds), 500);
                    }
                },
                error: () => {
                    this.addLog(`<span style="color: var(--brand-warning);">    ⚠ Batch ${batchNumber} failed, continuing...</span>`);
                    this.currentEnrich += batchIds.length;
                    setTimeout(() => this.enrichNextBatch(keywordIds), 500);
                }
            });
        }

        runClustering() {
            $('#dedup-progress-bar').css('width', '50%');
            $('#dedup-current-status div:first').html('🔍 Scanning for duplicates...');
            $('#dedup-status-detail').html('Running analysis...');

            this.addLog('<span style="color: var(--brand-success);">● PHASE 2: DEDUPLICATION SCAN</span>');
            this.addLog('<span style="color: var(--brand-primary);">  ● Pre-filtering:</span> Grouping by language...');

            // Extract threshold values from modal sliders
            const thresholdSemanticDuplicate = parseFloat($('#threshold-semantic-duplicate').val()) || 0.85;
            const thresholdSemanticRelated = parseFloat($('#threshold-semantic-related').val()) || 0.85;
            const thresholdFuzzy = parseFloat($('#threshold-fuzzy').val()) || 0.85;

            // Validate range (0.70-0.95)
            const validateThreshold = (value) => {
                const num = parseFloat(value);
                return num >= 0.70 && num <= 0.95 ? num : 0.85;
            };

            const semanticDuplicate = validateThreshold(thresholdSemanticDuplicate);
            const semanticRelated = validateThreshold(thresholdSemanticRelated);
            const fuzzy = validateThreshold(thresholdFuzzy);

            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_run_clustering_scan',
                    nonce: wisewandSEO.nonce,
                    threshold_semantic_duplicate: semanticDuplicate,
                    threshold_semantic_related: semanticRelated,
                    threshold_fuzzy: fuzzy
                },
                success: (response) => {
                    if (response.success) {
                        const stats = response.data.stats;
                        const engineName = response.data.engine_name || 'Unknown Engine';
                        const engineUsed = response.data.engine_used || 'fuzzy_matching';

                        this.addLog('<span style="color: var(--brand-success);">    ✓ Pre-filtering complete</span>');
                        this.addLog(' ');

                        // Dynamic log based on engine used
                        if (engineUsed === 'ai_embeddings') {
                            // Show embedding generation stats
                            if (stats.embeddings_generated > 0) {
                                this.addLog(`<span style="color: var(--brand-purple);">  ✨ Generated ${stats.embeddings_generated} new embeddings</span>`);
                            }
                            this.addLog(`→ Algorithm: <span style="color: var(--brand-purple); font-weight: 600;">${this.escapeHtml(engineName)}</span>`);
                            this.addLog('→ Threshold: 75% semantic similarity');
                            this.addLog('<span style="color: var(--brand-primary);">  ● AI Analysis:</span> Calculating cosine similarity...');
                        } else {
                            this.addLog(`→ Algorithm: <span style="color: var(--brand-warning); font-weight: 600;">${this.escapeHtml(engineName)}</span>`);
                            this.addLog('→ Threshold: 75% similarity (strict mode)');
                            this.addLog('<span style="color: var(--brand-primary);">  ● Fuzzy Matching:</span> Calculating Levenshtein distance...');
                        }

                        $('#dedup-progress-bar').css('width', '70%');

                        setTimeout(() => {
                            this.addLog('<span style="color: var(--brand-success);">    ✓ Similarity calculation complete</span>');
                            this.addLog(' ');
                            this.addLog('<span style="color: var(--brand-primary);">  ● Clustering:</span> Building clusters (graph algorithm)...');
                            $('#dedup-progress-bar').css('width', '85%');

                            setTimeout(() => {
                                this.addLog('<span style="color: var(--brand-success);">    ✓ Clusters built successfully</span>');
                                this.addLog(' ');
                                this.addLog('<span style="color: var(--brand-primary);">  ● Selection:</span> Choosing primary keywords...');
                                $('#dedup-progress-bar').css('width', '95%');

                                setTimeout(() => {
                                    this.showComplete(stats, response.data);
                                }, 500);
                            }, 500);
                        }, 500);
                    } else {
                        this.showError(response.data.message || 'Clustering failed');
                    }
                },
                error: (xhr) => {
                    this.handleAjaxError(xhr, 'Clustering scan failed');
                }
            });
        }

        handleAjaxError(xhr, defaultMsg) {
            console.error('Deduplication error:', xhr);

            let errorMsg = defaultMsg || 'Network error. Please try again.';

            if (xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {
                errorMsg = xhr.responseJSON.data.message;
            } else if (xhr.responseText) {
                const match = xhr.responseText.match(/Fatal error:(.+?)in/i);
                if (match) {
                    errorMsg = 'PHP Error: ' + match[1].trim();
                } else if (xhr.status === 500) {
                    errorMsg = 'Server error (500). The deduplication tables may not be created yet. Please deactivate and reactivate the plugin to run database migrations.';
                }
            }

            this.showError(errorMsg);
        }

        addLog(message) {
            const $log = $('#dedup-progress-steps');
            $log.append('<div>' + message + '</div>');
            $log.scrollTop($log[0].scrollHeight);
        }

        escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }

        showComplete(stats, data) {
            const elapsed = ((Date.now() - this.startTime) / 1000).toFixed(1);

            $('#dedup-progress-bar').css('width', '100%').css('box-shadow', '0 0 20px rgba(139, 92, 246, 0.6)');
            $('#dedup-progress-text').text('Complete!');
            $('#dedup-current-status div:first').html('✅ Scan Complete!');
            $('#dedup-status-detail').html(`Found ${stats.clusters} clusters with ${stats.variants} variants in ${elapsed}s`);

            this.addLog(' ');
            this.addLog('<span style="color: var(--brand-success); font-weight: 600;">✅ DEDUPLICATION COMPLETE!</span>');
            this.addLog(' ');
            this.addLog(`<span style="color: var(--brand-white);">📊 Results Summary:</span>`);
            this.addLog(`<span style="color: var(--brand-gray-light);">  → Total Keywords Scanned:</span> ${stats.total_keywords || 0}`);
            this.addLog(`<span style="color: var(--brand-success);">  → Clusters Detected:</span> ${stats.clusters || 0}`);
            this.addLog(`<span style="color: var(--brand-primary);">  → Variant Keywords:</span> ${stats.variants || 0}`);
            this.addLog(`<span style="color: var(--brand-purple);">  → Unique Keywords:</span> ${stats.unique || 0}`);

            // Calculate reduction properly with fallback
            const totalKw = stats.total_keywords || 0;
            const variants = stats.variants || 0;
            const uniqueAfter = totalKw - variants;
            const reductionPct = totalKw > 0 ? Math.round((variants / totalKw) * 100) : 0;

            if (reductionPct > 0) {
                this.addLog(`<span style="color: var(--brand-warning);">  → Potential Reduction:</span> ${totalKw} → ${uniqueAfter} (${reductionPct}% less cannibalization)`);
            } else {
                this.addLog(`<span style="color: var(--brand-warning);">  → Potential Reduction:</span> No duplicates found`);
            }
            this.addLog(' ');
            this.addLog(`<span style="color: var(--brand-gray-light);">⏱️  Processing Time:</span> ${elapsed} seconds`);

            // Update modal stats
            $('#dedup-clusters-count').text(stats.clusters);
            $('#dedup-variants-count').text(stats.variants);

            $('#modal-confirm').text('📋 View Clusters').prop('disabled', false).off('click').on('click', function () {
                closeModal();
                showClustersInterface();
            });
        }

        showError(message) {
            // Check if it's a table/migration error
            const isMigrationError = message.includes('table') || message.includes('reactivate') || message.includes('column');

            if (isMigrationError) {
                $('#dedup-current-status').html(`
                            <div style="font-weight: 600; color: var(--brand-warning); margin-bottom: 8px; font-size: 15px;">⚠️ Database Setup Required</div>
                            <div style="font-size: 13px; color: var(--brand-white); line-height: 1.6; margin-bottom: 12px;">${message}</div>
                            <div style="background: rgba(139, 92, 246, 0.1); padding: 12px; border-radius: 8px; border-left: 3px solid var(--brand-purple);">
                                <div style="font-size: 12px; color: var(--brand-white); font-weight: 600; margin-bottom: 8px;">🔧 How to Fix:</div>
                                <ol style="margin: 0; padding-left: 20px; font-size: 12px; color: var(--brand-gray-light); line-height: 1.8;">
                                    <li>Go to <strong style="color: var(--brand-white);">Plugins</strong> page</li>
                                    <li><strong style="color: var(--brand-warning);">Deactivate</strong> Wisewand Plugin</li>
                                    <li><strong style="color: var(--brand-success);">Reactivate</strong> Wisewand Plugin</li>
                                    <li>Return here and scan again</li>
                                </ol>
                                <div style="margin-top: 8px; font-size: 11px; color: var(--brand-gray-light);">
                                    This triggers database migrations that create the deduplication tables.
                                </div>
                            </div>
                        `);
                this.addLog('<span style="color: var(--brand-warning);">⚠️ Database migration required</span>');
                this.addLog('<span style="color: var(--brand-gray-light);">→ Please deactivate and reactivate the plugin</span>');
                $('#modal-confirm').text('✓ Got It').prop('disabled', false);
            } else {
                $('#dedup-current-status').html(`
                            <div style="font-weight: 600; color: var(--brand-error); margin-bottom: 6px; font-size: 15px;">❌ Error</div>
                            <div style="font-size: 13px; color: var(--brand-gray-light);">${message}</div>
                        `);
                $('#modal-confirm').text('❌ Failed').prop('disabled', false);
                this.addLog('<span style="color: var(--brand-error);">✗ Scan failed: ' + message + '</span>');
            }
        }
    }

    // AI Category Matcher Progress Manager (Global Scope)
    class AICategoryMatcherProgress {
        constructor(filterMode = 'uncategorized') {
            this.startTime = Date.now();
            this.filterMode = filterMode;
        }

        getHTML() {
            return `
                        <div id="ai-match-progress-container" style="margin-top: 12px;">
                            <div style="background: rgba(10, 14, 39, 0.6); border: 1px solid rgba(16, 185, 129, 0.2); border-radius: 16px; padding: 20px; backdrop-filter: blur(10px);">
                                <!-- Progress Bar -->
                                <div style="margin-bottom: 20px;">
                                    <div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
                                        <span style="font-size: 13px; font-weight: 600; color: var(--brand-white); letter-spacing: 0.05em; text-transform: uppercase;">AI Matching Progress</span>
                                        <span id="ai-match-progress-text" style="font-size: 13px; color: var(--brand-success); font-weight: 600;">Initializing...</span>
                                    </div>
                                    <div style="background: rgba(160, 168, 184, 0.15); border-radius: 12px; height: 10px; overflow: hidden; border: 1px solid rgba(16, 185, 129, 0.2);">
                                        <div id="ai-match-progress-bar" style="background: linear-gradient(90deg, var(--brand-success) 0%, var(--brand-primary) 100%); height: 100%; width: 0%; transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 0 12px rgba(16, 185, 129, 0.5);"></div>
                                    </div>
                                </div>

                                <!-- Current Status -->
                                <div id="ai-match-current-status" style="background: rgba(16, 185, 129, 0.1); border-radius: 12px; padding: 16px; margin-bottom: 16px; border-left: 4px solid var(--brand-success); backdrop-filter: blur(10px);">
                                    <div style="font-weight: 600; color: var(--brand-white); margin-bottom: 6px; font-size: 15px;">Starting AI analysis...</div>
                                    <div id="ai-match-status-detail" style="font-size: 13px; color: var(--brand-gray-light);"></div>
                                </div>

                                <!-- Progress Steps Log -->
                                <div id="ai-match-progress-steps" style="height: 290px; overflow-y: auto; font-size: 12px; font-family: 'Consolas', 'Monaco', monospace; background: #0A0E27; color: #E2E8F0; padding: 16px; border-radius: 12px; line-height: 1.8; border: 1px solid rgba(16, 185, 129, 0.3); box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.3);">
                                    <div style="color: var(--brand-success);">● Initializing AI category matcher...</div>
                                    <div style="color: var(--brand-gray-light);">→ Model: gpt-4o-mini (temperature: 0.3)</div>
                                    <div style="color: var(--brand-gray-light);">→ Batch size: 20 keywords per API call</div>
                                </div>
                            </div>

                            <!-- Info Banner -->
                            <div style="margin-top: 12px; padding: 10px 14px; background: rgba(16, 185, 129, 0.15); border-left: 3px solid var(--brand-success); border-radius: 8px; font-size: 11px; color: var(--brand-white); line-height: 1.5; backdrop-filter: blur(10px); border: 1px solid rgba(16, 185, 129, 0.3);">
                                🤖 <strong style="color: var(--brand-success);">AI-Powered Matching</strong> - Categories will be intelligently matched based on semantic relevance
                            </div>
                        </div>
                    `;
        }

        start() {
            this.addLog('→ Checking OpenAI API configuration...');
            this.addLog(' ');

            this.runMatching();
        }

        runMatching() {
            console.log('🤖 AI Matching: Getting keyword list with filter:', this.filterMode);

            this.addLog('<span style="color: var(--brand-success);">● Initializing</span>');
            this.addLog('<span style="color: var(--brand-gray-light);">  → Fetching keyword list...</span>');

            if (this.filterMode === 'uncategorized') {
                this.addLog('<span style="color: var(--brand-primary);">  → Filter: Only uncategorized keywords</span>');
            } else {
                this.addLog('<span style="color: var(--brand-gray-light);">  → Filter: All keywords</span>');
            }

            // Step 1: Get all keyword IDs
            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_ai_match_categories',
                    filter_mode: this.filterMode,
                    nonce: wisewandSEO.nonce
                },
                success: (response) => {
                    if (response.success && response.data.mode === 'init') {
                        console.log('🤖 Initialization:', response.data);

                        this.keywordIds = response.data.keyword_ids;
                        this.totalKeywords = response.data.total_keywords;
                        this.batchSize = 10; // Reduced to 10 for better reliability
                        this.totalBatches = Math.ceil(this.totalKeywords / this.batchSize);
                        this.currentBatch = 0;
                        this.totalMatched = 0;
                        this.totalSaved = 0;
                        this.failedBatches = [];
                        this.retryCount = {};

                        this.addLog(`<span style="color: var(--brand-success);">  ✓ Found ${this.totalKeywords} keywords</span>`);
                        this.addLog(`<span style="color: var(--brand-gray-light);">  → Will process in ${this.totalBatches} batches (10 per batch)</span>`);
                        this.addLog(`<span style="color: var(--brand-gray-light);">  → Auto-retry on failure (max 3 attempts)</span>`);
                        this.addLog(' ');

                        // Start processing
                        this.processNextBatch();
                    } else {
                        this.showError(response.data.message || 'Initialization failed');
                    }
                },
                error: (xhr) => {
                    console.error('Init error:', xhr);
                    this.handleError(xhr);
                }
            });
        }

        processNextBatch() {
            if (this.currentBatch >= this.totalBatches) {
                // All done!
                this.showComplete({
                    matched_count: this.totalMatched,
                    saved_count: this.totalSaved,
                });
                return;
            }

            const batchNumber = this.currentBatch + 1;
            const startIdx = this.currentBatch * this.batchSize;
            const endIdx = Math.min(startIdx + this.batchSize, this.totalKeywords);
            const batchIds = this.keywordIds.slice(startIdx, endIdx);

            const progress = Math.round((startIdx / this.totalKeywords) * 100);

            $('#ai-match-progress-bar').css('width', progress + '%');
            $('#ai-match-progress-text').text(`Batch ${batchNumber}/${this.totalBatches}`);
            $('#ai-match-current-status div:first').html(`🤖 Processing batch ${batchNumber}/${this.totalBatches}...`);
            $('#ai-match-status-detail').html(`Matching keywords ${startIdx + 1} to ${endIdx}...`);

            this.addLog(`<span style="color: var(--brand-primary);">● Batch ${batchNumber}/${this.totalBatches}:</span> Processing ${batchIds.length} keywords...`);

            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_ai_match_categories',
                    keyword_ids: batchIds,
                    nonce: wisewandSEO.nonce
                },
                success: (response) => {
                    if (response.success && response.data.mode === 'batch_complete') {
                        this.totalMatched += response.data.matched_count || 0;
                        this.totalSaved += response.data.saved_count || 0;

                        this.addLog(`<span style="color: var(--brand-success);">  ✓ Batch ${batchNumber}:</span> ${response.data.matched_count}/${response.data.batch_size} matched`);

                        this.currentBatch++;

                        // Continue with next batch
                        setTimeout(() => this.processNextBatch(), 500);
                    } else {
                        console.warn('Batch response issue:', response);
                        this.addLog(`<span style="color: var(--brand-warning);">  ⚠ Batch ${batchNumber} issue, continuing...</span>`);
                        this.currentBatch++;
                        setTimeout(() => this.processNextBatch(), 500);
                    }
                },
                error: (xhr) => {
                    // Retry logic (max 3 attempts)
                    const batchKey = `batch_${batchNumber}`;
                    this.retryCount[batchKey] = (this.retryCount[batchKey] || 0) + 1;

                    if (this.retryCount[batchKey] < 3) {
                        console.warn(`Batch ${batchNumber} error, retry ${this.retryCount[batchKey]}/3:`, xhr);
                        this.addLog(`<span style="color: var(--brand-warning);">  ⚠ Batch ${batchNumber} error, retrying (${this.retryCount[batchKey]}/3)...</span>`);

                        // Retry same batch after delay
                        setTimeout(() => this.processNextBatch(), 1000);
                    } else {
                        // Failed after 3 retries
                        console.error(`Batch ${batchNumber} failed after 3 retries`);
                        this.addLog(`<span style="color: var(--brand-error);">  ✗ Batch ${batchNumber} failed after 3 retries, skipping...</span>`);
                        this.failedBatches.push(batchNumber);

                        this.currentBatch++;
                        setTimeout(() => this.processNextBatch(), 500);
                    }
                }
            });
        }

        addLog(message) {
            const $log = $('#ai-match-progress-steps');
            $log.append('<div>' + message + '</div>');
            $log.scrollTop($log[0].scrollHeight);
        }

        showComplete(data) {
            const elapsed = ((Date.now() - this.startTime) / 1000).toFixed(1);

            console.log('🤖 showComplete called with data:', data);
            console.log('🤖 matched_count:', data.matched_count);
            console.log('🤖 saved_count:', data.saved_count);

            // Check if actually got matches
            if (data.matched_count === 0 || data.saved_count === 0) {
                console.warn('⚠️ AI Matching returned 0 results!');
                console.warn('⚠️ This usually means:');
                console.warn('  1. OpenAI API error (check debug.log)');
                console.warn('  2. No categories match keywords');
                console.warn('  3. All matches filtered out (invalid IDs)');
                console.warn('⚠️ Check wp-content/debug.log for details!');

                this.addLog(' ');
                this.addLog('<span style="color: var(--brand-warning);">⚠️ No matches found!</span>');
                this.addLog('<span style="color: var(--brand-gray-light);">  → Check wp-content/debug.log for details</span>');
                this.addLog('<span style="color: var(--brand-gray-light);">  → Possible: API error, no category matches, or validation filtered all</span>');
            }

            $('#ai-match-progress-text').text('Complete!');
            $('#ai-match-current-status div:first').html('✅ AI Matching Complete!');
            $('#ai-match-status-detail').html(`Matched ${data.saved_count} keywords to categories`);

            const completionRate = ((data.saved_count / this.totalKeywords) * 100).toFixed(1);

            this.addLog(' ');
            this.addLog('<span style="color: var(--brand-success); font-weight: 600;">✅ AI MATCHING COMPLETE!</span>');
            this.addLog(' ');
            this.addLog(`<span style="color: var(--brand-white);">📊 Results:</span>`);
            this.addLog(`<span style="color: var(--brand-success);">  → Keywords Processed:</span> ${this.totalKeywords}`);
            this.addLog(`<span style="color: var(--brand-success);">  → Successfully Matched:</span> ${data.matched_count}`);
            this.addLog(`<span style="color: var(--brand-primary);">  → Saved to Database:</span> ${data.saved_count}`);
            this.addLog(`<span style="color: var(--brand-purple);">  → Completion Rate:</span> ${completionRate}%`);

            if (this.failedBatches.length > 0) {
                this.addLog(' ');
                this.addLog(`<span style="color: var(--brand-warning);">  ⚠️ Failed Batches:</span> ${this.failedBatches.length} (after 3 retries each)`);
                this.addLog(`<span style="color: var(--brand-gray-light);">     Batches: ${this.failedBatches.join(', ')}</span>`);
            }

            this.addLog(' ');
            this.addLog(`<span style="color: var(--brand-gray-light);">⏱️  Processing Time:</span> ${elapsed} seconds`);
            this.addLog(`<span style="color: var(--brand-gray-light);">🤖 Model:</span> gpt-4o-mini (temp: 0.3)`);
            this.addLog(`<span style="color: var(--brand-gray-light);">📦 Batch Size:</span> 10 keywords`);

            if (data.matched_count === 0) {
                this.addLog(' ');
                this.addLog('<span style="color: var(--brand-warning);">⚠️ Debug: Check browser console (F12) and wp-content/debug.log</span>');
            }

            $('#modal-confirm').text('✅ Done').prop('disabled', false).off('click').on('click', function () {
                closeModal();
                // Always reload to show updated data (even if 0 matches shown, data might exist)
                location.reload();
            });
        }

        showError(message) {
            // Check if it's an API key error
            if (message.includes('API key') || message.includes('OpenAI')) {
                $('#ai-match-current-status').html(`
                            <div style="font-weight: 600; color: var(--brand-warning); margin-bottom: 8px; font-size: 15px;">⚠️ OpenAI Not Configured</div>
                            <div style="font-size: 13px; color: var(--brand-white); line-height: 1.6; margin-bottom: 12px;">${message}</div>
                            <a href="${wisewandSEO.settingsUrl}" class="button button-primary" style="background: var(--brand-success); border: none;">
                                ⚙️ Go to Settings
                            </a>
                        `);
                this.addLog('<span style="color: var(--brand-warning);">⚠️ API key not configured</span>');
                this.addLog('<span style="color: var(--brand-gray-light);">→ Please add your OpenAI API key in Settings</span>');
            } else {
                $('#ai-match-current-status').html(`
                            <div style="font-weight: 600; color: var(--brand-error); margin-bottom: 6px; font-size: 15px;">❌ Error</div>
                            <div style="font-size: 13px; color: var(--brand-gray-light);">${message}</div>
                        `);
                this.addLog('<span style="color: var(--brand-error);">✗ AI matching failed: ' + message + '</span>');
            }

            $('#modal-confirm').text('✓ Got It').prop('disabled', false);
        }

        handleError(xhr) {
            console.error('AI matching error:', xhr);

            let errorMsg = 'Network error. Please try again.';

            if (xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {
                errorMsg = xhr.responseJSON.data.message;
            }

            this.showError(errorMsg);
        }
    }

    // Show Clusters Interface
    function showClustersInterface() {
        // Fetch clusters and display
        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_get_clusters',
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    displayClustersModal(response.data.clusters, response.data.stats);
                } else {
                    showErrorModal('Error', response.data.message || 'Failed to load clusters');
                }
            },
            error: function () {
                showErrorModal('Error', 'Network error loading clusters');
            }
        });
    }

    function displayClustersModal(clusters, stats) {
        const modalBody = `
                    <div style="color: var(--brand-white);">
                        <!-- Stats Header -->
                        <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 20px;">
                            <div style="background: rgba(139, 92, 246, 0.15); padding: 12px; border-radius: 8px; text-align: center; border: 1px solid rgba(139, 92, 246, 0.3);">
                                <div style="font-size: 24px; font-weight: 700; color: var(--brand-purple);">${stats.total_clusters || 0}</div>
                                <div style="font-size: 11px; color: var(--brand-gray-light);">Clusters</div>
                            </div>
                            <div style="background: rgba(16, 185, 129, 0.15); padding: 12px; border-radius: 8px; text-align: center; border: 1px solid rgba(16, 185, 129, 0.3);">
                                <div style="font-size: 24px; font-weight: 700; color: var(--brand-success);">${stats.total_variants || 0}</div>
                                <div style="font-size: 11px; color: var(--brand-gray-light);">Variants</div>
                            </div>
                            <div style="background: rgba(0, 188, 212, 0.15); padding: 12px; border-radius: 8px; text-align: center; border: 1px solid rgba(0, 188, 212, 0.3);">
                                <div style="font-size: 24px; font-weight: 700; color: var(--brand-primary);">${stats.unique_keywords || 0}</div>
                                <div style="font-size: 11px; color: var(--brand-gray-light);">Unique</div>
                            </div>
                            <div style="background: rgba(245, 158, 11, 0.15); padding: 12px; border-radius: 8px; text-align: center; border: 1px solid rgba(245, 158, 11, 0.3);">
                                <div style="font-size: 24px; font-weight: 700; color: var(--brand-warning);">${Math.round(stats.avg_similarity * 100) || 0}%</div>
                                <div style="font-size: 11px; color: var(--brand-gray-light);">Avg Similarity</div>
                            </div>
                        </div>

                        <!-- Bulk Actions -->
                        ${clusters.length > 0 ? `
                        <div style="display: flex; gap: 12px; justify-content: center; margin-bottom: 20px; padding: 16px; background: rgba(139, 92, 246, 0.1); border-radius: 12px; border: 1px solid rgba(139, 92, 246, 0.3);">
                            <button type="button" id="accept-all-delete-variants" data-total-clusters="${clusters.length}" style="background: var(--brand-success); color: white; border: none; padding: 10px 20px; border-radius: 8px; font-size: 13px; cursor: pointer; font-weight: 600; box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3); transition: all 0.2s;">
                                ✅ Accept All & Delete Variants
                            </button>
                            <button type="button" id="expand-all-clusters" style="background: var(--brand-purple); color: white; border: none; padding: 10px 20px; border-radius: 8px; font-size: 13px; cursor: pointer; font-weight: 600; box-shadow: 0 2px 8px rgba(139, 92, 246, 0.3); transition: all 0.2s;">
                                ▼ Expand All
                            </button>
                            <button type="button" id="collapse-all-clusters" style="background: var(--brand-gray); color: white; border: none; padding: 10px 20px; border-radius: 8px; font-size: 13px; cursor: pointer; font-weight: 600; display: none;">
                                ▲ Collapse All
                            </button>
                        </div>
                        ` : ''}

                        <!-- Clusters List -->
                        <div id="clusters-list" style="max-height: 500px; overflow-y: auto; padding-right: 8px;">
                            ${clusters.length === 0 ? '<div style="text-align: center; padding: 40px; color: var(--brand-gray-light);">No clusters found. All keywords are unique!</div>' : ''}
                        </div>
                    </div>
                `;

        // Show in larger modal
        $('#modal-title').html('🔗 Keyword Clusters (' + clusters.length + ')');
        $('#modal-body').html(modalBody);
        $('#modal-confirm').hide();
        $('#wisewand-modal').fadeIn(200);

        // Render each cluster
        if (clusters.length > 0) {
            clusters.forEach((cluster, index) => {
                const clusterCard = buildClusterCard(cluster, index + 1);
                $('#clusters-list').append(clusterCard);
            });
        }
    }

    function buildClusterCard(cluster, index) {
        const similarityPercent = Math.round((cluster.cluster_metrics.avg_similarity || 0) * 100);
        const similarityColor = similarityPercent >= 95 ? 'var(--brand-success)' :
            similarityPercent >= 85 ? 'var(--brand-warning)' :
                'var(--brand-error)';

        const variants = cluster.variants || [];
        const primary = cluster.primary_data || {};

        // Build ranking badge for primary keyword
        let rankingBadge = '';
        if (primary.is_ranking) {
            const position = primary.position_abs || '?';
            rankingBadge = `
                        <span style="background: linear-gradient(135deg, #f59e0b, #ef4444); color: white; padding: 4px 10px; border-radius: 12px; font-size: 11px; font-weight: 700; display: inline-block; margin-left: 8px; box-shadow: 0 2px 8px rgba(245, 158, 11, 0.4);">
                            🏆 #${position}
                        </span>
                    `;
        }

        // Build tier badge for primary keyword
        let tierBadge = '';
        const tierMap = {
            'ranking': { emoji: '🏆', label: 'Ranking', color: '#f59e0b', bg: 'rgba(245, 158, 11, 0.15)' },
            'published': { emoji: '✅', label: 'Published', color: '#10b981', bg: 'rgba(16, 185, 129, 0.15)' },
            'scheduled': { emoji: '📅', label: 'Scheduled', color: '#3b82f6', bg: 'rgba(59, 130, 246, 0.15)' },
            'planned': { emoji: '📝', label: 'Planned', color: '#8b5cf6', bg: 'rgba(139, 92, 246, 0.15)' },
        };

        const tier = tierMap[primary.priority_tier] || tierMap['planned'];
        tierBadge = `
                    <span style="background: ${tier.bg}; color: ${tier.color}; padding: 3px 8px; border-radius: 10px; font-size: 10px; font-weight: 700; display: inline-block; margin-left: 6px; border: 1px solid ${tier.color};">
                        ${tier.emoji} ${tier.label}
                    </span>
                `;

        // Build protection warning if primary is ranking
        let protectionWarning = '';
        if (primary.is_ranking && primary.is_protected) {
            protectionWarning = `
                        <div style="background: rgba(245, 158, 11, 0.1); border: 1px solid rgba(245, 158, 11, 0.5); border-radius: 8px; padding: 10px; margin-bottom: 12px;">
                            <div style="font-size: 12px; color: #fbbf24; font-weight: 600; margin-bottom: 4px;">
                                🛡️ Protected Ranking Keyword
                            </div>
                            <div style="font-size: 11px; color: var(--brand-gray-light); line-height: 1.4;">
                                This keyword is currently ranking at position #${primary.position_abs || '?'}. It's protected from being deleted to prevent losing your ranking.
                            </div>
                        </div>
                    `;
        }

        let variantsHTML = '';
        variants.forEach(variant => {
            // Build variant ranking badge
            let variantRankingBadge = '';
            if (variant.is_ranking) {
                variantRankingBadge = `<span style="background: #ef4444; color: white; padding: 2px 6px; border-radius: 8px; font-size: 10px; font-weight: 700; margin-left: 6px;">🏆 #${variant.position_abs || '?'}</span>`;
            }

            // Build variant tier badge
            let variantTierBadge = '';
            if (variant.priority_tier) {
                const vTier = tierMap[variant.priority_tier] || tierMap['planned'];
                variantTierBadge = `<span style="background: ${vTier.bg}; color: ${vTier.color}; padding: 2px 6px; border-radius: 8px; font-size: 9px; font-weight: 700; margin-left: 4px; border: 1px solid ${vTier.color};">${vTier.emoji}</span>`;
            }

            // Disable radio if variant is protected ranking
            const isProtected = variant.is_ranking && variant.is_protected;
            const disabledAttr = isProtected ? 'disabled' : '';
            const protectedWarningIcon = isProtected ? '<span style="color: #fbbf24; font-size: 14px; margin-left: 4px;" title="Protected ranking keyword">🛡️</span>' : '';

            variantsHTML += `
                        <label style="display: flex; align-items: center; gap: 12px; padding: 8px 12px; background: rgba(139, 92, 246, 0.05); border-radius: 6px; cursor: ${isProtected ? 'not-allowed' : 'pointer'}; margin-bottom: 6px; border: 1px solid rgba(139, 92, 246, 0.2); transition: all 0.2s; opacity: ${isProtected ? '0.6' : '1'};">
                            <input type="radio" name="cluster-${cluster.id}-primary" value="${variant.id}" data-cluster-id="${cluster.id}" class="cluster-primary-radio" style="width: auto; margin: 0;" ${disabledAttr}>
                            <div style="flex: 1;">
                                <div style="font-weight: 600; color: var(--brand-white); font-size: 13px;">
                                    ${escapeHtml(variant.keyword)}${variantRankingBadge}${variantTierBadge}${protectedWarningIcon}
                                </div>
                                <div style="font-size: 11px; color: var(--brand-gray-light); margin-top: 2px;">
                                    Vol: ${formatNumber(variant.search_volume)} | Priority: ${variant.priority_score || 0} | Difficulty: ${variant.difficulty || '-'}%
                                </div>
                            </div>
                        </label>
                    `;
        });

        return `
                    <div class="cluster-card" data-cluster-id="${cluster.id}" style="background: rgba(10, 14, 39, 0.6); border: 1px solid rgba(139, 92, 246, 0.3); border-radius: 12px; padding: 16px; margin-bottom: 16px; backdrop-filter: blur(10px);">
                        ${protectionWarning}

                        <!-- Header -->
                        <div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 16px;">
                            <div style="flex: 1;">
                                <div style="font-size: 11px; color: var(--brand-gray-light); margin-bottom: 4px;">CLUSTER #${index}</div>
                                <div style="font-size: 15px; font-weight: 700; color: var(--brand-white); margin-bottom: 6px;">
                                    🔗 ${escapeHtml(cluster.primary_keyword)}${rankingBadge}${tierBadge}
                                </div>
                                <div style="font-size: 12px; color: var(--brand-gray-light);">
                                    Vol: ${formatNumber(cluster.search_volume)} | Priority: ${cluster.priority_score || 0} | Intent: ${cluster.search_intent || 'N/A'}
                                </div>
                            </div>
                            <div style="text-align: right;">
                                <div style="background: ${similarityColor}; color: white; padding: 4px 12px; border-radius: 12px; font-size: 12px; font-weight: 700; display: inline-block;">
                                    ${similarityPercent}%
                                </div>
                                <div style="font-size: 10px; color: var(--brand-gray-light); margin-top: 4px;">
                                    ${variants.length} variant${variants.length > 1 ? 's' : ''}
                                </div>
                            </div>
                        </div>

                        <!-- Variants (Collapsible) -->
                        <div class="cluster-variants-toggle" data-cluster-id="${cluster.id}" style="cursor: pointer; padding: 8px; background: rgba(139, 92, 246, 0.1); border-radius: 6px; margin-bottom: 12px; transition: all 0.2s;">
                            <span class="toggle-arrow" style="color: var(--brand-white); font-weight: 600; font-size: 13px;">▼ Show ${variants.length} Variant${variants.length > 1 ? 's' : ''}</span>
                            <span style="color: var(--brand-gray-light); font-size: 11px; margin-left: 8px;">(click to expand)</span>
                        </div>

                        <div class="cluster-variants-list" data-cluster-id="${cluster.id}" style="display: none; margin-bottom: 16px;">
                            <div style="font-size: 12px; color: var(--brand-gray-light); margin-bottom: 8px;">Select a variant to make it the primary keyword:</div>
                            ${variantsHTML}
                        </div>

                        <!-- Actions -->
                        <div style="display: flex; gap: 8px; flex-wrap: wrap;">
                            <button type="button" class="btn-accept-delete-cluster" data-cluster-id="${cluster.id}" data-variant-count="${variants.length}" data-variants='${JSON.stringify(variants.map(v => v.keyword))}' style="background: var(--brand-success); color: white; border: none; padding: 6px 12px; border-radius: 6px; font-size: 12px; cursor: pointer; font-weight: 600;">
                                ✓ Accept & Delete Variants
                            </button>
                            <button type="button" class="btn-schedule-cluster" data-cluster-id="${cluster.id}" data-keyword="${escapeHtml(cluster.primary_keyword)}" style="background: var(--brand-primary); color: white; border: none; padding: 6px 12px; border-radius: 6px; font-size: 12px; cursor: pointer; font-weight: 600;">
                                📅 Schedule Primary
                            </button>
                            <button type="button" class="btn-ungroup-cluster" data-cluster-id="${cluster.id}" style="background: var(--brand-gray); color: white; border: none; padding: 6px 12px; border-radius: 6px; font-size: 12px; cursor: pointer; font-weight: 600;">
                                ❌ Not Duplicates
                            </button>
                        </div>
                    </div>
                `;
    }

    // Toggle cluster variants (event delegation)
    $(document).on('click', '.cluster-variants-toggle', function () {
        const clusterId = $(this).data('cluster-id');
        const $variantsList = $('.cluster-variants-list[data-cluster-id="' + clusterId + '"]');
        const $arrow = $(this).find('.toggle-arrow');

        $variantsList.slideToggle(200, function () {
            // Update arrow direction
            if ($variantsList.is(':visible')) {
                $arrow.html($arrow.html().replace('▼ Show', '▲ Hide'));
            } else {
                $arrow.html($arrow.html().replace('▲ Hide', '▼ Show'));
            }
        });
    });

    function escapeHtml(text) {
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }

    function formatNumber(num) {
        if (!num) return '0';
        return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    }

    // Cluster Action: Change Primary
    $(document).on('change', '.cluster-primary-radio', function () {
        const newPrimaryId = $(this).val();
        const clusterId = $(this).data('cluster-id');

        if (!confirm('Set this keyword as the cluster primary?')) {
            return;
        }

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_set_cluster_primary',
                cluster_id: clusterId,
                new_primary_id: newPrimaryId,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    showSuccessModal('✅ Updated', 'Primary keyword updated successfully');
                    setTimeout(() => {
                        closeModal();
                        showClustersInterface(); // Refresh
                    }, 1500);
                } else {
                    alert('❌ ' + (response.data?.message || 'Failed'));
                }
            }
        });
    });

    // Cluster Action: Ungroup (Not Duplicates)
    $(document).on('click', '.btn-ungroup-cluster', function () {
        const clusterId = $(this).data('cluster-id');

        if (!confirm('Mark these keywords as NOT duplicates? They won\'t be clustered together in future scans.')) {
            return;
        }

        const $btn = $(this);
        $btn.prop('disabled', true).text('Ungrouping...');

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_ungroup_cluster',
                cluster_id: clusterId,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    $('[data-cluster-id="' + clusterId + '"]').fadeOut(300);
                    setTimeout(() => {
                        showClustersInterface(); // Refresh
                    }, 500);
                } else {
                    alert('❌ ' + (response.data?.message || 'Failed'));
                    $btn.prop('disabled', false).text('❌ Not Duplicates');
                }
            }
        });
    });

    // Cluster Action: Accept & Delete Variants
    $(document).on('click', '.btn-accept-delete-cluster', function () {
        const clusterId = $(this).data('cluster-id');
        const variantCount = $(this).data('variant-count');
        const variants = $(this).data('variants');
        const $btn = $(this);

        // Build variants list for confirmation
        let variantsList = '';
        if (Array.isArray(variants)) {
            variants.forEach((v, i) => {
                if (i < 10) { // Show max 10 in confirmation
                    variantsList += `\n  • ${v}`;
                }
            });
            if (variants.length > 10) {
                variantsList += `\n  • ... and ${variants.length - 10} more`;
            }
        }

        // Strong confirmation dialog
        const confirmMessage = `⚠️ PERMANENT ACTION

This will DELETE ${variantCount} variant keyword${variantCount > 1 ? 's' : ''} from your library.
Only the primary keyword will be kept.

Variants to delete:${variantsList}

This cannot be undone. Are you sure?`;

        if (!confirm(confirmMessage)) {
            return;
        }

        $btn.prop('disabled', true).text('⏳ Processing...');

        // First approve, then delete
        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_approve_cluster',
                cluster_id: clusterId,
                nonce: wisewandSEO.nonce
            },
            success: () => {
                // Now delete variants
                $.ajax({
                    url: wisewandSEO.ajaxUrl,
                    type: 'POST',
                    data: {
                        action: 'wisewand_delete_cluster_variants',
                        cluster_id: clusterId,
                        nonce: wisewandSEO.nonce
                    },
                    success: function (response) {
                        if (response.success) {
                            $btn.text('✅ Accepted').css('background', '#6b7280').prop('disabled', false);
                            showSuccessModal('✅ Complete', `Cluster accepted. ${response.data.deleted} variant(s) deleted from library.`);

                            setTimeout(() => {
                                closeModal();
                                loadLatestSnapshot(); // Refresh keywords table
                            }, 2000);
                        } else {
                            alert('❌ ' + (response.data?.message || 'Failed to delete variants'));
                            $btn.prop('disabled', false).text('✓ Accept & Delete Variants');
                        }
                    }
                });
            },
            error: () => {
                alert('❌ Failed to approve cluster');
                $btn.prop('disabled', false).text('✓ Accept & Delete Variants');
            }
        });
    });

    // Cluster Action: Schedule Primary
    $(document).on('click', '.btn-schedule-cluster', function () {
        const keyword = $(this).data('keyword');
        const clusterId = $(this).data('cluster-id');

        // Find the keyword in the table and schedule it
        const $keywordRow = $('.col-keyword strong').filter(function () {
            return $(this).text() === keyword;
        }).closest('tr');

        if ($keywordRow.length > 0) {
            const $scheduleBtn = $keywordRow.find('.btn-schedule-saved');
            if ($scheduleBtn.length > 0) {
                $scheduleBtn.trigger('click');
                closeModal();
            }
        }
    });

    // Bulk Action: Accept All & Delete All Variants
    $(document).on('click', '#accept-all-delete-variants', function () {
        const clusterCards = $('.cluster-card');
        const totalClusters = clusterCards.length;
        let totalVariants = 0;
        const variantsList = [];

        // Count total variants and build list
        clusterCards.each(function () {
            const $btn = $(this).find('.btn-accept-delete-cluster');
            const variantCount = $btn.data('variant-count') || 0;
            const variants = $btn.data('variants') || [];

            totalVariants += variantCount;

            if (Array.isArray(variants)) {
                variants.forEach(v => {
                    if (variantsList.length < 15) { // Show max 15 in confirmation
                        variantsList.push(v);
                    }
                });
            }
        });

        // Build confirmation message
        let variantsListText = '';
        variantsList.forEach(v => {
            variantsListText += `\n  • ${v}`;
        });
        if (totalVariants > 15) {
            variantsListText += `\n  • ... and ${totalVariants - 15} more`;
        }

        const confirmMessage = `⚠️ PERMANENT BULK ACTION

This will:
1. Accept all ${totalClusters} clusters
2. DELETE ${totalVariants} variant keywords from your library
3. Keep only the ${totalClusters} primary keywords

Sample variants to delete:${variantsListText}

Total keywords removed: ${totalVariants}
This cannot be undone. Are you absolutely sure?`;

        if (!confirm(confirmMessage)) {
            return;
        }

        const $btn = $(this);
        $btn.prop('disabled', true).text('⏳ Processing...');

        // Collect all cluster IDs
        const clusterIds = [];
        clusterCards.each(function () {
            clusterIds.push($(this).data('cluster-id'));
        });

        let completed = 0;
        let approvedCount = 0;
        let deletedCount = 0;
        let errors = 0;

        // Process each cluster: approve then delete
        clusterIds.forEach(clusterId => {
            // First approve
            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_approve_cluster',
                    cluster_id: clusterId,
                    nonce: wisewandSEO.nonce
                },
                success: () => {
                    approvedCount++;

                    // Then delete variants
                    $.ajax({
                        url: wisewandSEO.ajaxUrl,
                        type: 'POST',
                        data: {
                            action: 'wisewand_delete_cluster_variants',
                            cluster_id: clusterId,
                            nonce: wisewandSEO.nonce
                        },
                        success: function (response) {
                            if (response.success) {
                                deletedCount += response.data.deleted || 0;
                                $('.cluster-card[data-cluster-id="' + clusterId + '"] .btn-accept-delete-cluster')
                                    .text('✅ Accepted').css('background', '#6b7280');
                            } else {
                                errors++;
                            }

                            completed++;
                            if (completed === clusterIds.length) {
                                $btn.text(`✅ Complete (${deletedCount} deleted)`).prop('disabled', false);

                                showSuccessModal('✅ All Clusters Accepted', `
                                            <strong>Bulk action complete!</strong><br><br>
                                            ✓ Approved: ${approvedCount} clusters<br>
                                            🗑️ Deleted: ${deletedCount} variant keywords<br>
                                            ${errors > 0 ? `⚠️ Errors: ${errors}<br>` : ''}
                                            <br>
                                            Your keyword library has been optimized.
                                        `);

                                setTimeout(() => {
                                    closeModal();
                                    loadLatestSnapshot();
                                }, 3000);
                            }
                        },
                        error: () => {
                            errors++;
                            completed++;
                        }
                    });
                },
                error: () => {
                    errors++;
                    completed++;
                }
            });
        });
    });

    // Bulk Action: Expand All
    $(document).on('click', '#expand-all-clusters', function () {
        $('.cluster-variants-list').slideDown(200);
        $('.toggle-arrow').each(function () {
            $(this).html($(this).html().replace('▼ Show', '▲ Hide'));
        });
        $('#expand-all-clusters').hide();
        $('#collapse-all-clusters').show();
    });

    // Bulk Action: Collapse All
    $(document).on('click', '#collapse-all-clusters', function () {
        $('.cluster-variants-list').slideUp(200);
        $('.toggle-arrow').each(function () {
            $(this).html($(this).html().replace('▲ Hide', '▼ Show'));
        });
        $('#collapse-all-clusters').hide();
        $('#expand-all-clusters').show();
    });

    // Inline Edit: Author Dropdown (auto-save on change)
    $(document).on('change', '.keyword-author-select', function () {
        const $select = $(this);
        const keywordId = $select.data('keyword-id');
        const authorId = $select.val();

        console.log('Saving author:', keywordId, authorId);

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_save_keyword_author_categories',
                keyword_id: keywordId,
                author_id: authorId,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    $select.css('background', '#d1fae5'); // Green flash
                    setTimeout(() => $select.css('background', '#ffffff'), 1000);
                } else {
                    alert('Failed to save author');
                }
            }
        });
    });

    // Open Category Selection Modal (click on badges)
    $(document).on('click', '.open-category-modal', function () {
        const keywordId = $(this).data('keyword-id');
        const currentIds = $(this).data('category-ids') || [];
        openCategorySelectionModal(keywordId, currentIds);
    });

    function openCategorySelectionModal(keywordId, currentCategoryIds) {
        const allCats = wisewandSEO.allCategories || [];

        const modalBody = `<div style="color: var(--brand-white);"><input type="search" id="cat-search" placeholder="🔍 Search categories..." style="width: 100%; padding: 10px; border: 1px solid rgba(0, 188, 212, 0.3); border-radius: 6px; background: rgba(10, 14, 39, 0.6); color: #fff; font-size: 14px; margin-bottom: 16px;"><div id="sel-cats" style="margin-bottom: 16px; padding: 12px; background: rgba(16, 185, 129, 0.1); border-radius: 8px; border-left: 3px solid var(--brand-success); min-height: 50px;"><div style="font-size: 12px; font-weight: 600; margin-bottom: 8px; color: var(--brand-success);">✓ Selected (<span id="sel-count">0</span>)</div><div id="sel-badges" style="display: flex; gap: 6px; flex-wrap: wrap;"><span style="font-size: 11px; color: #94a3b8;">Click checkboxes below</span></div></div><div id="all-cats" style="max-height: 400px; overflow-y: auto; padding: 12px; background: rgba(10, 14, 39, 0.6); border-radius: 8px; border: 1px solid rgba(0, 188, 212, 0.2);"></div></div>`;

        showModal('📁 Select Categories', modalBody, '💾 Save', function () {
            const sel = $('.cat-cb:checked').map(function () { return parseInt($(this).data('cat-id')); }).get();
            $('#modal-confirm').prop('disabled', true).text('💾 Saving...');
            $.ajax({ url: wisewandSEO.ajaxUrl, type: 'POST', data: { action: 'wisewand_save_keyword_author_categories', keyword_id: keywordId, category_ids: sel, nonce: wisewandSEO.nonce }, success: (r) => { if (r.success) { $('#modal-confirm').text('✅ Saved!'); setTimeout(() => { closeModal(); location.reload(); }, 800); } else { alert('Failed'); $('#modal-confirm').prop('disabled', false).text('💾 Save'); } } });
        });

        const $list = $('#all-cats');
        allCats.forEach(c => {
            const chk = currentCategoryIds.includes(c.id) ? 'checked' : '';
            const nm = c.parent_name ? c.parent_name + ' > ' + c.name : c.name;
            $list.append(`<label class="cat-item" data-name="${nm.toLowerCase()}" style="display: flex; align-items: center; gap: 10px; padding: 10px; cursor: pointer; border-radius: 6px; margin-bottom: 2px; border: 1px solid transparent;"><input type="checkbox" class="cat-cb" data-cat-id="${c.id}" data-cat-name="${c.name}" ${chk} style="width: auto; margin: 0;"><span style="font-size: 13px; color: #fff;">${nm}</span></label>`);
        });

        $(document).on('mouseenter', '.cat-item', function () { $(this).css({ 'background': 'rgba(0, 188, 212, 0.1)', 'border-color': 'rgba(0, 188, 212, 0.3)' }); });
        $(document).on('mouseleave', '.cat-item', function () { $(this).css({ 'background': 'transparent', 'border-color': 'transparent' }); });
        $(document).on('change', '.cat-cb', upSel);
        $('#cat-search').on('input', function () { const s = $(this).val().toLowerCase(); $('.cat-item').each(function () { $(this).toggle(($(this).data('name') || '').includes(s)); }); });

        upSel();

        function upSel() {
            const $s = $('.cat-cb:checked');
            const cnt = $s.length;
            $('#sel-count').text(cnt);
            const $b = $('#sel-badges');
            if (cnt === 0) {
                $b.html('<span style="font-size: 11px; color: #94a3b8;">Click checkboxes below</span>');
            } else {
                $b.empty();
                $s.each(function () {
                    const n = $(this).data('cat-name');
                    const i = $(this).data('cat-id');
                    $b.append(`<span style="font-size: 11px; color: #1e293b; background: #e0f2fe; padding: 4px 8px; border-radius: 4px; display: inline-flex; align-items: center; gap: 4px;">${n} <button type="button" onclick="$('.cat-cb[data-cat-id=${i}]').prop('checked', false).trigger('change')" style="background: none; border: none; color: #64748b; cursor: pointer; padding: 0;">×</button></span>`);
                });
            }
        }
    }

    // Column Visibility Toggle
    $('#toggle-columns-btn').on('click', function () {
        $('#column-visibility-panel').slideToggle(200);
    });

    // Load saved column preferences
    function loadColumnPreferences() {
        const savedPrefs = localStorage.getItem('wisewand_column_prefs');
        if (savedPrefs) {
            try {
                const prefs = JSON.parse(savedPrefs);
                Object.keys(prefs).forEach(column => {
                    const isVisible = prefs[column];
                    $(`.column-toggle[data-column="${column}"]`).prop('checked', isVisible);
                    toggleColumn(column, isVisible);
                });
            } catch (e) {
                console.error('Error loading column preferences:', e);
            }
        }
    }

    // Toggle column visibility
    function toggleColumn(columnName, isVisible) {
        const $table = $('.seo-table');
        if (isVisible) {
            $table.find(`[data-column="${columnName}"]`).show();
            $table.find(`[data-column-target="${columnName}"]`).show();
        } else {
            $table.find(`[data-column="${columnName}"]`).hide();
            $table.find(`[data-column-target="${columnName}"]`).hide();
        }
    }

    // Save column preferences
    function saveColumnPreferences() {
        const prefs = {};
        $('.column-toggle').each(function () {
            const column = $(this).data('column');
            prefs[column] = $(this).is(':checked');
        });

        localStorage.setItem('wisewand_column_prefs', JSON.stringify(prefs));

        // Also save to database for cross-device sync
        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_save_column_preferences',
                preferences: JSON.stringify(prefs),
                nonce: wisewandSEO.nonce
            }
        });
    }

    // Handle column toggle clicks
    $('.column-toggle').on('change', function () {
        const column = $(this).data('column');
        const isVisible = $(this).is(':checked');

        toggleColumn(column, isVisible);
        saveColumnPreferences();
    });

    // Load preferences on page ready
    loadColumnPreferences();

    // Generate Smart Roadmap - Enhanced Modal with Two Buttons

    // Update "Schedule Selected" button visibility based on checkbox selections
    function updateScheduleSelectedButton() {
        // Count only VISIBLE checked boxes to match what user sees
        const selectedCount = $('.select-keyword-row:visible:checked').length;

        if (selectedCount > 0) {
            $('#schedule-selected-roadmap')
                .show()
                .find('.selected-keywords-count')
                .text(selectedCount);
        } else {
            $('#schedule-selected-roadmap').hide();
        }
    }

    // Update button visibility when checkboxes change
    $('.seo-table').on('change', '.select-keyword-row', updateScheduleSelectedButton);
    $('.select-all-keywords').on('change', function () {
        setTimeout(updateScheduleSelectedButton, 100);
    });

    // Button A: Generate All Keywords
    $('#generate-all-roadmap').on('click', function () {
        console.log('=== ROADMAP: Generate All clicked ===');
        openRoadmapModal('all');
    });

    // Button B: Schedule Selected Keywords
    $('#schedule-selected-roadmap').on('click', function () {
        console.log('=== ROADMAP: Schedule Selected clicked ===');
        // Count only VISIBLE checked boxes to match what user sees
        const selectedCount = $('.select-keyword-row:visible:checked').length;
        if (selectedCount === 0) {
            alert('Please select keywords first');
            return;
        }
        openRoadmapModal('selected');
    });

    // Extract modal opening logic to function
    function openRoadmapModal(selectionMode) {
        console.log('=== ROADMAP: Opening modal with mode:', selectionMode, '===');

        const marketValue = $('#market-selector').val();
        console.log('Market selector value:', marketValue);

        if (!marketValue) {
            alert('Error: Market selector not found');
            return;
        }

        const [language, location] = marketValue.split(':');
        console.log('Language:', language, 'Location:', location);

        // Count selected keywords in table
        // Count only VISIBLE checked boxes to match what user sees
        const selectedCount = $('.select-keyword-row:visible:checked').length;
        const totalKeywords = $('.seo-table tbody tr').length;

        console.log('Selected:', selectedCount, 'Total:', totalKeywords);
        // Phase 5: Part D - Allow today as start date
        const today = new Date();
        const todayStr = today.toISOString().split('T')[0];

        // Build modal title based on selection mode
        let modalTitle = '🚀 Generate Smart Roadmap';
        if (selectionMode === 'selected') {
            modalTitle += ` (${selectedCount} Selected Keywords)`;
        }

        const modalBody = `
                    <div class="modal-form-group">
                        <label>📊 Keyword Selection</label>
                        <select id="roadmap-keyword-source" class="modal-select">
                            <option value="auto" ${selectionMode === 'all' ? 'selected' : ''}>🤖 Auto-Select Best Keywords (Smart AI Selection)</option>
                            <option value="selected" ${selectionMode === 'selected' ? 'selected' : ''} ${selectedCount === 0 ? 'disabled' : ''}>✅ Use Selected from Table (${selectedCount} selected)</option>
                            <option value="all" ${selectionMode === 'all' ? '' : ''}>📚 All Keywords in Table (${totalKeywords} total)</option>
                        </select>
                        <p style="font-size: 11px; color: var(--brand-gray-light); margin-top: 6px;">
                            ${selectionMode === 'selected' ? '✅ Using your selected keywords from the table' : (selectedCount === 0 ? '💡 Tip: Select keywords in the table to enable "Use Selected" option' : 'Choose how to select keywords')}
                        </p>
                    </div>

                    <div class="modal-form-group">
                        <label>🌍 Language Filter</label>
                        <select id="roadmap-language-filter" class="modal-select">
                            <option value="loading">⏳ Loading available languages...</option>
                        </select>
                        <p style="font-size: 11px; color: var(--brand-gray-light); margin-top: 6px;">
                            Select a specific language or choose "All Languages" to mix multiple languages in one roadmap
                        </p>
                    </div>

                    <div class="modal-form-group">
                        <label>📅 Publishing Frequency</label>
                        <div style="display: flex; gap: 12px; align-items: center;">
                            <input type="number" id="roadmap-posts-count" min="1" max="50" value="1" class="modal-input" style="width: 80px;">
                            <span style="color: var(--brand-white);">posts per</span>
                            <select id="roadmap-period-type" class="modal-select" style="flex: 1;">
                                <option value="day">Day</option>
                                <option value="week">Week</option>
                            </select>
                        </div>
                        <div id="roadmap-duration-preview" style="margin-top: 10px; padding: 10px; background: rgba(0, 188, 212, 0.1); border-radius: 8px; border-left: 3px solid var(--brand-primary);">
                            <span style="color: var(--brand-primary); font-weight: 600; font-size: 13px;">
                                📊 Roadmap Duration: <span id="duration-text">Calculating...</span>
                            </span>
                        </div>
                    </div>

                    <div class="modal-form-group">
                        <label>🗓️ Start Date</label>
                        <input type="date" id="roadmap-start-date" class="modal-input" value="${todayStr}" min="${todayStr}">
                    </div>

                    <div class="modal-form-group" style="margin-top: 16px;">
                        <label style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
                            <input type="checkbox" id="roadmap-generate-ai-instructions"
                                   ${wisewandSEO.defaultAutoGenerateInstructions ? 'checked' : ''}
                                   ${wisewandSEO.openaiConfigured ? '' : 'disabled'}
                                   style="width: auto;">
                            <span style="font-weight: 600;">🤖 Generate AI Instructions with ChatGPT</span>
                            ${!wisewandSEO.openaiConfigured ? '<span style="color: #f59e0b; font-size: 10px;">⚠️ No API Key</span>' : '<span style="color: #10b981; font-size: 10px;">~$0.0001 per entry</span>'}
                        </label>
                        <p style="font-size: 11px; color: var(--brand-gray-light); margin-top: 6px; margin-left: 24px;">
                            ${wisewandSEO.openaiConfigured ? 'Generates specific Search Intention, Additional Instructions, and Avoid Information for each entry. Adds ~2-3 seconds per keyword to generation time.' : 'Configure OpenAI API key in Settings → OpenAI to enable'}
                        </p>
                    </div>

                    <details style="margin-top: 12px;">
                        <summary style="cursor: pointer; color: var(--brand-primary); font-weight: 600; font-size: 13px; margin-bottom: 12px;">⚙️ Advanced Settings</summary>
                        <div style="padding: 12px; background: rgba(0, 188, 212, 0.05); border-radius: 8px; margin-top: 8px;">
                            <div class="modal-form-group">
                                <label style="display: flex; align-items: center; gap: 8px; cursor: pointer; text-transform: none;">
                                    <input type="checkbox" id="roadmap-detect-cannibalisation" checked style="width: auto;">
                                    <span>🔍 Detect Content Cannibalisation (Recommended)</span>
                                </label>
                                <p style="font-size: 11px; color: var(--brand-gray-light); margin-top: 4px; margin-left: 24px;">
                                    Checks if keywords already have existing content and suggests updates instead of duplicates
                                </p>
                            </div>
                        </div>
                    </details>

                    <div id="roadmap-modal-feedback"></div>
                `;

        showModal(modalTitle, modalBody, '🚀 Generate Roadmap', function () {
            generateEnhancedRoadmap(selectionMode);
        });

        // Load available languages dynamically
        loadAvailableLanguages();

        function loadAvailableLanguages() {
            console.log('Loading available languages...');

            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_get_available_languages',
                    domain: wisewandSEO.domain,
                    language_code: language, // Current language from market selector
                    location_code: parseInt(location),
                    nonce: wisewandSEO.nonce
                },
                success: function (response) {
                    if (response.success && response.data.languages) {
                        const languages = response.data.languages;
                        const $select = $('#roadmap-language-filter');
                        $select.empty();

                        // Add "All Languages" option first
                        $select.append(`<option value="all">🌍 All Languages (${response.data.total_keywords} keywords)</option>`);

                        // Add each detected language with count
                        languages.forEach(lang => {
                            $select.append(`<option value="${lang.code}">${lang.name} (${lang.count} keywords)</option>`);
                        });

                        // Update duration preview when language changes
                        $select.on('change', updateDurationPreview);

                        console.log('Languages loaded:', languages);
                    } else {
                        console.error('Failed to load languages:', response);
                        $('#roadmap-language-filter').html('<option value="all">🌍 All Languages</option>');
                    }
                },
                error: function (xhr, status, error) {
                    console.error('Error loading languages:', error);
                    $('#roadmap-language-filter').html('<option value="all">🌍 All Languages</option>');
                }
            });
        }

        // Real-time duration calculation with language filtering
        function updateDurationPreview() {
            const postsPerPeriod = parseInt($('#roadmap-posts-count').val()) || 1;
            const periodType = $('#roadmap-period-type').val();
            const keywordSource = $('#roadmap-keyword-source').val();
            const selectedLang = $('#roadmap-language-filter').val();

            // Get keyword count based on language filter
            let keywordCount = totalKeywords;

            // If specific language selected, count matching rows
            if (selectedLang && selectedLang !== 'all' && selectedLang !== 'loading') {
                keywordCount = $(`.seo-table tbody tr[data-language="${selectedLang}"]`).length;
            }

            // Apply keyword selection strategy
            if (keywordSource === 'selected') {
                // Count selected keywords (optionally filtered by language)
                if (selectedLang && selectedLang !== 'all' && selectedLang !== 'loading') {
                    // Count only VISIBLE checked boxes to match what user sees
                    keywordCount = $(`.seo-table tbody tr[data-language="${selectedLang}"] .select-keyword-row:visible:checked`).length;
                } else {
                    keywordCount = selectedCount;
                }
            } else if (keywordSource === 'auto') {
                keywordCount = Math.min(keywordCount, 180); // Max 6 months
            }

            let duration = 0;
            if (periodType === 'day') {
                duration = Math.ceil(keywordCount / postsPerPeriod);
            } else if (periodType === 'week') {
                duration = Math.ceil((keywordCount / postsPerPeriod) * 7);
            }

            const durationText = periodType === 'day'
                ? `${duration} days (${keywordCount} keywords ÷ ${postsPerPeriod} per day)`
                : `${duration} days (${keywordCount} keywords ÷ ${postsPerPeriod} per week)`;

            $('#duration-text').text(durationText);
        }

        $('#roadmap-posts-count, #roadmap-period-type, #roadmap-keyword-source, #roadmap-language-filter').on('change input', updateDurationPreview);
        updateDurationPreview();

        function generateEnhancedRoadmap() {
            const postsPerPeriod = parseInt($('#roadmap-posts-count').val()) || 1;
            const periodType = $('#roadmap-period-type').val();
            const startDate = $('#roadmap-start-date').val();
            const keywordSource = $('#roadmap-keyword-source').val();
            const detectCannibalisation = $('#roadmap-detect-cannibalisation').is(':checked');
            const generateAIInstructions = $('#roadmap-generate-ai-instructions').is(':checked');
            const selectedLanguage = $('#roadmap-language-filter').val() || 'all';

            console.log('🌍 Generating roadmap for language:', selectedLanguage);
            console.log('🤖 Generate AI Instructions:', generateAIInstructions);

            // Validate language is loaded
            if (selectedLanguage === 'loading') {
                $('#roadmap-modal-feedback').html('<div class="modal-error">⏳ Please wait for languages to load...</div>');
                return;
            }

            // Get selected keywords if applicable
            let selectedKeywords = [];
            if (keywordSource === 'selected') {
                // CRITICAL FIX: Only collect VISIBLE checked keywords (respects filters)
                selectedKeywords = $('.select-keyword-row:visible:checked').map(function () {
                    return $(this).closest('tr').find('.col-keyword strong').text();
                }).get();

                if (selectedKeywords.length === 0) {
                    $('#roadmap-modal-feedback').html('<div class="modal-error">No keywords selected. Please select keywords from the table first.</div>');
                    return;
                }
            }

            $('#modal-confirm').prop('disabled', true).text('🚀 Generating...');
            $('#roadmap-modal-feedback').html('<div class="modal-info">⏳ Analyzing keywords and generating roadmap...</div>');

            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_generate_smart_roadmap',
                    domain: wisewandSEO.domain,
                    language_code: selectedLanguage, // Use selected language from filter!
                    location_code: parseInt(location),
                    posts_per_period: postsPerPeriod,
                    period_type: periodType,
                    start_date: startDate, // Phase 5: Part C - Send start date
                    keyword_selection: keywordSource,
                    selected_keywords: JSON.stringify(selectedKeywords),
                    detect_cannibalisation: detectCannibalisation,
                    generate_ai_instructions: generateAIInstructions ? 1 : 0, // Send explicit integer (0 or 1)
                    nonce: wisewandSEO.nonce
                },
                success: function (response) {
                    console.log('Roadmap AJAX success callback:', response);
                    console.log('Response type:', typeof response);
                    console.log('Response.success:', response?.success);
                    console.log('Response.data:', response?.data);

                    if (response && response.success) {
                        const data = response.data;

                        // Check if AI instructions should be generated
                        if (data.generate_ai_instructions && data.created_entry_ids && data.created_entry_ids.length > 0) {
                            console.log('🤖 Starting AI Instructions generation for', data.created_entry_ids.length, 'entries');

                            // Show initial success + start AI generation
                            const msg = `
                                        <strong>✅ Roadmap Created! (${data.total_scheduled} entries)</strong><br><br>
                                        <strong>🤖 Now generating AI Instructions...</strong><br>
                                        This will take ~2-3 seconds per entry.
                                    `;
                            $('#roadmap-modal-feedback').html('<div class="modal-info">' + msg + '</div>');
                            $('#modal-confirm').text('⏳ Generating AI Instructions...').prop('disabled', true);

                            // Start client-side batch processing
                            processAIInstructionsBatch(data.created_entry_ids, data);
                        } else {
                            // No AI generation - show standard success
                            const msg = `
                                        <strong>✅ Roadmap Generated Successfully!</strong><br><br>
                                        📊 Total Scheduled: <strong>${data.total_scheduled}</strong> keywords<br>
                                        🆕 New Content: <strong>${data.creates}</strong><br>
                                        🔄 Updates: <strong>${data.updates}</strong><br>
                                        ${data.skipped > 0 ? `⏭️ Skipped: <strong>${data.skipped}</strong><br>` : ''}
                                        <br>
                                        🎯 Cannibalisation Risk:<br>
                                        • None: ${data.by_risk.none}<br>
                                        • Low: ${data.by_risk.low}<br>
                                        • Medium: ${data.by_risk.medium}<br>
                                        • High: ${data.by_risk.high}<br>
                                        <br>
                                        📅 Date Range: ${data.date_start} to ${data.date_end}<br>
                                        ⏱️ Duration: ${data.total_days} days
                                    `;
                            $('#roadmap-modal-feedback').html('<div class="modal-success">' + msg + '</div>');
                            $('#modal-confirm').text('✅ Done').prop('disabled', false);

                            setTimeout(() => {
                                closeModal();
                            }, 3000);
                        }
                    } else {
                        console.error('Roadmap generation failed:', response);
                        const errorDetail = response?.data?.message || 'Unknown error';
                        $('#roadmap-modal-feedback').html(`
                                    <div class="modal-error">
                                        ❌ Failed to generate roadmap<br><br>
                                        <strong>Error:</strong> ${errorDetail}<br><br>
                                        <strong>Debug Info:</strong><br>
                                        • Check browser console (F12) for response details<br>
                                        • Check WordPress Admin → Wisewand → Logs<br>
                                        • Response logged above in console
                                    </div>
                                `);
                        $('#modal-confirm').prop('disabled', false).text('🚀 Retry');
                    }
                },
                error: function (xhr, status, error) {
                    console.error('Roadmap AJAX error:', {
                        status: xhr.status,
                        statusText: xhr.statusText,
                        responseText: xhr.responseText,
                        error: error,
                        fullXHR: xhr
                    });

                    let errorMsg = 'Connection error';
                    try {
                        const parsed = JSON.parse(xhr.responseText);
                        errorMsg = parsed.data?.message || parsed.message || errorMsg;
                    } catch (e) {
                        errorMsg = xhr.responseText || ('HTTP ' + xhr.status);
                    }

                    $('#roadmap-modal-feedback').html(`
                                <div class="modal-error">
                                    ❌ AJAX Error<br><br>
                                    <strong>Status:</strong> ${xhr.status} ${xhr.statusText}<br>
                                    <strong>Error:</strong> ${errorMsg}<br><br>
                                    <strong>Full error logged in console</strong> - Press F12 to view
                                </div>
                            `);
                    $('#modal-confirm').prop('disabled', false).text('🚀 Retry');
                }
            });
        }

        // AI Instructions Batch Processing (client-side to avoid timeout)
        function processAIInstructionsBatch(entryIds, roadmapData) {
            const totalEntries = entryIds.length;
            let currentIndex = 0;
            let successful = 0;
            let failed = 0;
            const startTime = Date.now();

            console.log('🤖 AI Instructions Batch: Starting for', totalEntries, 'entries');

            // OpenAI GPT-4o-mini pricing: $0.150 per 1M input tokens, $0.600 per 1M output tokens
            // Estimated: ~500 input + ~300 output tokens per request = ~$0.00027 per entry
            const estimatedCost = (totalEntries * 0.00027).toFixed(3);
            const estimatedTime = Math.ceil(totalEntries * 2.5); // ~2.5 sec per entry with delays

            // Format seconds to "Xm Ys" or "Xs"
            function formatTime(seconds) {
                if (seconds < 60) {
                    return seconds + 's';
                }
                const minutes = Math.floor(seconds / 60);
                const secs = seconds % 60;
                return minutes + 'm ' + secs + 's';
            }

            function processNext() {
                if (currentIndex >= totalEntries) {
                    showBatchComplete();
                    return;
                }

                const entryId = entryIds[currentIndex];
                const progress = Math.round(((currentIndex + 1) / totalEntries) * 100);
                const elapsed = Math.round((Date.now() - startTime) / 1000);
                const avgTimePerEntry = currentIndex > 0 ? elapsed / currentIndex : 2.5;
                const remaining = Math.ceil((totalEntries - currentIndex) * avgTimePerEntry);

                updateBatchProgress(currentIndex + 1, totalEntries, progress, elapsed, remaining);

                console.log(`🤖 Processing entry ${currentIndex + 1}/${totalEntries} (ID: ${entryId})`);

                $.ajax({
                    url: wisewandSEO.ajaxUrl,
                    type: 'POST',
                    timeout: 30000,
                    data: {
                        action: 'wisewand_generate_instructions_ai',
                        entry_id: entryId,
                        nonce: wisewandSEO.calendarNonce
                    },
                    success: function (response) {
                        if (response.success) {
                            successful++;
                            console.log(`✅ Entry ${entryId}: AI instructions generated`);
                        } else {
                            failed++;
                            console.warn(`⚠️ Entry ${entryId}: Generation failed -`, response.data?.message);
                        }

                        currentIndex++;
                        setTimeout(processNext, 1000); // 1 sec delay between calls (rate limiting)
                    },
                    error: function (xhr, status, error) {
                        failed++;
                        console.error(`❌ Entry ${entryId}: AJAX error -`, error);

                        currentIndex++;
                        setTimeout(processNext, 1000);
                    }
                });
            }

            function updateBatchProgress(current, total, percent, elapsed, remaining) {
                const msg = `
                            <div style="background: rgba(59, 130, 246, 0.1); border: 1px solid rgba(59, 130, 246, 0.3); border-radius: 12px; padding: 20px;">
                                <div style="font-size: 16px; font-weight: 600; color: var(--brand-white); margin-bottom: 16px;">
                                    ✅ Roadmap Created - 🤖 Generating AI Instructions
                                </div>

                                <div style="margin-bottom: 16px;">
                                    <div style="display: flex; justify-content: space-between; margin-bottom: 8px; font-size: 13px; color: var(--brand-white);">
                                        <span>Processing entry ${current} of ${total}</span>
                                        <span style="color: var(--brand-primary); font-weight: 600;">${percent}%</span>
                                    </div>
                                    <div style="background: rgba(160, 168, 184, 0.2); border-radius: 12px; height: 12px; overflow: hidden; border: 1px solid rgba(59, 130, 246, 0.3);">
                                        <div style="background: linear-gradient(90deg, #10b981 0%, #3b82f6 100%); height: 100%; width: ${percent}%; transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 0 12px rgba(59, 130, 246, 0.5);"></div>
                                    </div>
                                </div>

                                <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; font-size: 12px;">
                                    <div style="text-align: center; padding: 8px; background: rgba(16, 185, 129, 0.1); border-radius: 6px;">
                                        <div style="color: var(--brand-success); font-weight: 600;">${successful}</div>
                                        <div style="color: var(--brand-gray-light);">Successful</div>
                                    </div>
                                    <div style="text-align: center; padding: 8px; background: rgba(59, 130, 246, 0.1); border-radius: 6px;">
                                        <div style="color: var(--brand-primary); font-weight: 600;">${formatTime(elapsed)}</div>
                                        <div style="color: var(--brand-gray-light);">Elapsed</div>
                                    </div>
                                    <div style="text-align: center; padding: 8px; background: rgba(251, 191, 36, 0.1); border-radius: 6px;">
                                        <div style="color: var(--brand-warning); font-weight: 600;">~${formatTime(remaining)}</div>
                                        <div style="color: var(--brand-gray-light);">Remaining</div>
                                    </div>
                                </div>

                                <div style="margin-top: 12px; padding: 10px; background: rgba(59, 130, 246, 0.05); border-radius: 6px; font-size: 11px; color: var(--brand-gray-light);">
                                    💡 Estimated cost: ~$${estimatedCost} | GPT-4o-mini
                                </div>
                            </div>
                        `;
                $('#roadmap-modal-feedback').html(msg);
            }

            function showBatchComplete() {
                const elapsed = Math.round((Date.now() - startTime) / 1000);
                const actualCost = (successful * 0.00027).toFixed(4);

                const msg = `
                            <div style="background: rgba(16, 185, 129, 0.1); border: 2px solid #10b981; border-radius: 12px; padding: 20px;">
                                <div style="font-size: 18px; font-weight: 700; color: #10b981; margin-bottom: 16px;">
                                    ✅ Roadmap Complete with AI Instructions!
                                </div>

                                <div style="color: var(--brand-white); line-height: 1.8; font-size: 13px;">
                                    <strong>📊 Roadmap Summary:</strong><br>
                                    • Total Entries: <strong>${roadmapData.total_scheduled}</strong><br>
                                    • Date Range: ${roadmapData.date_start} to ${roadmapData.date_end} (${roadmapData.total_days} days)<br>
                                    <br>
                                    <strong>🤖 AI Instructions:</strong><br>
                                    • Successfully Generated: <strong style="color: #10b981;">${successful}</strong><br>
                                    ${failed > 0 ? `• Failed: <strong style="color: #f59e0b;">${failed}</strong> (entries will have blank instructions)<br>` : ''}
                                    • Processing Time: <strong>${formatTime(elapsed)}</strong><br>
                                    • Actual Cost: ~$${actualCost}<br>
                                    <br>
                                    <strong>✨ All entries now have context-aware AI instructions!</strong><br>
                                    View Editorial Calendar to review and edit entries.
                                </div>
                            </div>
                        `;

                $('#roadmap-modal-feedback').html(msg);
                $('#modal-confirm').text('✅ Done').prop('disabled', false).off('click').on('click', () => {
                    closeModal();
                    location.reload(); // Reload to show updated calendar
                });

                console.log('🤖 AI Instructions Batch Complete:', {
                    total: totalEntries,
                    successful: successful,
                    failed: failed,
                    elapsed: elapsed + 's',
                    cost: '$' + actualCost
                });
            }

            processNext(); // Start processing
        }
    } // End of openRoadmapModal function


    // Remove keyword from calendar
    $(document).on('click', '.btn-remove-from-calendar', function (e) {
        e.stopPropagation();
        const calendarId = $(this).data('calendar-id');
        const keyword = $(this).data('keyword');

        if (!confirm(`Remove "${keyword}" from calendar?\n\nThis will cancel the scheduled article but keep the keyword in your library.`)) {
            return;
        }

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_remove_from_calendar',
                calendar_id: calendarId,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    loadLatestSnapshot(); // Refresh table
                } else {
                    alert('Failed: ' + (response.data?.message || 'Unknown error'));
                }
            }
        });
    });

    // Clear all calendar entries
    $('#clear-all-calendar-btn').on('click', function () {
        // Count all entries in calendar (check via AJAX first)
        const $btn = $(this);

        if (!confirm('🗑️ Clear ALL Calendar Entries?\n\nThis will:\n• Delete all scheduled, generating, and pending articles\n• Keep already published posts\n• Keep keywords in your library\n• Cannot be undone\n\nAre you sure?')) {
            return;
        }
        $btn.prop('disabled', true).text('🗑️ Clearing...');

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_clear_all_calendar',
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    alert(`✅ ${response.data.deleted_count} entries cleared from calendar`);
                    loadLatestSnapshot(); // Refresh table
                } else {
                    alert('Failed: ' + (response.data?.message || 'Unknown error'));
                }
            },
            complete: function () {
                $btn.prop('disabled', false).text('🗑️ Clear Calendar');
            }
        });
    });

    // Manual keywords - Add to calendar
    $('#add-manual-keywords').on('click', function () {
        const keywords = $('#manual-keywords').val().trim();
        if (!keywords) {
            alert('Please enter at least one keyword');
            return;
        }

        const $btn = $(this);
        $btn.prop('disabled', true).text('📅 Adding...');

        $.ajax({
            url: wisewandSEO.ajaxUrl,
            type: 'POST',
            data: {
                action: 'wisewand_add_manual_keywords',
                keywords: keywords,
                nonce: wisewandSEO.nonce
            },
            success: function (response) {
                if (response.success) {
                    alert('✅ Added ' + response.data.success_count + ' keyword(s) to calendar!\n\n' + response.data.message);
                    $('#manual-keywords').val('');
                    $('#manual-results').html(response.data.summary_html || '');
                } else {
                    alert('❌ ' + (response.data?.message || 'Failed'));
                }
            },
            error: function () {
                alert('❌ Connection error');
            },
            complete: function () {
                $btn.prop('disabled', false).text('📅 Add to Calendar');
            }
        });
    });

    // Schedule keyword button click handler
    $(document).on('click', '.btn-schedule', function (e) {
        e.preventDefault();
        const $btn = $(this);
        const keywordData = JSON.parse($btn.attr('data-keyword-data'));

        if (confirm('Schedule "' + keywordData.keyword + '" for publication?\n\nThis will add it to the Editorial Calendar where you can set the publication date and customize the article settings.')) {
            $btn.prop('disabled', true).text('📅 Scheduling...');

            $.ajax({
                url: wisewandSEO.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'wisewand_schedule_keyword',
                    keyword_data: keywordData,
                    nonce: wisewandSEO.nonce
                },
                success: function (response) {
                    if (response.success) {
                        alert('✅ Keyword scheduled successfully!\n\nPublication Date: ' + response.data.publication_date + '\n\nYou can view and edit it in the Editorial Calendar.');
                        $btn.text('✓ Scheduled').css('background', '#6b7280');
                    } else {
                        alert('❌ Failed to schedule keyword:\n' + (response.data?.message || 'Unknown error'));
                        $btn.prop('disabled', false).text('📅 Schedule');
                    }
                },
                error: function (xhr, status, error) {
                    console.error('Schedule error:', xhr.responseText);
                    alert('❌ Schedule failed: ' + error);
                    $btn.prop('disabled', false).text('📅 Schedule');
                }
            });
        }
    });

});
