(function($) {
    'use strict';

    var pollTimer = null;
    var completeRetries = 0;
    var currentJobId = null;
    var currentRowId = null;
    var currentImageGeneration = sitestaffrBlogData.settings && sitestaffrBlogData.settings.image_generation;

    // Tab behavior lives in the shared SiteStaffrTabs component
    // (admin/js/sitestaffr-tabs.js) — the tablist carries data-tab-storage.

    function initGenerateForm() {
        $('#sitestaffr-blog-generate').on('click', function() {
            var topic = $('#sitestaffr-blog-topic').val().trim();
            var keyword = $('#sitestaffr-blog-keyword').val().trim();
            var imageGeneration = $('#sitestaffr-blog-run-image-gen').is(':checked');

            if ($(this).prop('disabled')) {
                return;
            }

            if (!topic) {
                notify(sitestaffrBlogData.i18n.topicRequired);
                $('#sitestaffr-blog-topic').focus();
                return;
            }

            currentImageGeneration = imageGeneration;

            var $btn = $(this);
            var $status = $('#sitestaffr-blog-generate-status');
            var $progress = $('#sitestaffr-blog-progress');

            $btn.prop('disabled', true);
            $status.text(sitestaffrBlogData.i18n.submitting).css('color', '#666');

            $.post(ajaxurl, {
                action: 'sitestaffr_blog_generate_post',
                nonce: sitestaffrBlogData.nonces.blog,
                topic: topic,
                keyword: keyword,
                tone: $('#sitestaffr-blog-run-tone').val(),
                word_count_target: $('#sitestaffr-blog-run-wc-target').val(),
                language: $('#sitestaffr-blog-run-language').val(),
                image_generation: imageGeneration ? 1 : 0
            }, function(response) {
                if (response.success) {
                    currentJobId = response.data.job_id;
                    currentRowId = response.data.row_id;

                    $status.text('');
                    $('#sitestaffr-blog-form-content').fadeOut(200, function() {
                        $('#sitestaffr-blog-progress').show();
                        updateProgress(0, sitestaffrBlogData.i18n.starting);
                    });

                    setTabGenerating(true);
                    refreshDrafts();
                    startPolling();
                } else {
                    $btn.prop('disabled', false);
                    $status.text(response.data?.message || sitestaffrBlogData.i18n.generateFailed).css('color', '#991b1b');
                }
            }).fail(function() {
                $btn.prop('disabled', false);
                $status.text(sitestaffrBlogData.i18n.generateFailed).css('color', '#991b1b');
            });
        });
    }

    function initSuggestTopic() {
        $('#sitestaffr-blog-suggest-topic').on('click', function() {
            var $btn = $(this);
            var $status = $('#sitestaffr-blog-suggest-status');
            if ($btn.prop('disabled')) {
                return;
            }

            $btn.prop('disabled', true);
            $status.text(sitestaffrBlogData.i18n.suggesting).css('color', '#666');

            $.post(ajaxurl, {
                action: 'sitestaffr_blog_suggest_topic',
                nonce: sitestaffrBlogData.nonces.blog,
                current_topic: $('#sitestaffr-blog-topic').val().trim(),
                current_keyword: $('#sitestaffr-blog-keyword').val().trim()
            }, function(response) {
                $btn.prop('disabled', false);
                if (response.success) {
                    $('#sitestaffr-blog-topic').val(response.data.topic);
                    $('#sitestaffr-blog-keyword').val(response.data.keyword);
                    $status.text(response.data.rationale || '').css('color', '#666');
                } else {
                    $status.text(response.data?.message || sitestaffrBlogData.i18n.suggestFailed).css('color', '#991b1b');
                }
            }).fail(function() {
                $btn.prop('disabled', false);
                $status.text(sitestaffrBlogData.i18n.suggestFailed).css('color', '#991b1b');
            });
        });
    }

    function startPolling() {
        stopPolling();
        completeRetries = 0;
        pollTimer = setInterval(function() {
            checkStatus();
        }, 7000);
    }

    // Small spinning icon on the New Post tab while a generation is running,
    // so the state is visible from the other tabs.
    function setTabGenerating(on) {
        $('#blog-tab-btn-new-post .sitestaffr-blog-tab-generating').remove();
        if (on) {
            $('#blog-tab-btn-new-post').append('<span class="sitestaffr-blog-tab-generating dashicons dashicons-update" aria-hidden="true"></span>');
        }
    }

    function stopPolling() {
        if (pollTimer) {
            clearInterval(pollTimer);
            pollTimer = null;
        }
        setProgressNotice('');
    }

    function checkStatus() {
        if (!currentJobId || !currentRowId) {
            stopPolling();
            return;
        }

        $.post(ajaxurl, {
            action: 'sitestaffr_blog_check_status',
            nonce: sitestaffrBlogData.nonces.blog,
            job_id: currentJobId,
            row_id: currentRowId
        }, function(response) {
            if (response.success) {
                var data = response.data;

                if (data.status === 'complete') {
                    // On hosts whose bot protection blocks the middleware's push,
                    // the draft arrives via the pull-fallback a few seconds after
                    // "complete" — keep polling briefly instead of giving up, so
                    // the preview lightbox still opens.
                    if (!data.edit_url && completeRetries < 8) {
                        completeRetries++;
                        updateProgress(100, sitestaffrBlogData.i18n.finalizing || sitestaffrBlogData.i18n.complete);
                        return;
                    }

                    stopPolling();
                    setTabGenerating(false);
                    updateProgress(100, sitestaffrBlogData.i18n.complete);

                    refreshDrafts();

                    // The draft + image are created by the signed webhook (or the
                    // pull-fallback pickup), and the poll carries the stored body
                    // HTML + media-library image URL to rebuild the preview lightbox.
                    setTimeout(function() {
                        if (data.edit_url) {
                            showCompletionMessage(data.title, data.edit_url, data.word_count, data.image_generation_failed);
                            openPreviewLightbox(data.title, data.preview_html, data.word_count, data.edit_url, data.image_generation_failed, data.featured_image, data.wp_post_id);
                        } else {
                            resetForm();
                        }
                    }, 1000);
                } else if (data.status === 'generating') {
                    updateProgress(data.progress || 0, data.step || sitestaffrBlogData.i18n.generating);
                    // Delivery-retry reassurance: the push was refused (usually host
                    // bot protection) and the post is being pulled in instead. Tell
                    // the user it is recoverable rather than leaving a silent spinner.
                    setProgressNotice(data.notice);
                }
            } else {
                if (response.data?.status === 'failed') {
                    stopPolling();
                    setTabGenerating(false);
                    updateProgress(0, '');
                    $('#sitestaffr-blog-progress').hide();
                    $('#sitestaffr-blog-form-content').show();
                    $('#sitestaffr-blog-generate').prop('disabled', false);
                    $('#sitestaffr-blog-generate-status')
                        .text(response.data?.message || sitestaffrBlogData.i18n.generateFailed)
                        .css('color', '#991b1b');
                }
            }
        }).fail(function() {
            stopPolling();
            setTabGenerating(false);
            resetForm();
            $('#sitestaffr-blog-generate-status')
                .text(sitestaffrBlogData.i18n.generateFailed)
                .css('color', '#991b1b');
        });
    }

    function getIconMap() {
        var imageGen = currentImageGeneration;

        if (imageGen) {
            // Image generation reports progress 90 — the art icon must cover
            // through 99 so the checkmark only appears at actual completion.
            return [
                { max: 19, icon: 'dashicons-welcome-learn-more' },
                { max: 54, icon: 'dashicons-edit-large' },
                { max: 69, icon: 'dashicons-tag' },
                { max: 99, icon: 'dashicons-art' },
                { max: 100, icon: 'dashicons-yes-alt' }
            ];
        }
        return [
            { max: 19, icon: 'dashicons-welcome-learn-more' },
            { max: 59, icon: 'dashicons-edit-large' },
            { max: 99, icon: 'dashicons-tag' },
            { max: 100, icon: 'dashicons-yes-alt' }
        ];
    }
    var CIRCLE_CIRCUMFERENCE = 2 * Math.PI * 60; // r=60 → 376.99

    // Show (or clear) the secondary line under the progress step. Text only —
    // the message originates server-side and is never trusted as markup.
    function setProgressNotice(message) {
        var $notice = $('.sitestaffr-blog-progress-notice');
        if (message) {
            $notice.text(message).show();
        } else {
            $notice.text('').hide();
        }
    }

    function updateProgress(percent, step) {
        var offset = CIRCLE_CIRCUMFERENCE - (percent / 100) * CIRCLE_CIRCUMFERENCE;
        $('.sitestaffr-blog-progress-arc').css('stroke-dashoffset', offset);
        $('.sitestaffr-blog-progress-step').text(step);

        var $icon = $('.sitestaffr-blog-progress-icon');
        var iconMap = getIconMap();
        for (var i = 0; i < iconMap.length; i++) {
            if (percent <= iconMap[i].max) {
                $icon.attr('class', 'sitestaffr-blog-progress-icon dashicons ' + iconMap[i].icon);
                break;
            }
        }

        var $progress = $('#sitestaffr-blog-progress');
        if (percent >= 100) {
            $progress.addClass('is-complete');
        } else {
            $progress.removeClass('is-complete');
        }
    }

    function showCompletionMessage(title, editUrl, wordCount, imageGenFailed) {
        var msg = sitestaffrBlogData.i18n.postReady
            .replace('{title}', title)
            .replace('{words}', wordCount || '');
        var $status = $('#sitestaffr-blog-generate-status');
        var html = '<span style="color:#10b981;">' + $('<span>').text(msg).html() + '</span> ' +
            '<a href="' + editUrl + '" class="button button-small">' +
            sitestaffrBlogData.i18n.editDraft + '</a>';
        if (imageGenFailed) {
            html = '<p style="margin:0 0 8px;color:#92400e;font-size:13px;">' + sitestaffrBlogData.i18n.imageGenFailed + '</p>' + html;
        }
        $status.html(html);
    }

    // Component-styled replacement for the native notify().
    function notify(message) {
        if (window.SiteStaffrModal) {
            window.SiteStaffrModal.alertDialog({ message: message });
        }
    }

    // Preview lightbox — chrome (Esc, focus trap, focus-return) comes from the
    // shared component; the large-content layout and backdrop stay page-owned.
    var lightboxController = null;

    function getLightboxController() {
        if (!lightboxController && window.SiteStaffrModal) {
            var el = document.getElementById('sitestaffr-blog-preview-lightbox');
            if (el) {
                lightboxController = window.SiteStaffrModal.enhance(el, {
                    card: '.sitestaffr-blog-lightbox-dialog',
                    closeOnBackdrop: false,
                    onClose: resetForm
                });
            }
        }
        return lightboxController;
    }

    function openPreviewLightbox(title, bodyHtml, wordCount, editUrl, imageGenFailed, featuredImage, wpPostId) {
        $('#sitestaffr-blog-preview-title').text(title);
        $('#sitestaffr-blog-preview-wc').text(wordCount ? wordCount.toLocaleString() + ' words' : '');
        var $body = $('#sitestaffr-blog-preview-body').html(bodyHtml || '');
        // Prepend the featured image via jQuery (attr-encoded) so it scrolls with
        // the post body and stays XSS-safe even though the URL is server-supplied.
        if (featuredImage) {
            $('<img>', { 'class': 'sitestaffr-blog-lightbox-image', src: featuredImage, alt: '' }).prependTo($body);
        }
        $('#sitestaffr-blog-preview-edit').attr('href', editUrl);
        $('#sitestaffr-blog-preview-publish')
            .data('wp-post-id', wpPostId || '')
            .prop('disabled', !wpPostId)
            .text(sitestaffrBlogData.i18n.publish);
        var $imgNotice = $('#sitestaffr-blog-preview-img-notice');
        if (imageGenFailed) {
            $imgNotice.text(sitestaffrBlogData.i18n.imageGenFailed).show();
        } else {
            $imgNotice.text('').hide();
        }
        var controller = getLightboxController();
        if (controller) {
            controller.open();
        }
    }

    function closePreviewLightbox() {
        var controller = getLightboxController();
        if (controller) {
            controller.close();
        }
    }

    function resetForm() {
        $('#sitestaffr-blog-topic').val('');
        $('#sitestaffr-blog-keyword').val('');
        $('#sitestaffr-blog-generate').prop('disabled', false);
        $('#sitestaffr-blog-progress').hide().removeClass('is-complete');
        $('#sitestaffr-blog-form-content').show();
        updateProgress(0, '');
        currentJobId = null;
        currentRowId = null;
    }

    function initPreviewActions() {
        $('#sitestaffr-blog-preview-publish').on('click', function() {
            var $btn = $(this);
            var wpPostId = $btn.data('wp-post-id');

            if (!wpPostId || $btn.prop('disabled')) {
                return;
            }

            $btn.prop('disabled', true).text(sitestaffrBlogData.i18n.publishing);

            $.post(ajaxurl, {
                action: 'sitestaffr_blog_publish_post',
                nonce: sitestaffrBlogData.nonces.blog,
                wp_post_id: wpPostId
            }, function(response) {
                if (response.success) {
                    $btn.text(sitestaffrBlogData.i18n.published);
                    refreshDrafts();
                    if (response.data && response.data.view_url) {
                        window.location.href = response.data.view_url;
                    }
                } else {
                    $btn.prop('disabled', false).text(sitestaffrBlogData.i18n.publish);
                    notify(response.data?.message || sitestaffrBlogData.i18n.publishFailed);
                }
            }).fail(function() {
                $btn.prop('disabled', false).text(sitestaffrBlogData.i18n.publish);
                notify(sitestaffrBlogData.i18n.publishFailed);
            });
        });
    }

    function refreshDrafts() {
        $.post(ajaxurl, {
            action: 'sitestaffr_blog_get_drafts',
            nonce: sitestaffrBlogData.nonces.blog
        }, function(response) {
            if (!response.success) return;

            var drafts = response.data.drafts || [];
            var $list = $('#sitestaffr-blog-drafts-list');

            var activeCount = drafts.filter(function(d) {
                return d.status === 'complete' || d.status === 'generating';
            }).length;

            var $badge = $('#blog-tab-btn-drafts .sitestaffr-blog-tab-count');
            if (activeCount > 0) {
                if ($badge.length) {
                    $badge.text(activeCount);
                } else {
                    $('#blog-tab-btn-drafts').append(' <span class="sitestaffr-blog-tab-count">' + activeCount + '</span>');
                }
            } else {
                $badge.remove();
            }

            if (drafts.length === 0) {
                $list.html('<p class="sitestaffr-blog-empty">' + emptyDraftsMessage() + '</p>');
                return;
            }

            var html = '<h3>' + sitestaffrBlogData.i18n.generatedPosts + '</h3>' +
                '<table class="widefat sitestaffr-blog-drafts-table"><thead><tr>' +
                '<th>' + sitestaffrBlogData.i18n.status + '</th>' +
                '<th>' + sitestaffrBlogData.i18n.topic + '</th>' +
                '<th>' + sitestaffrBlogData.i18n.keyword + '</th>' +
                '<th>' + sitestaffrBlogData.i18n.created + '</th>' +
                '<th>' + sitestaffrBlogData.i18n.actions + '</th>' +
                '</tr></thead><tbody>';

            drafts.forEach(function(draft) {
                var statusHtml;
                if (draft.status === 'generating') {
                    statusHtml = '<span class="sitestaffr-blog-status is-generating"><span class="spinner is-active" style="float:none;margin:0 4px 0 0;"></span>' + sitestaffrBlogData.i18n.generating + '</span>';
                } else if (draft.status === 'complete' && draft.post_status === 'publish') {
                    statusHtml = '<span class="sitestaffr-blog-status is-published">' + sitestaffrBlogData.i18n.publishedStatus + '</span>';
                } else if (draft.status === 'complete' && draft.post_status === 'draft') {
                    statusHtml = '<span class="sitestaffr-blog-status is-complete">' + sitestaffrBlogData.i18n.readyForReview + '</span>';
                } else if (draft.status === 'complete') {
                    statusHtml = '<span class="sitestaffr-blog-status is-complete">' + sitestaffrBlogData.i18n.ready + '</span>';
                } else if (draft.status === 'failed') {
                    // .text().html() escapes < > & but NOT quotes, so it is unsafe inside an
                    // attribute — an AI-written topic or a middleware error containing a double
                    // quote would break out of it. Build the node instead; serialization escapes.
                    statusHtml = $('<span>', {
                        'class': 'sitestaffr-blog-status is-failed',
                        title: draft.fail_reason || sitestaffrBlogData.i18n.failReasonDefault,
                        text: sitestaffrBlogData.i18n.failed
                    }).prop('outerHTML');
                } else {
                    statusHtml = '<span class="sitestaffr-blog-status">' + $('<span>').text(draft.status).html() + '</span>';
                }

                var actionsHtml = '';
                if (draft.status === 'complete' && draft.post_status === 'publish' && draft.view_url) {
                    actionsHtml += '<a href="' + draft.view_url + '" target="_blank" rel="noopener" class="button button-small">' + sitestaffrBlogData.i18n.viewLive + '</a> ';
                }
                if (draft.status === 'complete' && draft.post_status === 'draft' && draft.wp_post_id) {
                    actionsHtml += '<button type="button" class="button button-small button-primary sitestaffr-blog-row-publish" data-post-id="' + draft.wp_post_id + '">' + sitestaffrBlogData.i18n.publish + '</button> ';
                    actionsHtml += '<button type="button" class="button button-small sitestaffr-blog-email-review" data-sitestaffr-email="review_link" data-id="' + draft.wp_post_id + '">' + sitestaffrBlogData.i18n.emailReviewLink + '</button> ';
                }
                if (draft.edit_url) {
                    actionsHtml += '<a href="' + draft.edit_url + '" class="button button-small">' + sitestaffrBlogData.i18n.editDraft + '</a> ';
                }
                if (draft.status === 'failed') {
                    actionsHtml += $('<button>', {
                        type: 'button',
                        'class': 'button button-small sitestaffr-blog-retry',
                        'data-topic': draft.topic,
                        'data-keyword': draft.keyword || '',
                        text: sitestaffrBlogData.i18n.retry
                    }).prop('outerHTML') + ' ';
                }
                actionsHtml += '<button type="button" class="button button-small button-link-delete sitestaffr-blog-delete" data-id="' + draft.id + '">' + sitestaffrBlogData.i18n.deleteDraft + '</button>';

                html += '<tr data-job-id="' + draft.id + '">' +
                    '<td data-colname="' + sitestaffrBlogData.i18n.status + '">' + statusHtml + '</td>' +
                    '<td data-colname="' + sitestaffrBlogData.i18n.topic + '">' + $('<span>').text(draft.topic).html() + '</td>' +
                    '<td data-colname="' + sitestaffrBlogData.i18n.keyword + '">' + $('<span>').text(draft.keyword).html() + '</td>' +
                    '<td data-colname="' + sitestaffrBlogData.i18n.created + '">' + $('<span>').text(draft.created_at).html() + '</td>' +
                    '<td class="sitestaffr-blog-draft-actions">' + actionsHtml + '</td>' +
                    '</tr>';
            });

            html += '</tbody></table>';
            $list.html(html);
        });
    }

    function updateDraftsBadge() {
        var count = $('.sitestaffr-blog-drafts-table tbody tr').length;
        var $badge = $('#blog-tab-btn-drafts .sitestaffr-blog-tab-count');
        if (count > 0) {
            if ($badge.length) {
                $badge.text(count);
            } else {
                $('#blog-tab-btn-drafts').append(' <span class="sitestaffr-blog-tab-count">' + count + '</span>');
            }
        } else {
            $badge.remove();
            $('#sitestaffr-blog-drafts-list').html(
                '<p class="sitestaffr-blog-empty">' + emptyDraftsMessage() + '</p>'
            );
        }
    }

    // With Autopilot on, "use the New Post tab" is the wrong nudge — posts are
    // already on the way; say that instead.
    function emptyDraftsMessage() {
        return sitestaffrBlogData.settings.autopilot_enabled
            ? sitestaffrBlogData.i18n.noDraftsAutopilot
            : sitestaffrBlogData.i18n.noDrafts;
    }

    function initDraftsActions() {
        // Retry a failed generation: prefill the New Post form with the same
        // topic/keyword and hand off to the normal generate flow.
        $(document).on('click', '.sitestaffr-blog-retry', function() {
            $('#sitestaffr-blog-topic').val(String($(this).data('topic') || ''));
            $('#sitestaffr-blog-keyword').val(String($(this).data('keyword') || ''));
            $('#blog-tab-btn-new-post').trigger('click');
            var target = document.getElementById('sitestaffr-blog-topic');
            if (target && target.scrollIntoView) {
                target.scrollIntoView({ behavior: 'smooth', block: 'center' });
            }
            $('#sitestaffr-blog-generate').focus();
        });

        // Pipeline empty-state CTA: jump to the New Post tab.
        $(document).on('click', '.sitestaffr-blog-goto-new-post', function() {
            $('#blog-tab-btn-new-post').trigger('click');
        });

        $(document).on('click', '.sitestaffr-blog-delete', function() {
            var $btn = $(this);
            window.SiteStaffrModal.confirm({
                message: sitestaffrBlogData.i18n.confirmDelete,
                danger: true
            }).then(function(ok) {
            if (!ok) return;

            var id = $btn.data('id');
            var $row = $btn.closest('tr');

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

            $.post(ajaxurl, {
                action: 'sitestaffr_blog_delete_post',
                nonce: sitestaffrBlogData.nonces.blog,
                id: id
            }, function(response) {
                if (response.success) {
                    $row.fadeOut(300, function() {
                        $(this).remove();
                        updateDraftsBadge();
                    });
                } else {
                    $btn.prop('disabled', false);
                    notify(response.data?.message || sitestaffrBlogData.i18n.deleteFailed);
                }
            }).fail(function() {
                $btn.prop('disabled', false);
                notify(sitestaffrBlogData.i18n.deleteFailed);
            });
            });
        });

        // Publish a Ready draft straight from the list (same handler as the
        // preview lightbox's Publish button).
        $(document).on('click', '.sitestaffr-blog-row-publish', function() {
            var $btn = $(this);
            var postId = $btn.data('post-id');

            $btn.prop('disabled', true).text(sitestaffrBlogData.i18n.publishing);

            $.post(ajaxurl, {
                action: 'sitestaffr_blog_publish_post',
                nonce: sitestaffrBlogData.nonces.blog,
                wp_post_id: postId
            }, function(response) {
                if (response.success) {
                    refreshDrafts();
                } else {
                    $btn.prop('disabled', false).text(sitestaffrBlogData.i18n.publish);
                    notify(response.data?.message || sitestaffrBlogData.i18n.publishFailed);
                }
            }).fail(function() {
                $btn.prop('disabled', false).text(sitestaffrBlogData.i18n.publish);
                notify(sitestaffrBlogData.i18n.publishFailed);
            });
        });
    }

    function initSettingsSave() {
        $('#sitestaffr-blog-save-settings').on('click', function() {
            var $btn = $(this);
            var $status = $('#sitestaffr-blog-settings-status');

            $btn.prop('disabled', true);
            $status.text(sitestaffrBlogData.i18n.saving).css('color', '#666');

            var scheduleDays = [];
            $('input[name="schedule_days[]"]:checked').each(function() {
                scheduleDays.push($(this).val());
            });

            $.post(ajaxurl, {
                action: 'sitestaffr_blog_save_settings',
                nonce: sitestaffrBlogData.nonces.blog,
                tone: $('#sitestaffr-blog-tone').val(),
                word_count_target: $('#sitestaffr-blog-wc-target').val(),
                language: $('#sitestaffr-blog-language').val(),
                autopilot_enabled: $('#sitestaffr-blog-autopilot').is(':checked') ? 1 : 0,
                autopilot_delivery: $('input[name="autopilot_delivery"]:checked').val() || 'publish',
                image_generation: $('#sitestaffr-blog-image-gen').is(':checked') ? 1 : 0,
                'schedule_days[]': scheduleDays,
                schedule_time: $('#sitestaffr-blog-schedule-time').val()
            }, function(response) {
                $btn.prop('disabled', false);
                if (response.success) {
                    sitestaffrBlogData.settings.image_generation = $('#sitestaffr-blog-image-gen').is(':checked');
                    $status.text(sitestaffrBlogData.i18n.saved).css('color', '#10b981');
                    setTimeout(function() { $status.text(''); }, 2000);
                } else {
                    $status.text(response.data?.message || sitestaffrBlogData.i18n.saveFailed).css('color', '#991b1b');
                }
            }).fail(function() {
                $btn.prop('disabled', false);
                $status.text(sitestaffrBlogData.i18n.saveFailed).css('color', '#991b1b');
            });
        });
    }

    function refreshUpcomingTopics(done) {
        var finish = function() { if (typeof done === 'function') { done(); } };
        $.post(ajaxurl, {
            action: 'sitestaffr_blog_get_topics',
            nonce: sitestaffrBlogData.nonces.blog
        }, function(response) {
            if (!response.success || !response.data.topics || !response.data.topics.length) {
                $('#sitestaffr-blog-upcoming').remove();
                finish();
                return;
            }

            // The publish-slot column only means something when autopilot
            // schedules the queue; without it topics are generated on demand.
            var showSlots = !!(sitestaffrBlogData.settings && sitestaffrBlogData.settings.autopilot_enabled);

            var $tipTrigger = $('<span class="sitestaffr-tooltip-trigger" tabindex="0" role="button"></span>')
                .attr('aria-label', 'Help')
                .attr('data-tooltip', sitestaffrBlogData.i18n.upcomingTooltip)
                .append('<span class="dashicons dashicons-info" aria-hidden="true"></span>');

            var topics = response.data.topics;
            var html = '<div id="sitestaffr-blog-upcoming"><h3>' + sitestaffrBlogData.i18n.upcoming + ' ' + $('<div>').append($tipTrigger).html() + '</h3>';
            html += '<table class="widefat sitestaffr-blog-upcoming-table"><thead><tr>';
            html += '<th class="col-topic">' + sitestaffrBlogData.i18n.topic + '</th>';
            html += '<th class="col-keyword">' + sitestaffrBlogData.i18n.keyword + '</th>';
            if (showSlots) {
                html += '<th class="col-slot">' + sitestaffrBlogData.i18n.publishes + '</th>';
            }
            html += '<th class="col-actions">' + sitestaffrBlogData.i18n.actions + '</th>';
            html += '</tr></thead><tbody>';

            topics.forEach(function(topic) {
                var actions = '<button type="button" class="button button-small sitestaffr-blog-generate-topic" data-id="' + topic.id + '">' + sitestaffrBlogData.i18n.generateNow + '</button> ';
                actions += '<button type="button" class="button button-small sitestaffr-blog-edit-topic" data-id="' + topic.id + '">' + sitestaffrBlogData.i18n.edit + '</button> ';
                actions += '<button type="button" class="button button-small sitestaffr-blog-skip-topic" data-id="' + topic.id + '">' + sitestaffrBlogData.i18n.skip + '<span class="dashicons dashicons-controls-skipforward" aria-hidden="true"></span></button>';

                html += '<tr data-topic-id="' + topic.id + '">';
                html += '<td class="col-topic" data-colname="' + sitestaffrBlogData.i18n.topic + '">' + $('<span>').text(topic.topic).html() + '</td>';
                html += '<td class="col-keyword" data-colname="' + sitestaffrBlogData.i18n.keyword + '">' + $('<span>').text(topic.keyword).html() + '</td>';
                if (showSlots) {
                    html += '<td class="col-slot" data-colname="' + sitestaffrBlogData.i18n.publishes + '">' + (topic.scheduled_for ? $('<span>').text(topic.scheduled_for).html() : '&mdash;') + '</td>';
                }
                html += '<td class="col-actions">' + actions + '</td>';
                html += '</tr>';
            });

            html += '</tbody></table></div>';

            var $existing = $('#sitestaffr-blog-upcoming');
            if ($existing.length) {
                $existing.replaceWith(html);
            } else {
                $('#sitestaffr-blog-drafts-list').before(html);
            }
            finish();
        }).fail(finish);
    }

    function initTopicActions() {
        // Skips mutate the saved topic queue (mark skipped + add one replacement).
        // Firing several at once races on that read-modify-write and topics get
        // lost, so we serialize: only one skip runs at a time.
        var skipInProgress = false;

        $(document).on('click', '.sitestaffr-blog-generate-topic', function() {
            var $btn = $(this);
            window.SiteStaffrModal.confirm({
                message: sitestaffrBlogData.i18n.confirmGenerateTopic
            }).then(function(ok) {
            if (!ok) return;

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

            $.post(ajaxurl, {
                action: 'sitestaffr_blog_generate_post',
                nonce: sitestaffrBlogData.nonces.blog,
                topic_id: $btn.data('id')
            }, function(response) {
                if (response.success) {
                    currentJobId = response.data.job_id;
                    currentRowId = response.data.row_id;
                    currentImageGeneration = !!response.data.image_generation;

                    // Reuse the manual-generation progress experience.
                    $('#blog-tab-btn-new-post').trigger('click');
                    $('#sitestaffr-blog-form-content').hide();
                    $('#sitestaffr-blog-progress').show();
                    updateProgress(0, sitestaffrBlogData.i18n.starting);

                    setTabGenerating(true);
                    refreshDrafts();
                    refreshUpcomingTopics();
                    startPolling();
                } else {
                    $btn.prop('disabled', false);
                    notify(response.data && response.data.message ? response.data.message : sitestaffrBlogData.i18n.generateFailed);
                }
            }).fail(function() {
                $btn.prop('disabled', false);
                notify(sitestaffrBlogData.i18n.generateFailed);
            });
            });
        });

        $(document).on('click', '.sitestaffr-blog-skip-topic', function() {
            if (skipInProgress) return; // one skip at a time — see note above.
            var $btn = $(this);
            window.SiteStaffrModal.confirm({
                message: sitestaffrBlogData.i18n.confirmSkipTopic
            }).then(function(ok) {
            if (!ok || skipInProgress) return;

            skipInProgress = true;
            var topicId = $btn.data('id');
            // Disable EVERY skip button while one is in flight so rapid clicks can't
            // fire concurrent requests that clobber each other's queue writes.
            $('.sitestaffr-blog-skip-topic').prop('disabled', true);

            // Show a spinner on the clicked button: the server generates a fresh
            // replacement topic (an AI call), so give the owner clear feedback that
            // work is happening rather than a silently grayed-out button.
            var originalBtnHtml = $btn.html();
            $btn.addClass('is-skipping').html(
                '<span class="sitestaffr-blog-skip-spinner dashicons dashicons-update" aria-hidden="true"></span>' + sitestaffrBlogData.i18n.skipping
            );

            var releaseAndEnable = function() {
                skipInProgress = false;
                $('.sitestaffr-blog-skip-topic').prop('disabled', false);
                $btn.removeClass('is-skipping').html(originalBtnHtml);
            };

            $.post(ajaxurl, {
                action: 'sitestaffr_blog_skip_topic',
                nonce: sitestaffrBlogData.nonces.blog,
                topic_id: topicId
            }, function(response) {
                if (response.success) {
                    $btn.closest('tr').fadeOut(300, function() {
                        $(this).remove();
                        // Reload the queue: the replacement topic fetched by the
                        // server appears immediately with refreshed publish slots.
                        // Release the lock only once the queue has re-rendered.
                        refreshUpcomingTopics(releaseAndEnable);
                    });
                } else {
                    releaseAndEnable();
                    notify(response.data && response.data.message ? response.data.message : 'Failed to skip topic.');
                }
            }).fail(function() {
                releaseAndEnable();
                notify('Failed to skip topic.');
            });
            });
        });

        // Inline edit: swap the topic/keyword cells for inputs so owners can fix
        // wording without skipping (which would spend a topic credit).
        $(document).on('click', '.sitestaffr-blog-edit-topic', function() {
            var $row = $(this).closest('tr');
            if ($row.hasClass('is-editing')) return;
            $row.addClass('is-editing');

            var topicId      = $(this).data('id');
            var $topicCell   = $row.find('td.col-topic');
            var $keywordCell = $row.find('td.col-keyword');
            var $actionsCell = $row.find('td.col-actions');

            // Stash originals so Cancel can restore the row untouched.
            $row.data('origTopic', $topicCell.text());
            $row.data('origKeyword', $keywordCell.text());
            $row.data('origActions', $actionsCell.html());

            $topicCell.empty().append(
                $('<input type="text" class="sitestaffr-blog-edit-topic-input regular-text">')
                    .attr('aria-label', sitestaffrBlogData.i18n.editTopicTitle)
                    .css('width', '100%')
                    .val($row.data('origTopic'))
            );
            $keywordCell.empty().append(
                $('<input type="text" class="sitestaffr-blog-edit-keyword-input regular-text">')
                    .attr('aria-label', sitestaffrBlogData.i18n.editTopicKeyword)
                    .css('width', '100%')
                    .val($row.data('origKeyword'))
            );
            $actionsCell.html(
                '<button type="button" class="button button-small button-primary sitestaffr-blog-save-topic" data-id="' + topicId + '">' + sitestaffrBlogData.i18n.save + '</button> ' +
                '<button type="button" class="button button-small sitestaffr-blog-cancel-topic">' + sitestaffrBlogData.i18n.cancel + '</button>'
            );
            $topicCell.find('input').trigger('focus');
        });

        $(document).on('click', '.sitestaffr-blog-cancel-topic', function() {
            restoreTopicRow($(this).closest('tr'));
        });

        $(document).on('click', '.sitestaffr-blog-save-topic', function() {
            var $btn       = $(this);
            var $row       = $btn.closest('tr');
            var newTopic   = $.trim($row.find('.sitestaffr-blog-edit-topic-input').val());
            var newKeyword = $.trim($row.find('.sitestaffr-blog-edit-keyword-input').val());

            if (!newTopic || !newKeyword) {
                notify(sitestaffrBlogData.i18n.editRequired);
                return;
            }

            $btn.prop('disabled', true);
            $.post(ajaxurl, {
                action: 'sitestaffr_blog_update_topic',
                nonce: sitestaffrBlogData.nonces.blog,
                topic_id: $btn.data('id'),
                topic: newTopic,
                keyword: newKeyword
            }, function(response) {
                if (response.success) {
                    restoreTopicRow($row, response.data.topic, response.data.keyword);
                } else {
                    $btn.prop('disabled', false);
                    notify(response.data && response.data.message ? response.data.message : sitestaffrBlogData.i18n.updateFailed);
                }
            }).fail(function() {
                $btn.prop('disabled', false);
                notify(sitestaffrBlogData.i18n.updateFailed);
            });
        });
    }

    // Restore a row out of edit mode. With no overrides it reverts to the
    // stashed originals (Cancel); with them it shows the saved values.
    function restoreTopicRow($row, topic, keyword) {
        $row.find('td.col-topic').text(typeof topic !== 'undefined' ? topic : $row.data('origTopic'));
        $row.find('td.col-keyword').text(typeof keyword !== 'undefined' ? keyword : $row.data('origKeyword'));
        $row.find('td.col-actions').html($row.data('origActions'));
        $row.removeClass('is-editing');
    }

    $(document).ready(function() {
        initGenerateForm();
        initSuggestTopic();
        initDraftsActions();
        initSettingsSave();
        initPreviewActions();

        // Autopilot toggle.
        $('#sitestaffr-blog-autopilot').on('change', function() {
            $('#sitestaffr-blog-autopilot-options').toggle(this.checked);
        });

        initTopicActions();
        refreshUpcomingTopics();

        $('.sitestaffr-blog-lightbox-backdrop, .sitestaffr-blog-lightbox-close').on('click', function() {
            closePreviewLightbox();
        });
    });
})(jQuery);
