/**
 * Contentosapp Studio Admin — Detail page behaviors.
 * Extracted from costudio-admin.js to allow page-specific loading.
 */
/* global CostudioData, marked, DOMPurify */
(function ($) {
    'use strict';

    var data = window.CostudioData || {};
    var ajax = data.ajax_url || '';
    var i18n = data.i18n || {};

    function t(key, fallback) {
        return (typeof i18n[key] === 'string' && i18n[key].length) ? i18n[key] : fallback;
    }

    function esc(str) {
        return $('<div>').text(str).html();
    }

    function safeParse(md) {
        var text = md == null ? '' : String(md);
        if (typeof marked !== 'undefined' && typeof DOMPurify !== 'undefined') {
            return DOMPurify.sanitize(marked.parse(text));
        }
        return esc(text).replace(/\n/g, '<br>');
    }

    function pad(n) {
        return (n < 10 ? '0' : '') + n;
    }

    // ────────────────────────────────────────────────────────────────────────
    // ── DETAIL PAGE (page-detalhe.php) ──────────────────────────────────────
    // ────────────────────────────────────────────────────────────────────────

    $(function () {

        var $root = $('#fos-detalhe-data');
        if (!$root.length) { return; } // Not on the detail page.

        var detalheProdId = parseInt($root.data('production-id'), 10) || 0;
        var detalheStatus = $root.data('status') || '';
        var detalheNonce = $root.data('nonce') || '';
        var hubUrl = $root.data('hub-url') || '';
        var startedAtTs = parseInt($root.data('started-at'), 10) || 0;

        if (!detalheProdId) { return; }

        var agentQty = parseInt($root.data('agent-qty'), 10) || 6;
        var providerLabel = $root.data('provider-label') || '';
        var agentDefs = {};
        try {
            agentDefs = $root.data('agent-defs') || {};
        } catch (e) { console.warn('Contentosapp Studio: Could not parse agent-defs from DOM'); }

        $(document).on('click', '.js-costudio-open-addon-modal', function (e) {
            e.preventDefault();
            if (typeof window.costudioAddonModal === 'function') {
                window.costudioAddonModal();
            }
        });

        // ══════════════════════════════════════════════════════════════════════
        // 1. POLLING ENGINE
        // ══════════════════════════════════════════════════════════════════════

        var detalhePoller = {
            timer: null,
            pollMinMs: 4000,
            pollMaxMs: 15000,
            pollMs: 4000,
            stableTicks: 0,
            lastAgentDone: 0,
            serverOffset: null,
            status: detalheStatus,
            sessionStartedTs: startedAtTs,
            elapsedTotalS: parseInt($root.data('elapsed-total-s'), 10) || 0,
            currentAgent: parseInt($root.data('current-agent'), 10) || 0,
            currentAgentStartTs: parseInt($root.data('current-agent-started-at'), 10) || 0,
            currentAgentElapsedS: parseInt($root.data('current-agent-elapsed-s'), 10) || 0,
            lastRenderedTotalS: 0,
            lastRenderedAgentS: 0
        };

        // ── Timer Engine (Live Chronometer) ──────────────────────────────────
        var detalheTimer = {
            interval: null,

            start: function () {
                if (this.interval) return;

                var self = this;
                this.interval = setInterval(function () {
                    self.update();
                }, 1000);
                this.update();
            },

            stop: function () {
                if (this.interval) {
                    clearInterval(this.interval);
                    this.interval = null;
                }
            },

            update: function () {
                var now = Math.floor(Date.now() / 1000);

                // Adjust for server-client clock offset
                if (detalhePoller.serverOffset !== null) {
                    now += detalhePoller.serverOffset;
                }

                // A. Main Hero Timer (real wall-clock session)
                var totalS = detalhePoller.elapsedTotalS;
                if (isSessionClockRunning(detalhePoller.status) && detalhePoller.sessionStartedTs > 0) {
                    totalS = Math.max(totalS, now - detalhePoller.sessionStartedTs);
                }
                totalS = Math.max(0, totalS, detalhePoller.lastRenderedTotalS);
                detalhePoller.lastRenderedTotalS = totalS;
                $('.fos-hero__stat--duration .fos-hero__stat-value').text(this.format(totalS));

                // B. Current Agent Timer
                if (detalhePoller.currentAgent > 0) {
                    var agentDiff = detalhePoller.currentAgentElapsedS;
                    if (
                        isAgentClockRunning(detalhePoller.status)
                        && detalhePoller.currentAgentStartTs > 0
                    ) {
                        agentDiff = Math.max(agentDiff, now - detalhePoller.currentAgentStartTs);
                    }
                    agentDiff = Math.max(0, agentDiff, detalhePoller.lastRenderedAgentS);
                    detalhePoller.lastRenderedAgentS = agentDiff;

                    var $row = $('#agent-row-' + detalhePoller.currentAgent);
                    if ($row.length && (detalhePoller.currentAgentStartTs > 0 || agentDiff > 0)) {
                        var str = this.format(agentDiff);
                        $row.find('.fos-pipeline-row__duration:eq(0)').text(str);
                        $row.find('.fos-agent-duration-val').text(str);
                        $row.find('.fos-agent-meta-duration').show();
                    }
                }

                // C. Heartbeat Timer (Technical Logs)
                var lastHeartbeat = parseInt($('#fos-detalhe-debug-heartbeat-ts').val(), 10) || 0;
                if (lastHeartbeat > 0) {
                    var hbDiff = now - lastHeartbeat;
                    if (hbDiff < 0) hbDiff = 0;
                    $('#fos-heartbeat-timer').text(hbDiff + 's');
                }
            },

            format: function (diff) {
                var h = Math.floor(diff / 3600);
                var m = Math.floor((diff % 3600) / 60);
                var s = diff % 60;

                if (h > 0) {
                    return h + ':' + pad(m) + ':' + pad(s);
                }
                return pad(m) + ':' + pad(s);
            }
        };

        function isSessionClockRunning(status) {
            return status === 'pending'
                || status === 'starting'
                || status === 'running'
                || status === 'awaiting_approval';
        }

        function isAgentClockRunning(status) {
            return status === 'starting' || status === 'running';
        }

        // ── Actions Toggle (Technical Logs) ───────────────────────────────────
        $(document).on('click', '.fos-hero__debug-toggle, .fos-btn-debug-toggle, .fos-detalhe-debug-toggle', function (e) {
            e.preventDefault();
            var $content = $('#fos-detalhe-debug-content');
            var $carets = $('.fos-debug-caret');

            if ($content.length) {
                var isOpening = !$content.is(':visible');
                $carets.css('transform', isOpening ? 'rotate(180deg)' : 'rotate(0deg)');

                $content.slideToggle(250, function () {
                    if (isOpening) {
                        $content.css('display', 'grid');
                        $('html, body').animate({
                            scrollTop: $content.offset().top - 160
                        }, 500);
                    }
                });
            }
        });

        // ══════════════════════════════════════════════════════════════════════
        // 2. POLLING ENGINE CORE — status sync
        // ══════════════════════════════════════════════════════════════════════

        function detalheStartPolling() {
            detalheStopPolling();
            detalhePoller.pollMs = detalhePoller.pollMinMs;
            detalhePoller.stableTicks = 0;
            detalhePoll();
        }

        function detalheStopPolling() {
            if (detalhePoller.timer) {
                clearTimeout(detalhePoller.timer);
                detalhePoller.timer = null;
            }
        }

        function detalheScheduleNextPoll(delayMs) {
            detalheStopPolling();
            detalhePoller.timer = setTimeout(detalhePoll, Math.max(500, delayMs || detalhePoller.pollMs));
        }

        function detalheComputeDelay(status, currentAgent, doneCount) {
            var changed = (status !== detalhePoller.lastStatus)
                || (currentAgent !== detalhePoller.lastCurrent)
                || (doneCount !== detalhePoller.lastDoneCount);

            if (changed) {
                detalhePoller.stableTicks = 0;
                detalhePoller.pollMs = detalhePoller.pollMinMs;
            } else {
                detalhePoller.stableTicks += 1;
                if (detalhePoller.stableTicks >= 2) {
                    detalhePoller.pollMs = Math.min(detalhePoller.pollMs + 1000, detalhePoller.pollMaxMs);
                }
            }

            if (document.hidden) {
                detalhePoller.pollMs = Math.max(detalhePoller.pollMs, 10000);
            }

            detalhePoller.lastStatus = status;
            detalhePoller.lastCurrent = currentAgent;
            detalhePoller.lastDoneCount = doneCount;

            return detalhePoller.pollMs;
        }

        function detalheFormatDiagTs(ts) {
            var num = parseInt(ts, 10) || 0;
            if (!num) { return '—'; }
            return new Date(num * 1000).toISOString().replace('T', ' ').replace('.000Z', ' UTC');
        }

        function detalheRenderPipelineLog(lines) {
            var el = document.getElementById('fos-detalhe-debug-log-body');
            if (!el) { return; }
            if (!Array.isArray(lines) || !lines.length) {
                $(el).html('<div style="color:var(--fos-text-dim)">' + t('waiting_for_runtime_events', 'Waiting for runtime events…') + '</div>');
                return;
            }

            var html = '';
            lines.forEach(function (entry) {
                if (typeof entry === 'string') {
                    html += '<div class="fos-log-line">' + esc(entry) + '</div>';
                    return;
                }

                var ts = entry.ts ? new Date(entry.ts * 1000) : null;
                var timeStr = ts ? pad(ts.getHours()) + ':' + pad(ts.getMinutes()) + ':' + pad(ts.getSeconds()) : '—';

                var level = (entry.level || 'info').toUpperCase();
                var lvlClass = 'fos-log-level--' + (entry.level || 'info').toLowerCase();
                var agent = entry.agent ? '#' + pad(entry.agent) : '';
                var msg = entry.msg || '';

                html += '<div class="fos-log-line">' +
                    '<span class="fos-log-time">' + esc(timeStr) + '</span>' +
                    '<span class="fos-log-level ' + lvlClass + '">' + esc(level) + '</span>' +
                    (agent ? '<span class="fos-log-agent">' + esc(agent) + '</span>' : '') +
                    '<span class="fos-log-msg">' + esc(msg) + '</span>' +
                    '</div>';
            });

            $(el).html(html);
        }

        function detalheRenderDiag(diag, currentAgent, doneCount) {
            if (!diag || typeof diag !== 'object') { return; }

            var dispatchText = '—';
            if (diag.last_dispatch_method) {
                dispatchText = diag.last_dispatch_method;
                if (diag.last_dispatch_result) {
                    dispatchText += ' / ' + diag.last_dispatch_result;
                }
            }

            $('#fos-detalhe-debug-runner-state').text(diag.runner_state || 'waiting');
            $('#fos-detalhe-debug-stage').text(diag.current_stage || 'boot');
            $('#fos-detalhe-debug-token').text(diag.has_pending_token ? t('yes', 'Yes') : t('no', 'No'));
            $('#fos-detalhe-debug-token-source').text(diag.pending_token_source || '—');
            $('#fos-detalhe-debug-heartbeat').text(detalheFormatDiagTs(diag.last_heartbeat_at));
            $('#fos-detalhe-debug-heartbeat-ts').val(parseInt(diag.last_heartbeat_at, 10) || 0);
            $('#fos-detalhe-debug-dispatch').text(dispatchText);
            $('#fos-detalhe-debug-last-log').text(detalheFormatDiagTs(diag.last_log_at));

            var heartbeatAge = parseInt(diag.last_heartbeat_at, 10) ? (Math.floor(Date.now() / 1000) - parseInt(diag.last_heartbeat_at, 10)) : 0;
            var pendingAge = parseInt(diag.pending_token_age, 10) || 0;
            var runLockAge = parseInt(diag.run_lock_age, 10) || 0;
            var runIsActive = !!diag.run_lock_active;
            var looksStalled = currentAgent === 1
                && doneCount === 0
                && !runIsActive
                && ((!diag.last_heartbeat_at && diag.has_pending_token) || heartbeatAge > 45 || pendingAge > 45);

            if (looksStalled) {
                var bits = [];
                if (diag.has_pending_token) {
                    bits.push(t('pending_background_token', 'pending background token') + (pendingAge ? ' (' + pendingAge + 's)' : ''));
                }
                if (heartbeatAge > 45) {
                    bits.push(t('heartbeat_stale', 'stale heartbeat') + ' (' + heartbeatAge + 's)');
                }
                $('#fos-detalhe-debug-stall')
                    .text(t('pipeline_stall_warning', 'The pipeline looks stalled before Agent 01 could save output:') + ' ' + bits.join(' · '))
                    .show();
            } else if (runIsActive && currentAgent === 1 && doneCount === 0 && runLockAge > 0) {
                $('#fos-detalhe-debug-stall')
                    .text(t('pipeline_running_warning', 'A background runner is still processing Agent 01:') + ' ' + runLockAge + 's')
                    .show();
            } else {
                if ($('#fos-detalhe-debug-stall').length) {
                    $('#fos-detalhe-debug-stall').hide().text('');
                }
            }
        }

        function detalheSetFinalizingNotice(show, subtitle) {
            var $body = $('.fos-pipeline-body');
            if (!$body.length) { return; }

            var $notice = $('#fos-finalizing-notice');
            if (!show) {
                $notice.remove();
                return;
            }

            if (!$notice.length) {
                $notice = $('<div id="fos-finalizing-notice" class="fos-finalizing-notice">' +
                    '<div class="fos-finalizing-notice__icon">🚀</div>' +
                    '<div>' +
                    '<div class="fos-finalizing-notice__title"></div>' +
                    '<div class="fos-finalizing-notice__text"></div>' +
                    '</div>' +
                    '</div>');
                $body.find('.fos-pipeline-body__header').after($notice);
            }

            $notice.find('.fos-finalizing-notice__title').text(
                t('finalizing_notice_title', 'Todos os agentes terminaram. Publicação em andamento.')
            );
            $notice.find('.fos-finalizing-notice__text').text(
                subtitle || t('finalizing_notice_text', 'O Contentosapp Studio está preparando referências, imagens, schema, metadados e o rascunho final no WordPress.')
            );
        }

        function detalheEnsureAgentOutputPreview($row, output) {
            var text = output == null ? '' : String(output);
            if (!text.length) { return; }

            var $details = $row.find('.fos-pipeline-row__details').first();
            if (!$details.length) { return; }

            var $preview = $details.find('.fos-agent-output-preview').first();
            if (!$preview.length) {
                $preview = $(
                    '<div class="fos-pipeline-row__output-preview fos-agent-output-preview" style="display:none;">' +
                    '<div class="fos-preview-label">' + esc(t('output_preview', 'Output preview')) + '</div>' +
                    '<div class="fos-agent-output-preview__body"></div>' +
                    '</div>'
                );

                var $status = $details.find('.fos-agent-running-status').first();
                var $actions = $details.find('.fos-agent-done-actions').first();
                if ($status.length) {
                    $preview.insertBefore($status);
                } else if ($actions.length) {
                    $preview.insertBefore($actions);
                } else {
                    $details.append($preview);
                }
            }

            var previewText = text.length > 600 ? text.slice(0, 600) : text;
            var $bodyPreview = $preview.find('.fos-agent-output-preview__body');
            if ($bodyPreview.length) {
                $bodyPreview.html(safeParse(previewText));
            } else {
                $preview.children().not('.fos-preview-label').remove();
                $bodyPreview = $('<div class="fos-agent-output-preview__body"></div>').html(safeParse(previewText));
                $preview.append($bodyPreview);
            }

            $preview.stop(true, true).fadeIn(180);
        }

        function detalhePoll() {
            $.post(ajax, {
                action: 'costudio_poll_status',
                nonce: detalheNonce,
                production_id: detalheProdId,
            })
                .done(function (res) {
                    if (!res || !res.success) {
                        detalheScheduleNextPoll(Math.min(detalhePoller.pollMs + 2000, detalhePoller.pollMaxMs));
                        return;
                    }

                    var d = res.data;
                    if (detalhePoller.serverOffset === null && d.server_time) {
                        detalhePoller.serverOffset = d.server_time - Math.floor(Date.now() / 1000);
                    }

                    var newStatus = d.status || '';
                    var currentAgent = parseInt(d.current_agent, 10) || 0;
                    var agentsDone = d.agents_done || {};
                    var agentPreviews = d.agent_previews || {};
                    var doneCount = Object.keys(agentsDone).length;
                    var currentAgentQty = parseInt(d.agent_qty, 10) || agentQty || 1;
                    var isFinalizing = (
                        d.pipeline_phase === 'publishing'
                        || (newStatus === 'running' && doneCount >= currentAgentQty && currentAgent > currentAgentQty)
                    );

                    if (newStatus === 'pending') {
                        var queuePosition = parseInt(d.queue_position, 10) || 0;
                        var queueTotal = parseInt(d.queue_total, 10) || 0;
                        var queueMax = Math.max(queuePosition, queueTotal);

                        $('.fos-pending-queue-position').text(queuePosition ? '#' + queuePosition : t('waiting', 'Waiting'));
                        $('.fos-pending-queue-total').text(queueTotal);
                        $('.fos-detalhe-progress__pct').text(queuePosition ? '#' + queuePosition : t('queue_label', 'Queue'));
                        if (queuePosition) {
                            $('.fos-pending-queue-subtitle').text(
                                t('queue_position_sentence', 'Waiting for the local slot. Position {position} of {total} in the queue.')
                                    .replace('{position}', queuePosition)
                                    .replace('{total}', queueMax)
                            );
                        }
                    }

                    if (detalheStatus === 'pending' && newStatus === 'running') {
                        detalheStopPolling();
                        setTimeout(function () { window.location.reload(); }, 500);
                        return;
                    }

                    // Update stable timer boundaries. A genuine session/agent
                    // transition may reset the monotonic guards; ordinary chunk
                    // resumes keep the exact same boundary.
                    var nextSessionStart = parseInt(d.started_at_ts, 10) || detalhePoller.sessionStartedTs;
                    var nextAgentStart = parseInt(d.current_agent_start_ts, 10) || 0;
                    if (nextSessionStart !== detalhePoller.sessionStartedTs) {
                        // A running production cannot begin a new session by
                        // itself. Preserve the live boundary across internal
                        // pipeline rewinds (for example Reviewer → Writer).
                        // Manual reprocessing reloads the detail page and gets
                        // its new session boundary from the initial HTML.
                        if (
                            isSessionClockRunning(detalhePoller.status)
                            && isSessionClockRunning(newStatus)
                            && detalhePoller.sessionStartedTs > 0
                        ) {
                            nextSessionStart = detalhePoller.sessionStartedTs;
                        } else {
                            detalhePoller.lastRenderedTotalS = 0;
                        }
                    }
                    if (
                        currentAgent !== detalhePoller.currentAgent
                        || nextAgentStart !== detalhePoller.currentAgentStartTs
                    ) {
                        detalhePoller.lastRenderedAgentS = 0;
                    }

                    detalhePoller.status = newStatus;
                    detalhePoller.sessionStartedTs = nextSessionStart;
                    detalhePoller.elapsedTotalS = parseInt(d.elapsed_total_s, 10) || 0;
                    detalhePoller.currentAgent = currentAgent;
                    detalhePoller.currentAgentStartTs = nextAgentStart;
                    detalhePoller.currentAgentElapsedS = parseInt(d.current_agent_elapsed_s, 10) || 0;

                    if (d.pipeline_log && d.pipeline_log.length) {
                        detalheRenderPipelineLog(d.pipeline_log);
                    }
                    if (d.pipeline_diag) {
                        detalheRenderDiag(d.pipeline_diag, currentAgent, doneCount);
                    }

                    // ── Update Hero ──────────────────────────────────────────
                    var $hero = $('.fos-hero');
                    var pct = Math.round((doneCount / currentAgentQty) * 100);

                    $hero.find('.fos-hero__progress-fill').css('width', pct + '%');
                    $hero.find('.fos-hero__stat--progress .fos-hero__stat-value').text(doneCount + '/' + currentAgentQty);
                    detalheSetFinalizingNotice(isFinalizing, d.phase_subtitle || '');

                    if (d.agent_defs) { agentDefs = d.agent_defs; }

                    var $chip = $hero.find('.fos-hero__chip');
                    var $dot = $hero.find('.fos-hero__chip-dot');
                    $hero.removeClass('fos-hero--running fos-hero--paused fos-hero--error fos-hero--awaiting fos-hero--completed fos-hero--neutral fos-hero--queued');

                    if (newStatus === 'running') {
                        $hero.addClass('fos-hero--running');
                        $chip.text(isFinalizing ? t('finalizing', 'Finalizando') : t('running', 'Running')).prepend($dot.length ? $dot : '<span class="fos-hero__chip-dot"></span>');
                    } else if (newStatus === 'paused') {
                        $hero.addClass('fos-hero--paused');
                        $chip.text(t('paused', 'Paused')).prepend($dot.length ? $dot : '<span class="fos-hero__chip-dot"></span>');
                    } else if (newStatus === 'error') {
                        $hero.addClass('fos-hero--error');
                        $chip.text(t('error', 'Error'));
                        $dot.remove();
                    } else if (newStatus === 'completed') {
                        $hero.addClass('fos-hero--completed');
                        $chip.text(t('completed', 'Completed'));
                        $dot.remove();
                    } else if (newStatus === 'awaiting_approval') {
                        $hero.addClass('fos-hero--awaiting');
                        $chip.text(t('awaiting_approval', 'Awaiting Approval')).prepend($dot.length ? $dot : '<span class="fos-hero__chip-dot"></span>');
                    } else if (newStatus === 'pending') {
                        $hero.addClass('fos-hero--queued');
                        $chip.text(t('queued', 'Queued')).prepend($dot.length ? $dot : '<span class="fos-hero__chip-dot"></span>');
                    }

                    var $agentStat = $hero.find('.fos-hero__stat--agent');
                    var $agentLabel = $agentStat.find('.fos-hero__stat-label');
                    var $agentVal = $agentStat.find('.fos-hero__stat-value');
                    var $agentSub = $agentStat.find('.fos-hero__stat-sub');

                    if (isFinalizing) {
                        $agentLabel.text(t('current_stage', 'Etapa Atual'));
                        $agentVal.text(d.phase_label || t('finalizing_publication', 'Finalizando publicação'));
                        $agentSub.text(t('creating_wp_draft', 'criando o rascunho no WordPress…'));
                    } else if (currentAgent && agentDefs[currentAgent]) {
                        if (newStatus === 'error') {
                            $agentVal.css('color', '#fff'); // Inherit from hero--error
                        }
                        var agentName = typeof agentDefs[currentAgent] === 'object' ? agentDefs[currentAgent].name : agentDefs[currentAgent];
                        $agentLabel.text(newStatus === 'awaiting_approval' ? t('next_agent', 'Próximo Agente') : t('current_agent', 'Agente Atual'));
                        $agentVal.text(agentName);
                        if (newStatus === 'running') {
                            $agentSub.text(t('processing_stage', 'processando etapa…'));
                        }
                    }

                    var $durationVal = $hero.find('.fos-hero__stat--duration .fos-hero__stat-value');
                    var $durationSub = $hero.find('.fos-hero__stat--duration .fos-hero__stat-sub');

                    if (isSessionClockRunning(newStatus)) {
                        $durationSub.html('<span style="opacity: 0.8">● ' + t('live_heartbeat', 'live heartbeat') + '</span>');
                        detalheTimer.start();
                        detalheTimer.update();
                    } else {
                        detalheTimer.update();
                        detalheTimer.stop();
                        $durationVal.text(d.duration_lbl || '—');
                        $durationSub.text(t('session_duration', 'session duration'));
                    }

                    // ── Update Rows ──────────────────────────────────────────
                    for (var ti = 1; ti <= currentAgentQty; ti++) {
                        var $row = $('#agent-row-' + ti);
                        if (!$row.length) continue;

                        $row.removeClass('fos-pipeline-row--done fos-pipeline-row--running fos-pipeline-row--queued fos-pipeline-row--error');

                        // Rows flagged data-skipped="1" by the PHP renderer are
                        // permanently skipped for this production (News skips
                        // Agent 01; Update skips every agent except 04). The
                        // SKIPPED marker written to their output column would
                        // otherwise flip them to "Done" here.
                        if ($row.attr('data-skipped') === '1') {
                            $row.addClass('fos-pipeline-row--skipped');
                            $row.find('.fos-pipeline-node__glyph').text('⏭');
                            $row.find('.fos-pipeline-row__badge').text(t('skipped', 'Skipped')).css({ background: 'var(--fos-bg-soft)', color: 'var(--fos-text-dim)' });
                            $row.find('.fos-agent-running-status').hide();
                            $row.find('.fos-agent-done-actions').hide();
                            $row.find('.fos-agent-row-actions').hide();
                            $row.find('.fos-pipeline-row__meta').css('visibility', 'hidden');
                            continue;
                        }

                        if (agentsDone[String(ti)]) {
                            $row.addClass('fos-pipeline-row--done');
                            $row.find('.fos-pipeline-node__glyph').text('✓');
                            $row.find('.fos-pipeline-row__badge').text(t('done', 'Done')).css({ background: 'var(--fos-success-light)', color: 'var(--fos-success-dark)' });
                            $row.find('.fos-agent-running-status').hide();
                            $row.find('.fos-agent-done-actions').css('display', 'flex');
                            $row.find('.fos-agent-row-actions').css('display', 'flex')
                                .find('button').prop('disabled', false).attr('aria-disabled', 'false');
                            $row.find('.fos-pipeline-row__meta').css('visibility', 'visible');

                            var dur = (d.agent_durations && d.agent_durations[String(ti)]) ? d.agent_durations[String(ti)] : '—';
                            var wc = (d.word_counts && d.word_counts[String(ti)]) ? d.word_counts[String(ti)] : '—';
                            var started = (d.agent_start_times && d.agent_start_times[String(ti)]) ? d.agent_start_times[String(ti)] : '—';

                            $row.find('.fos-row-duration').text(dur);
                            $row.find('.fos-row-words').text(wc);
                            $row.find('.fos-agent-duration-val').text(dur);
                            $row.find('.fos-agent-words-val').text(wc);
                            $row.find('.fos-agent-start-val').text(started);
                            detalheEnsureAgentOutputPreview($row, agentPreviews[String(ti)] || (typeof agentsDone[String(ti)] === 'string' ? agentsDone[String(ti)] : ''));
                        } else if (ti === currentAgent) {
                            if (newStatus === 'error') {
                                $row.addClass('fos-pipeline-row--error');
                                $row.find('.fos-pipeline-node__glyph').text('!');
                                $row.find('.fos-pipeline-row__badge').text(t('failed', 'Failed')).css({ background: 'var(--fos-danger-light)', color: 'var(--fos-danger)' });
                                $row.find('.fos-agent-running-status').hide();
                                $row.find('.fos-agent-done-actions').hide();
                                $row.find('.fos-agent-row-actions').hide();
                            } else {
                                $row.addClass('fos-pipeline-row--running');
                                $row.find('.fos-pipeline-node__glyph').text('●');
                                $row.find('.fos-pipeline-row__badge').text(t('running', 'Running')).css({ background: 'var(--fos-primary-faint)', color: 'var(--fos-primary)' });
                                $row.find('.fos-agent-running-status').show();
                                $row.find('.fos-agent-done-actions').hide();
                                $row.find('.fos-agent-row-actions').css('display', 'flex')
                                    .find('button').prop('disabled', true).attr('aria-disabled', 'true');

                                // Update stats if available (even for running agent)
                                var dur = (d.agent_durations && d.agent_durations[String(ti)]) ? d.agent_durations[String(ti)] : '—';
                                var wc = (d.word_counts && d.word_counts[String(ti)]) ? d.word_counts[String(ti)] : '—';
                                var currentStarted = (d.agent_start_times && d.agent_start_times[String(ti)])
                                    ? d.agent_start_times[String(ti)]
                                    : '—';

                                $row.find('.fos-row-duration').text(dur);
                                $row.find('.fos-row-words').text(wc);
                                $row.find('.fos-agent-duration-val').text(dur);
                                $row.find('.fos-agent-words-val').text(wc);
                                $row.find('.fos-agent-start-val').text(currentStarted);
                                $row.find('.fos-pipeline-row__meta').css('visibility', 'visible');
                            }
                        } else {
                            $row.addClass('fos-pipeline-row--queued');
                            $row.find('.fos-pipeline-node__glyph').text(ti);
                            $row.find('.fos-pipeline-row__badge').text(t('waiting', 'Waiting')).css({ background: 'var(--fos-bg-soft)', color: 'var(--fos-text-dim)' });
                            $row.find('.fos-agent-running-status').hide();
                            $row.find('.fos-agent-done-actions').hide();
                            $row.find('.fos-agent-row-actions').hide();
                            $row.find('.fos-pipeline-row__meta').css('visibility', 'hidden');
                        }
                    }

                    if (d.stream_partial && d.stream_partial.text) {
                        detalheShowStreamPartial(d.stream_partial.agent, d.stream_partial.text);
                    } else {
                        $('.fos-stream-partial').remove();
                    }

                    if (newStatus === 'completed' || newStatus === 'error' || newStatus === 'paused' || newStatus === 'awaiting_approval' || newStatus === 'pending_upgrade') {
                        detalheStopPolling();
                        setTimeout(function () { window.location.reload(); }, 1200);
                        return;
                    }

                    detalheStatus = newStatus;
                    detalheScheduleNextPoll(detalheComputeDelay(newStatus, currentAgent, doneCount));
                })
                .fail(function () {
                    detalheScheduleNextPoll(Math.min(detalhePoller.pollMs + 2000, detalhePoller.pollMaxMs));
                });
        }

        function detalheShowStreamPartial(agentNum, text) {
            var $row = $('#agent-row-' + agentNum);
            if (!$row.length) { return; }

            var $partial = $row.find('.fos-stream-partial');
            if (!$partial.length) {
                $partial = $('<div class="fos-stream-partial" style="' +
                    'margin-top:8px;padding:8px 10px;' +
                    'background:var(--fos-surface-alt,#f8fafc);' +
                    'border:1px solid var(--fos-border,#e2e8f0);' +
                    'border-radius:6px;font-size:12px;line-height:1.5;' +
                    'max-height:120px;overflow-y:auto;' +
                    'color:var(--fos-text-sub,#64748b);' +
                    'white-space:pre-wrap;word-break:break-word;' +
                    'font-family:monospace;"></div>');
                // Find a good place to append inside the row or accordion content
                $row.find('.fos-pipeline-row__content').append($partial);
            }

            var preview = text.length > 500 ? '…' + text.slice(-500) : text;
            $partial.text(preview);
            if ($partial[0]) $partial[0].scrollTop = $partial[0].scrollHeight;

            // Update word count in real-time
            var wc = text.trim().split(/\s+/).length;
            $row.find('.fos-pipeline-row__duration:eq(1)').text(wc.toLocaleString());
            $row.find('.fos-agent-words-val').text(wc.toLocaleString());
        }

        // ══════════════════════════════════════════════════════════════════════
        // 4. ACCORDION UI TOGGLES
        // ══════════════════════════════════════════════════════════════════════

        $(document).on('click', '.fos-pipeline-row__trigger', function (e) {
            if ($(e.target).closest('button, a').length) { return; }
            var $trigger = $(this);
            var targetId = $trigger.data('target');
            if (!targetId) return;

            var $target = $('#' + targetId);
            if (!$target.length) return;

            $target.slideToggle(200);
            $trigger.find('.fos-pipeline-row__caret').toggleClass('is-open');
        });

        $(document).on('click', '.fos-log-trigger', function (e) {
            var $trigger = $(this);
            var targetId = $trigger.data('target');
            if (!targetId) return;

            var $target = $('#' + targetId);
            if (!$target.length) return;

            $target.slideToggle(200);
            $trigger.find('.fos-pipeline-row__caret').toggleClass('is-open');
        });

        // ══════════════════════════════════════════════════════════════════════
        // 5. ACTION HANDLERS (Pause, Resume, Cancel, Retry, Delete, Export)
        // ══════════════════════════════════════════════════════════════════════

        $(document).on('click', '.fos-pause-btn', function () {
            var $btn = $(this);
            var id = $btn.data('id');
            if (!id || $btn.prop('disabled')) return;

            $btn.prop('disabled', true).addClass('is-loading');
            $.post(ajax, { action: 'costudio_pause_production', nonce: detalheNonce, production_id: id })
                .done(function (res) { if (res && res.success) { window.location.reload(); } else { alert(res.data || t('error', 'Error')); $btn.prop('disabled', false).removeClass('is-loading'); } })
                .fail(function () { alert(t('network_error', 'Network error.')); $btn.prop('disabled', false).removeClass('is-loading'); });
        });

        $(document).on('click', '.fos-approve-btn', function () {
            var $btn = $(this);
            var id = $btn.data('id');
            if (!id || $btn.prop('disabled')) return;

            $btn.prop('disabled', true).addClass('is-loading');
            $.post(ajax, { action: 'costudio_approve_agent', nonce: detalheNonce, production_id: id })
                .done(function (res) { if (res && res.success) { window.location.reload(); } else { alert(res.data || t('error', 'Error')); $btn.prop('disabled', false).removeClass('is-loading'); } })
                .fail(function () { alert(t('network_error', 'Network error.')); $btn.prop('disabled', false).removeClass('is-loading'); });
        });

        $(document).on('click', '#fos-resume-pipeline-btn, .fos-resume-btn', function () {
            var $btn = $(this);
            var id = $btn.data('id');
            if (!id || $btn.prop('disabled')) return;

            $btn.prop('disabled', true).addClass('is-loading');
            $.post(ajax, { action: 'costudio_resume_pipeline', nonce: detalheNonce, production_id: id })
                .done(function (res) { if (res && res.success) { window.location.reload(); } else { alert(res.data || t('error', 'Error')); $btn.prop('disabled', false).removeClass('is-loading'); } })
                .fail(function () { alert(t('network_error', 'Network error.')); $btn.prop('disabled', false).removeClass('is-loading'); });
        });

        $(document).on('click', '.fos-cancel-btn', function () {
            var $btn = $(this);
            var id = $btn.data('id');
            if (!id || $btn.prop('disabled')) return;

            var $root = $btn.closest('.fos-cancel-btn-root');
            if (!$btn.hasClass('is-confirming')) {
                $btn.addClass('is-confirming').text(t('confirm_cancel_action', 'Confirm cancel?'));
                setTimeout(function () { $btn.removeClass('is-confirming').text(t('cancel', 'Cancel')); }, 3000);
                return;
            }

            $btn.prop('disabled', true).addClass('is-loading');
            $.post(ajax, { action: 'costudio_cancel_production', nonce: detalheNonce, production_id: id })
                .done(function (res) { if (res && res.success) { window.location.reload(); } else { alert(res.data || t('error', 'Error')); $btn.prop('disabled', false).removeClass('is-loading'); } })
                .fail(function () { alert(t('network_error', 'Network error.')); $btn.prop('disabled', false).removeClass('is-loading'); });
        });

        $(document).on('click', '.fos-retry-btn', function () {
            var $btn = $(this);
            var id = $btn.data('id');
            var agent = $btn.data('agent');
            if (!id || $btn.prop('disabled')) return;

            if (!$btn.hasClass('is-confirming')) {
                $btn.addClass('is-confirming').text(t('confirm_reprocess', 'Confirm reprocess?'));
                setTimeout(function () { $btn.removeClass('is-confirming').text(t('reprocess_from_here', 'Reprocess from here')); }, 3000);
                return;
            }

            $btn.prop('disabled', true).addClass('is-loading');
            $.post(ajax, { action: 'costudio_retry_agent', nonce: detalheNonce, production_id: id, from_agent: agent })
                .done(function (res) { if (res && res.success) { window.location.reload(); } else { alert(res.data || t('error', 'Error')); $btn.prop('disabled', false).removeClass('is-loading'); } })
                .fail(function () { alert(t('network_error', 'Network error.')); $btn.prop('disabled', false).removeClass('is-loading'); });
        });

        $(document).on('click', '.fos-delete-btn', function () {
            var $btn = $(this);
            var id = $btn.data('id');
            if (!id || $btn.prop('disabled')) return;

            if (!confirm(t('confirm_delete', 'Deseja excluir esta produção permanentemente?'))) return;

            $btn.prop('disabled', true).addClass('is-loading');
            $.post(ajax, { action: 'costudio_delete_production', nonce: detalheNonce, production_id: id })
                .done(function (res) { if (res && res.success) { window.location.href = hubUrl; } else { alert(res.data || t('error', 'Error')); $btn.prop('disabled', false).removeClass('is-loading'); } })
                .fail(function () { alert(t('network_error', 'Network error.')); $btn.prop('disabled', false).removeClass('is-loading'); });
        });

        $(document).on('click', '.fos-export-zip-btn', function () {
            var $btn = $(this);
            var id = $btn.data('id');
            if (!id || $btn.prop('disabled')) return;

            $btn.prop('disabled', true).addClass('is-loading');
            var form = document.createElement('form');
            form.method = 'POST';
            form.action = ajax;
            form.target = '_blank';
            form.innerHTML = '<input type="hidden" name="action" value="costudio_export_production"><input type="hidden" name="nonce" value="' + detalheNonce + '"><input type="hidden" name="production_id" value="' + id + '">';
            document.body.appendChild(form);
            form.submit();
            document.body.removeChild(form);
            setTimeout(function () { $btn.prop('disabled', false).removeClass('is-loading'); }, 2000);
        });

        // ══════════════════════════════════════════════════════════════════════
        // 6. OUTPUT VIEW / EDIT HANDLERS
        // ══════════════════════════════════════════════════════════════════════

        var currentEditState = { id: 0, agent: 0, updatedAt: '' };

        $(document).on('click', '[data-action="fos-view-output"], [data-action="fos-edit-output"]', function (e) {
            e.preventDefault();
            var $btn = $(this);
            var action = $btn.data('action');
            var id = $btn.data('id');
            var agent = $btn.data('agent');

            if (!id || !agent) return;

            $btn.addClass('is-loading');
            $.post(ajax, { action: 'costudio_get_production', nonce: detalheNonce, production_id: id })
                .done(function (res) {
                    $btn.removeClass('is-loading');
                    if (!res.success) { alert(res.data || t('error', 'Error')); return; }

                    var prod = res.data;
                    var col = 'output_' + String(agent).padStart(2, '0');
                    var content = prod[col] || '';

                    currentEditState = { id: id, agent: agent, updatedAt: prod.updated_at || '' };

                    fosOpenOutputModal(agent, content, action === 'fos-edit-output', $btn[0]);
                })
                .fail(function () { $btn.removeClass('is-loading'); alert(t('network_error', 'Network error.')); });
        });

        $(document).on('click', '[data-action="fos-retry-agent"]', function (e) {
            e.preventDefault();
            var $btn = $(this);
            var id = $btn.data('id');
            var agent = $btn.data('agent');

            if (!id || !agent) return;

            if (!$btn.hasClass('is-confirming')) {
                $btn.addClass('is-confirming').text(t('confirm_reprocess_from', 'Confirmar — reprocessar do Agente') + ' ' + agent);
                setTimeout(function () { $btn.removeClass('is-confirming').text(t('reprocess_from_here', 'Reprocessar daqui')); }, 3000);
                return;
            }

            $btn.prop('disabled', true).addClass('is-loading');
            $.post(ajax, { action: 'costudio_retry_agent', nonce: detalheNonce, production_id: id, from_agent: agent })
                .done(function (res) { if (res && res.success) { window.location.reload(); } else { alert(res.data || t('error', 'Error')); $btn.prop('disabled', false).removeClass('is-loading'); } })
                .fail(function () { alert(t('network_error', 'Network error.')); $btn.prop('disabled', false).removeClass('is-loading'); });
        });

        function fosOpenOutputModal(agent, content, isEdit, trigger) {
            if (window.CostudioOutputInspector && typeof window.CostudioOutputInspector.open === 'function') {
                var definition = agentDefs[agent] || agentDefs[String(agent)] || {};
                var agentName = typeof definition === 'object' ? (definition.name || '') : String(definition || '');
                var agentEmoji = typeof definition === 'object' ? (definition.emoji || '') : '';
                var agentDesc = typeof definition === 'object' ? (definition.desc || '') : '';

                window.CostudioOutputInspector.open({
                    agent: agent,
                    agentName: agentName,
                    agentEmoji: agentEmoji,
                    agentDesc: agentDesc,
                    content: content,
                    mode: isEdit ? 'edit' : 'preview',
                    editable: true,
                    trigger: trigger || null,
                    metadata: { providerLabel: providerLabel },
                    productionId: detalheProdId,
                    nonce: detalheNonce
                });
                return;
            }

            var $modal = $('#fos-output-modal');
            var title = t('agent_label', 'Agent') + ' ' + String(agent).padStart(2, '0');

            $('#fos-output-modal-title').text(title);
            $('#fos-output-editor').val(content);

            $('#fos-output-body-html').html(safeParse(content));

            if (isEdit) {
                $('#fos-output-view-wrap').hide();
                $('#fos-output-edit-wrap').show();
                $('#fos-output-save-btn').show();
            } else {
                $('#fos-output-view-wrap').show();
                $('#fos-output-edit-wrap').hide();
                $('#fos-output-save-btn').hide();
            }

            $modal.fadeIn(180);
            $('body').addClass('fos-modal-open');
        }

        $(document).on('click', '[data-action="fos-modal-close"]', function () {
            $('.fos-modal').fadeOut(150);
            $('body').removeClass('fos-modal-open');
        });

        $(document).on('click', '.fos-modal', function (e) {
            if (this.id === 'fos-output-modal' && window.CostudioOutputInspector) return;
            // Close if clicking anywhere outside the content box
            if (!$(e.target).closest('.fos-modal__content').length) {
                $(this).fadeOut(150);
                $('body').removeClass('fos-modal-open');
            }
        });

        $(document).on('click', '#fos-output-copy-btn', function () {
            var content = $('#fos-output-editor').val();
            if (!content) return;

            var $btn = $(this);
            var $txt = $btn.find('.fos-btn__text');
            var original = $txt.text();

            if (navigator.clipboard && navigator.clipboard.writeText) {
                navigator.clipboard.writeText(content).then(function () {
                    $txt.text(t('copied', 'Copiado!'));
                    setTimeout(function () { $txt.text(original); }, 2000);
                });
            } else {
                // Fallback for non-https or older browsers
                var textArea = document.createElement("textarea");
                textArea.value = content;
                document.body.appendChild(textArea);
                textArea.select();
                try {
                    document.execCommand('copy');
                    $txt.text(t('copied', 'Copiado!'));
                    setTimeout(function () { $txt.text(original); }, 2000);
                } catch (err) {
                    console.error('Copy failed', err);
                }
                document.body.removeChild(textArea);
            }
        });

        $(document).on('click', '#fos-output-save-btn', function () {
            var $btn = $(this);
            var content = $('#fos-output-editor').val();

            $btn.prop('disabled', true).addClass('is-loading');
            $.post(ajax, {
                action: 'costudio_update_output',
                nonce: detalheNonce,
                production_id: currentEditState.id,
                agent: currentEditState.agent,
                content: content,
                updated_at: currentEditState.updatedAt
            })
                .done(function (res) {
                    if (res.success) {
                        window.location.reload();
                    } else {
                        alert(res.data || t('error', 'Error'));
                        $btn.prop('disabled', false).removeClass('is-loading');
                    }
                })
                .fail(function () { $btn.prop('disabled', false).removeClass('is-loading'); alert(t('network_error', 'Network error.')); });
        });

        $(document).on('click', '#fos-preview-article-btn', function (e) {
            e.preventDefault();
            var $btn = $(this);
            var id = $btn.data('id');

            if (!id) return;

            $btn.addClass('is-loading');
            // Renders through the SAME real publish-time pipeline as the
            // Output Inspector's Writer preview (Costudio_WP_Publisher::preview(),
            // via costudio_preview_article) — not a client-side approximation,
            // and not the old output_04+05+06 concatenation (output_06 is the
            // Visual Designer's VISUAL_PLAN JSON, never part of the article body).
            $.post(ajax, { action: 'costudio_preview_article', nonce: detalheNonce, production_id: id })
                .done(function (res) {
                    $btn.removeClass('is-loading');
                    if (!res.success) { alert(res.data || t('error', 'Error')); return; }

                    var preview = res.data;

                    $('#fos-preview-modal-title').text(preview.title || t('article_preview', 'Article Preview'));
                    $('#fos-preview-seo-title').text(preview.seo_title || '—');
                    $('#fos-preview-slug').text(preview.slug || '—');
                    $('#fos-preview-meta-desc').text(preview.meta_description || '—');
                    $('#fos-preview-focus-kw').text(preview.focus_keyword || '—');

                    var html = window.DOMPurify ? window.DOMPurify.sanitize(preview.html || '') : '';
                    $('#fos-preview-body').html(html || '<p><em>' + t('empty', '(empty)') + '</em></p>');

                    $('#fos-preview-modal').fadeIn(180);
                    $('body').addClass('fos-modal-open');
                })
                .fail(function () { $btn.removeClass('is-loading'); alert(t('network_error', 'Network error.')); });
        });

        // ══════════════════════════════════════════════════════════════════════
        // 9. BOOTSTRAP
        // ══════════════════════════════════════════════════════════════════════

        $(document).ready(function () {
            if (detalheStatus === 'running' || detalheStatus === 'starting' || detalheStatus === 'pending') {
                detalheStartPolling();
            }
            if (isSessionClockRunning(detalheStatus) && startedAtTs > 0) {
                detalheTimer.start();
            }
        });

    });

}(jQuery));
