// suno_detail.js — 批次详情页：轮询状态 + 改名 + 封面/歌词 + 发行勾选
(function() {
const root = document.getElementById('suno-detail');
if (!root) return;
const STATUS_URL = root.dataset.statusUrl;
const RESUME_URL = root.dataset.resumeUrl;
const RENAME_TPL = root.dataset.renameUrlTpl;
const PUBLISH_TPL = root.dataset.publishUrlTpl;
// Fast (2s) while the batch is progressing; stops entirely once terminal.
const POLL_MS = 2000;
const POLL_MS_ERR = 4000;
const TERMINAL_BATCH_STATUSES = new Set(['completed', 'failed']);
const TERMINAL_CLIP_STATUSES = new Set(['complete', 'error', 'failed']);
const csrf = document.querySelector('meta[name="csrf-token"]')?.content || '';
let pollStopped = false;

function applySnapshot(snap) {
    document.getElementById('d-progress').textContent = snap.completed_count + '/' + snap.total_count;
    document.getElementById('d-failed').textContent = snap.failed_count;
    const stEl = document.getElementById('d-status');
    if (stEl.textContent !== snap.batch_status) {
        stEl.textContent = snap.batch_status;
        stEl.className = 'badge badge-' + snap.batch_status;
    }
    // Show/hide verification-pause panel
    const panel = document.getElementById('d-resume-panel');
    if (panel) {
        panel.style.display = (snap.batch_status === 'paused_verification') ? 'block' : 'none';
    }
    (snap.clips || []).forEach(c => {
        const card = document.querySelector('.clip-card[data-clip-id="' + c.clip_id + '"]');
        if (!card) return;

        // Status badge
        const stBadge = card.querySelector('.c-status');
        if (stBadge && stBadge.textContent !== (c.status || '-')) {
            stBadge.textContent = c.status || '-';
            stBadge.className = 'badge c-status badge-' + (c.status || '');
        }

        // Cover: swap placeholder div for <img> once image_url lands
        if (c.image_url) {
            const cover = card.querySelector('.c-cover');
            if (cover && cover.tagName !== 'IMG') {
                const img = document.createElement('img');
                img.className = 'c-cover';
                img.src = c.image_url;
                img.alt = '';
                img.style.cssText = 'width:100px; height:100px; object-fit:cover; border-radius:6px; background:#eee;';
                cover.replaceWith(img);
            } else if (cover && cover.src !== c.image_url) {
                cover.src = c.image_url;
            }
        }

        // Audio: swap placeholder span for <audio> once audio_url lands
        const wrap = card.querySelector('.c-audio-wrap');
        if (wrap && c.audio_url) {
            const existing = wrap.querySelector('audio.c-audio');
            if (!existing) {
                wrap.innerHTML = '';
                const aud = document.createElement('audio');
                aud.controls = true;
                aud.preload = 'none';
                aud.src = c.audio_url;
                aud.className = 'c-audio';
                aud.style.cssText = 'width:100%; height:30px;';
                wrap.appendChild(aud);
            }
        }

        // Lyrics: update if new text arrived
        const ly = card.querySelector('.c-lyrics');
        if (ly && c.lyrics && ly.textContent !== c.lyrics) {
            ly.textContent = c.lyrics;
            const sum = card.querySelector('details > summary');
            if (sum) sum.textContent = '歌词（' + c.lyrics.length + ' 字）';
        }
    });
}

function isFullyTerminal(snap) {
    if (!snap || !TERMINAL_BATCH_STATUSES.has(snap.batch_status)) return false;
    // Also require every clip to be in a terminal state — Suno often keeps
    // filling in audio_url / lyrics for a minute or two after the batch itself
    // is flagged completed.
    const clips = snap.clips || [];
    if (clips.length === 0) return true;  // failed batches often have zero clips
    return clips.every(c => TERMINAL_CLIP_STATUSES.has(c.status || ''));
}

function poll() {
    if (pollStopped) return;
    fetch(STATUS_URL)
        .then(r => r.json())
        .then(snap => {
            if (snap && !snap.error) {
                applySnapshot(snap);
                if (isFullyTerminal(snap)) {
                    pollStopped = true;
                    return;
                }
            }
            setTimeout(poll, POLL_MS);
        })
        .catch(() => setTimeout(poll, POLL_MS_ERR));
}

// Poll immediately on page load — no initial delay.
poll();

// ── 恢复（验证暂停）─────────────────────────────────────────────────
const resumeBtn = document.getElementById('d-resume-btn');
if (resumeBtn && RESUME_URL) {
    resumeBtn.addEventListener('click', async function() {
        const msg = document.getElementById('d-resume-msg');
        this.disabled = true;
        const orig = this.textContent;
        this.textContent = '提交中...';
        if (msg) { msg.textContent = ''; msg.style.color = '#888'; }
        try {
            const resp = await fetch(RESUME_URL, {
                method: 'POST',
                headers: {'Content-Type': 'application/json', 'X-CSRF-Token': csrf},
                body: JSON.stringify({csrf_token: csrf}),
            });
            const data = await resp.json();
            if (data.ok) {
                if (msg) { msg.textContent = '已恢复，后台继续提交...'; msg.style.color = '#52c41a'; }
                const panel = document.getElementById('d-resume-panel');
                if (panel) panel.style.display = 'none';
            } else {
                if (msg) { msg.textContent = '失败：' + (data.error || ''); msg.style.color = '#f5222d'; }
                this.textContent = orig;
                this.disabled = false;
            }
        } catch (e) {
            if (msg) { msg.textContent = '网络错误：' + e.message; msg.style.color = '#f5222d'; }
            this.textContent = orig;
            this.disabled = false;
        }
    });
}

// ── Rename ───────────────────────────────────────────────────────────
document.querySelectorAll('.c-rename-btn').forEach(btn => {
    btn.addEventListener('click', async function() {
        const card = this.closest('.clip-card');
        const cid = card.dataset.clipId;
        const inp = card.querySelector('.c-rename-input');
        const newTitle = (inp.value || '').trim();
        if (!newTitle) { alert('请输入新名'); return; }
        const url = RENAME_TPL.replace('__CLIP__', cid);
        this.disabled = true;
        const orig = this.textContent;
        this.textContent = '...';
        try {
            const fd = new FormData();
            fd.append('title', newTitle);
            fd.append('csrf_token', csrf);
            const resp = await fetch(url, {method: 'POST', body: fd, headers: {'X-CSRF-Token': csrf}});
            const data = await resp.json();
            if (data.ok) {
                this.textContent = '✓';
                setTimeout(() => { this.textContent = orig; this.disabled = false; }, 1500);
            } else {
                alert('改名失败：' + (data.error || ''));
                this.textContent = orig;
                this.disabled = false;
            }
        } catch (e) {
            alert('网络错误：' + e.message);
            this.textContent = orig;
            this.disabled = false;
        }
    });
});

// ── 发行勾选 ────────────────────────────────────────────────────────
document.querySelectorAll('.c-publish-chk').forEach(chk => {
    chk.addEventListener('change', async function() {
        const card = this.closest('.clip-card');
        const cid = card.dataset.clipId;
        const url = PUBLISH_TPL.replace('__CLIP__', cid);
        const desired = this.checked ? 1 : 0;
        this.disabled = true;
        try {
            const resp = await fetch(url, {
                method: 'POST',
                headers: {'Content-Type': 'application/json', 'X-CSRF-Token': csrf},
                body: JSON.stringify({is_published: desired, csrf_token: csrf}),
            });
            const data = await resp.json();
            if (!data.ok) {
                alert('保存失败：' + (data.error || ''));
                this.checked = !desired;
            }
        } catch (e) {
            alert('网络错误：' + e.message);
            this.checked = !desired;
        } finally {
            this.disabled = false;
        }
    });
});
})();
