// media.js — Webamp player, music library, media panel, video tab, gallery vault
// Extracted from dashboard.html

// ── Media Player (Webamp integration) ─────────────────────
const _fallbackAudio = document.getElementById('webamp-fallback-audio');
let _webampReady = false;

function initWebamp() {
    if (typeof Webamp === 'undefined') {
        console.warn('Webamp not loaded, using fallback audio');
        return;
    }
    if (!Webamp.browserIsSupported()) {
        console.warn('Webamp not supported in this browser, using fallback');
        return;
    }
    window._webamp = new Webamp({
        initialTracks: [],
        enableHotkeys: true,
        zIndex: 1000,
    });
    window._webamp.renderWhenReady(document.getElementById('webamp-container')).then(() => {
        _webampReady = true;
        // Start hidden until user plays something
        window._webamp.close();
    });
}

function showWebamp() {
    if (window._webamp && _webampReady) {
        window._webamp.reopen();
    } else {
        // If Webamp isn't loaded, show a message
        const launcher = document.getElementById('webamp-launcher');
        launcher.querySelector('div').textContent = 'Loading player...';
        setTimeout(() => {
            launcher.querySelector('div').textContent = 'Music Player';
        }, 2000);
    }
}

const mediaPlayer = {
    current: null,
    isPlaying: false,

    play(item) {
        const url = item.stream_url || item.audio_url || '';
        if (!url) return;

        this.current = item;
        const title = item.name || item.title || 'Unknown';
        const artist = item.artist || item.country || '';

        if (window._webamp && _webampReady) {
            const track = {
                url: url,
                metaData: { artist: artist, title: title }
            };
            if (item.duration_seconds) track.duration = item.duration_seconds;
            window._webamp.setTracksToPlay([track]);
            window._webamp.reopen();
            this.isPlaying = true;
        } else {
            // Fallback: use basic <audio> element
            _fallbackAudio.src = url;
            _fallbackAudio.load();
            _fallbackAudio.play().catch(e => console.warn('Playback error:', e));
            this.isPlaying = true;
        }

        // Highlight playing card
        document.querySelectorAll('.media-card.playing').forEach(c => c.classList.remove('playing'));
        document.querySelectorAll('.media-card').forEach(c => {
            if (c.dataset.url === url) c.classList.add('playing');
        });

        this._recordHistory(item);
    },

    stop() {
        if (window._webamp && _webampReady) {
            window._webamp.stop();
        } else {
            _fallbackAudio.pause();
            _fallbackAudio.src = '';
        }
        this.isPlaying = false;
        this.current = null;
        document.querySelectorAll('.media-card.playing').forEach(c => c.classList.remove('playing'));
    },

    togglePlay() {
        if (!this.current) return;
        if (window._webamp && _webampReady) {
            // Webamp handles its own play/pause via its UI
            return;
        }
        if (this.isPlaying) {
            _fallbackAudio.pause();
            this.isPlaying = false;
        } else {
            _fallbackAudio.play().catch(() => {});
            this.isPlaying = true;
        }
    },

    setVolume(v) {
        if (window._webamp && _webampReady) {
            window._webamp.setVolume(Math.round(Math.max(0, Math.min(1, v)) * 100));
        } else {
            _fallbackAudio.volume = Math.max(0, Math.min(1, v));
        }
    },

    _recordHistory(item) {
        const body = {
            name: item.name || item.title || '',
            type: item.stream_url ? 'radio' : (item.audio_url ? 'podcast' : 'music'),
        };
        if (item.stream_url) body.stream_url = item.stream_url;
        if (item.audio_url) body.audio_url = item.audio_url;
        if (item.favicon) body.favicon = item.favicon;
        if (item.image) body.image = item.image;
        apiFetch('/api/media/history', { method: 'POST' }).catch(() => {});
    }
};

function _formatTime(s) {
    if (!s || !isFinite(s)) return '0:00';
    const m = Math.floor(s / 60);
    const sec = Math.floor(s % 60);
    return m + ':' + (sec < 10 ? '0' : '') + sec;
}

// ── Music Library (Vault) ─────────────────────────────
let _musicLibraryLoaded = false;

async function loadMusicLibrary() {
    const search = (document.getElementById('music-search-input').value || '').trim();
    const params = search ? '?search=' + encodeURIComponent(search) : '';
    try {
        const res = await apiFetch(API + '/api/media/music/library' + params);
        const data = await res.json();
        renderMusicLibrary(data.tracks || []);
    } catch (e) {
        console.warn('Music library load error:', e);
    }
}

function renderMusicLibrary(tracks) {
    const grid = document.getElementById('music-library');
    const dropzone = document.getElementById('music-dropzone');
    if (!tracks.length) {
        grid.innerHTML = '';
        dropzone.style.display = '';
        return;
    }
    dropzone.style.display = 'none';
    let html = '';
    tracks.forEach(t => {
        const sizeKB = t.size ? (t.size / 1024).toFixed(0) + ' KB' : '';
        const sizeMB = t.size > 1048576 ? (t.size / 1048576).toFixed(1) + ' MB' : sizeKB;
        const added = t.added_at ? formatDate(t.added_at, 'date') : '';
        const streamUrl = API + '/api/media/music/stream/' + t.id;
        html += '<div class="media-card" data-url="' + streamUrl + '">';
        html += '<div class="media-card-art"><i class="fas fa-music"></i></div>';
        html += '<div class="media-card-info">';
        html += '<h4>' + escapeHtml(t.filename || 'Unknown') + '</h4>';
        html += '<p>' + sizeMB + (added ? ' &middot; ' + added : '') + '</p>';
        html += '</div>';
        html += '<div class="media-card-actions">';
        html += '<button class="play-btn" onclick="mediaPlayer.play({audio_url:\'' + streamUrl + '\', name:\'' + escapeHtml(t.filename || '').replace(/'/g, "\\'") + '\'})" title="Play"><i class="fas fa-play"></i></button>';
        if (window._webamp && _webampReady) {
            html += '<button onclick="addToWebampPlaylist(\'' + streamUrl + '\', \'' + escapeHtml(t.filename || '').replace(/'/g, "\\'") + '\')" title="Add to playlist"><i class="fas fa-list"></i></button>';
        }
        html += '<button onclick="deleteMusicTrack(\'' + t.id + '\')" title="Delete" style="color:var(--error)"><i class="fas fa-trash"></i></button>';
        html += '</div></div>';
    });
    grid.innerHTML = html;
}

function addToWebampPlaylist(url, name) {
    if (window._webamp && _webampReady) {
        window._webamp.appendTracks([{ url: url, metaData: { title: name } }]);
        window._webamp.reopen();
    }
}

async function uploadMusicFiles(files) {
    if (!files || !files.length) return;
    const progress = document.getElementById('music-upload-progress');
    progress.style.display = '';
    let uploaded = 0;
    for (const file of files) {
        progress.textContent = 'Uploading ' + (uploaded + 1) + '/' + files.length + ': ' + file.name + '...';
        const formData = new FormData();
        formData.append('file', file);
        try {
            await apiFetch(API + '/api/media/music/upload', { method: 'POST', body: formData });
            uploaded++;
        } catch (e) {
            console.warn('Upload failed for', file.name, e);
        }
    }
    progress.textContent = uploaded + ' file(s) uploaded.';
    setTimeout(() => { progress.style.display = 'none'; }, 3000);
    // Reset file input
    document.getElementById('music-upload-input').value = '';
    loadMusicLibrary();
}

async function deleteMusicTrack(trackId) {
    if (!confirm('Delete this track?')) return;
    try {
        await apiFetch(API + '/api/media/music/' + trackId, { method: 'DELETE' });
        loadMusicLibrary();
    } catch (e) {
        console.warn('Delete failed:', e);
    }
}

function filterMusicLibrary() {
    loadMusicLibrary();
}

// Drag-and-drop on music tab
(function() {
    const musicTab = document.getElementById('media-music');
    if (!musicTab) return;
    const dropzone = document.getElementById('music-dropzone');
    ['dragenter', 'dragover'].forEach(evt => {
        musicTab.addEventListener(evt, e => {
            e.preventDefault();
            e.stopPropagation();
            if (dropzone) dropzone.classList.add('drag-over');
        });
    });
    ['dragleave', 'drop'].forEach(evt => {
        musicTab.addEventListener(evt, e => {
            e.preventDefault();
            e.stopPropagation();
            if (dropzone) dropzone.classList.remove('drag-over');
        });
    });
    musicTab.addEventListener('drop', e => {
        const files = e.dataTransfer.files;
        if (files && files.length) uploadMusicFiles(files);
    });
})();

// ── Media Panel Functions ────────────────────────
let _mediaGenresLoaded = false;
let _mediaInitialized = false;

async function loadMedia() {
    if (!_mediaInitialized) {
        _mediaInitialized = true;
        loadRadioGenres();
        loadRadioPopular();
    }
}

function switchMediaTab(tab) {
    document.querySelectorAll('.media-tab').forEach(t => t.classList.remove('active'));
    document.querySelectorAll('.media-tab-content').forEach(c => c.style.display = 'none');
    event.currentTarget.classList.add('active');
    document.getElementById('media-' + tab).style.display = '';

    if (tab === 'favorites') loadFavorites();
    if (tab === 'history') loadMediaHistory();
    if (tab === 'music' && !_musicLibraryLoaded) { _musicLibraryLoaded = true; loadMusicLibrary(); }
    if (tab === 'radio' && document.getElementById('radio-results').innerHTML === '') loadRadioPopular();
    if (tab === 'video') document.getElementById('video-search-input').focus();
}

// ── Video Tab Functions ─────────────────────────────
function toggleVideoPlatform(chip) {
    const platform = chip.dataset.platform;
    const bar = chip.closest('.video-platform-bar');
    const allChip = bar.querySelector('[data-platform="all"]');
    if (platform === 'all') {
        bar.querySelectorAll('.video-platform-chip').forEach(c => c.classList.remove('active'));
        allChip.classList.add('active');
    } else {
        allChip.classList.remove('active');
        chip.classList.toggle('active');
        if (!bar.querySelector('.video-platform-chip.active')) {
            allChip.classList.add('active');
        }
    }
    if (document.getElementById('video-search-input').value.trim()) searchVideos();
}

function getSelectedPlatforms() {
    const bar = document.querySelector('.video-platform-bar');
    if (!bar || bar.querySelector('[data-platform="all"].active')) return null;
    const active = bar.querySelectorAll('.video-platform-chip.active');
    return Array.from(active).map(c => c.dataset.platform);
}

async function searchVideos() {
    const query = document.getElementById('video-search-input').value.trim();
    if (!query) return;
    const grid = document.getElementById('video-results');
    grid.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)"><div class="spinner"></div></div>';
    try {
        const payload = {query: query};
        const platforms = getSelectedPlatforms();
        if (platforms) payload.platforms = platforms;
        const res = await apiFetch('/api/media/video/search', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(payload)
        });
        const data = await res.json();
        renderVideoResults(data.items || [], grid);
    } catch (e) {
        grid.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)">Video search failed.</div>';
    }
}

function renderVideoResults(items, container) {
    if (!items.length) {
        container.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)">No results found.</div>';
        return;
    }
    let html = '';
    items.forEach((item, idx) => {
        const title = escapeHtml(item.title || item.name || 'Untitled');
        const detail = escapeHtml(item.source || item.detail || '');
        const thumb = item.thumbnail || '';
        const url = item.url || item.href || '';
        html += '<div class="video-card" data-url="' + escapeHtml(url) + '">';
        if (thumb) {
            html += '<img class="video-thumbnail" src="' + escapeHtml(thumb)
                + '" alt="" onerror="this.style.display=\'none\'" onclick="playVideo(this.closest(\'.video-card\'))" />';
        }
        html += '<div class="video-info">';
        html += '<div class="video-title" title="' + title + '">' + title + '</div>';
        if (detail) html += '<div class="video-detail">' + detail + '</div>';
        html += '<div class="video-card-actions">';
        html += '<button class="btn-play" onclick="playVideo(this.closest(\'.video-card\'))">'
            + '<i class="fas fa-play"></i> Play</button>';
        html += '<button class="btn-download" onclick="downloadVideo(this, \'' + escapeHtml(url).replace(/'/g, "\\'") + '\')">'
            + '<i class="fas fa-download"></i> Download</button>';
        html += '</div></div></div>';
        html += '<div class="video-player-inline" id="video-player-' + idx + '"></div>';
    });
    container.innerHTML = html;
}

function _detectVideoPlatform(url) {
    try {
        const host = new URL(url).hostname.replace(/^(www\.|m\.)/, '');
        if (host === 'youtube.com' || host === 'youtu.be' || host === 'youtube-nocookie.com') return 'youtube';
        if (host === 'vimeo.com' || host === 'player.vimeo.com') return 'vimeo';
    } catch(e) {}
    return 'other';
}

function _extractVideoId(url) {
    try {
        const u = new URL(url);
        const host = u.hostname.replace(/^(www\.|m\.)/, '');
        if (host === 'youtube.com' || host === 'youtube-nocookie.com') {
            return u.searchParams.get('v') || u.pathname.split('/').pop();
        }
        if (host === 'youtu.be') return u.pathname.slice(1);
        if (host === 'vimeo.com') return u.pathname.split('/').filter(Boolean).pop();
    } catch(e) {}
    return '';
}

let _activeVideoPlayer = null;

async function playVideo(cardEl) {
    // Close any existing player
    if (_activeVideoPlayer) {
        if (_activeVideoPlayer.plyr) _activeVideoPlayer.plyr.destroy();
        _activeVideoPlayer.container.style.display = 'none';
        _activeVideoPlayer.container.innerHTML = '';
        _activeVideoPlayer = null;
    }
    const url = cardEl.dataset.url;
    const playerDiv = cardEl.nextElementSibling;
    if (!playerDiv || !playerDiv.classList.contains('video-player-inline')) return;
    playerDiv.style.display = 'block';
    playerDiv.innerHTML = '<div class="spinner" style="padding:20px;text-align:center"></div>';

    const platform = _detectVideoPlatform(url);
    const videoId = _extractVideoId(url);

    if ((platform === 'youtube' || platform === 'vimeo') && videoId) {
        // Plyr embed for YouTube/Vimeo
        const wrapper = document.createElement('div');
        const closeBtn = document.createElement('button');
        closeBtn.className = 'video-player-close';
        closeBtn.innerHTML = '<i class="fas fa-times"></i>';
        closeBtn.onclick = function() { closeVideoPlayer(this); };

        if (platform === 'youtube') {
            wrapper.innerHTML = '<div id="plyr-yt-' + videoId + '" data-plyr-provider="youtube"'
                + ' data-plyr-embed-id="' + videoId + '"></div>';
        } else {
            wrapper.innerHTML = '<div id="plyr-vm-' + videoId + '" data-plyr-provider="vimeo"'
                + ' data-plyr-embed-id="' + videoId + '"></div>';
        }

        playerDiv.innerHTML = '';
        playerDiv.appendChild(closeBtn);
        playerDiv.appendChild(wrapper);

        if (typeof Plyr !== 'undefined') {
            const plyrEl = wrapper.querySelector('[data-plyr-provider]');
            const plyrInstance = new Plyr(plyrEl, {
                youtube: { noCookie: true, showRelated: false },
                controls: ['play-large', 'play', 'progress', 'current-time',
                           'mute', 'volume', 'captions', 'settings',
                           'pip', 'airplay', 'fullscreen']
            });
            _activeVideoPlayer = { plyr: plyrInstance, container: playerDiv };
        } else {
            // Plyr not loaded — iframe fallback
            const src = platform === 'youtube'
                ? 'https://www.youtube-nocookie.com/embed/' + videoId + '?autoplay=1'
                : 'https://player.vimeo.com/video/' + videoId + '?autoplay=1';
            wrapper.innerHTML = '<iframe width="100%" height="360" src="' + src
                + '" frameborder="0" allow="autoplay; encrypted-media; picture-in-picture"'
                + ' allowfullscreen></iframe>';
            _activeVideoPlayer = { plyr: null, container: playerDiv };
        }
    } else {
        // Other platform — use embed API fallback
        try {
            const res = await apiFetch('/api/media/video/embed', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({url: url})
            });
            const data = await res.json();
            if (data.success && data.html) {
                const closeBtn = document.createElement('button');
                closeBtn.className = 'video-player-close';
                closeBtn.innerHTML = '<i class="fas fa-times"></i>';
                closeBtn.onclick = function() { closeVideoPlayer(this); };
                playerDiv.innerHTML = data.html;
                playerDiv.insertBefore(closeBtn, playerDiv.firstChild);
                _activeVideoPlayer = { plyr: null, container: playerDiv };
            } else {
                playerDiv.innerHTML = '<div style="padding:10px;color:var(--text-dim)">Could not embed this video.</div>';
            }
        } catch(e) {
            playerDiv.innerHTML = '<div style="padding:10px;color:var(--text-dim)">Embed failed.</div>';
        }
    }
}

function closeVideoPlayer(closeBtn) {
    const playerDiv = closeBtn.closest('.video-player-inline');
    if (_activeVideoPlayer && _activeVideoPlayer.container === playerDiv) {
        if (_activeVideoPlayer.plyr) _activeVideoPlayer.plyr.destroy();
        _activeVideoPlayer = null;
    }
    playerDiv.style.display = 'none';
    playerDiv.innerHTML = '';
}

async function downloadVideo(btn, url) {
    const quality = document.getElementById('video-quality-select').value;
    const origText = btn.innerHTML;
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Downloading...';
    try {
        const res = await apiFetch('/api/media/video/download', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({url: url, quality: quality})
        });
        const data = await res.json();
        if (data.success) {
            btn.innerHTML = '<i class="fas fa-check"></i> ' + escapeHtml(data.size || 'Done');
            setTimeout(() => { btn.innerHTML = origText; btn.disabled = false; }, 3000);
        } else {
            btn.innerHTML = '<i class="fas fa-exclamation-triangle"></i> Failed';
            setTimeout(() => { btn.innerHTML = origText; btn.disabled = false; }, 3000);
        }
    } catch(e) {
        btn.innerHTML = '<i class="fas fa-exclamation-triangle"></i> Error';
        setTimeout(() => { btn.innerHTML = origText; btn.disabled = false; }, 3000);
    }
}

async function searchRadio() {
    const name = document.getElementById('radio-search-input').value.trim();
    const tag = document.getElementById('radio-genre-select').value;
    const params = new URLSearchParams();
    if (name) params.set('name', name);
    if (tag) params.set('tag', tag);
    params.set('limit', '30');

    const grid = document.getElementById('radio-results');
    grid.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)"><div class="spinner"></div></div>';

    try {
        const res = await apiFetch('/api/media/radio/search?' + params);
        const data = await res.json();
        renderStationGrid(data.stations || [], grid);
    } catch (e) {
        grid.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)">Failed to search radio stations.</div>';
    }
}

async function loadRadioPopular() {
    const grid = document.getElementById('radio-results');
    grid.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)"><div class="spinner"></div></div>';

    try {
        const res = await apiFetch('/api/media/radio/popular?limit=30');
        const data = await res.json();
        renderStationGrid(data.stations || [], grid);
    } catch (e) {
        grid.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)">Failed to load popular stations.</div>';
    }
}

async function loadRadioGenres() {
    if (_mediaGenresLoaded) return;
    try {
        const res = await apiFetch('/api/media/radio/genres?limit=60');
        const data = await res.json();
        const sel = document.getElementById('radio-genre-select');
        (data.genres || []).forEach(g => {
            const opt = document.createElement('option');
            opt.value = g.name;
            opt.textContent = g.name + ' (' + g.stationcount + ')';
            sel.appendChild(opt);
        });
        _mediaGenresLoaded = true;
    } catch (e) { /* ignore */ }
}

function renderStationGrid(stations, container) {
    if (!stations.length) {
        container.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)">No stations found.</div>';
        return;
    }
    container.innerHTML = stations.map(s => {
        const tags = (s.tags || []).slice(0, 2).join(', ');
        const meta = [s.country, tags, s.bitrate ? s.bitrate + 'kbps' : ''].filter(Boolean).join(' · ');
        const url = s.stream_url || '';
        const playing = mediaPlayer.current && (mediaPlayer.current.stream_url === url) ? ' playing' : '';
        const artHtml = s.favicon
            ? '<img src="' + s.favicon.replace(/"/g, '&quot;') + '" onerror="this.parentElement.innerHTML=\'<i class=\\\'fas fa-broadcast-tower\\\'></i>\'" />'
            : '<i class="fas fa-broadcast-tower"></i>';
        return '<div class="media-card' + playing + '" data-url="' + url.replace(/"/g, '&quot;') + '">'
            + '<div class="media-card-art">' + artHtml + '</div>'
            + '<div class="media-card-info"><h4>' + (s.name || 'Unknown').replace(/</g, '&lt;') + '</h4><p>' + meta.replace(/</g, '&lt;') + '</p></div>'
            + '<div class="media-card-actions">'
            + '<button class="play-btn" onclick="mediaPlayer.play(' + JSON.stringify(s).replace(/"/g, '&quot;') + ')" title="Play"><i class="fas fa-play"></i></button>'
            + '<button onclick="toggleFavorite(' + JSON.stringify({name: s.name, stream_url: url, favicon: s.favicon, type: 'radio', country: s.country, tags: s.tags}).replace(/"/g, '&quot;') + ', this)" title="Favorite"><i class="fas fa-heart"></i></button>'
            + '</div></div>';
    }).join('');
}

async function searchPodcasts() {
    const term = document.getElementById('podcast-search-input').value.trim();
    if (!term) return;

    const grid = document.getElementById('podcast-results');
    const epDiv = document.getElementById('podcast-episodes');
    grid.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)"><div class="spinner"></div></div>';
    epDiv.innerHTML = '';

    try {
        const res = await apiFetch('/api/media/podcasts/search?term=' + encodeURIComponent(term) + '&limit=25');
        const data = await res.json();
        renderPodcastGrid(data.podcasts || [], grid);
    } catch (e) {
        grid.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)">Failed to search podcasts.</div>';
    }
}

function renderPodcastGrid(podcasts, container) {
    if (!podcasts.length) {
        container.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)">No podcasts found.</div>';
        return;
    }
    container.innerHTML = podcasts.map(p => {
        const meta = [p.artist, p.primary_genre].filter(Boolean).join(' · ');
        const artHtml = p.artwork
            ? '<img src="' + p.artwork.replace(/"/g, '&quot;') + '" onerror="this.parentElement.innerHTML=\'<i class=\\\'fas fa-podcast\\\'></i>\'" />'
            : '<i class="fas fa-podcast"></i>';
        return '<div class="media-card" style="cursor:pointer" onclick="loadEpisodes(\'' + (p.feed_url || '').replace(/'/g, "\\'") + '\', this)">'
            + '<div class="media-card-art">' + artHtml + '</div>'
            + '<div class="media-card-info"><h4>' + (p.name || 'Unknown').replace(/</g, '&lt;') + '</h4><p>' + meta.replace(/</g, '&lt;') + '</p></div>'
            + '<div class="media-card-actions">'
            + '<button onclick="event.stopPropagation(); toggleFavorite(' + JSON.stringify({name: p.name, feed_url: p.feed_url, artwork: p.artwork, type: 'podcast', artist: p.artist}).replace(/"/g, '&quot;') + ', this)" title="Favorite"><i class="fas fa-heart"></i></button>'
            + '</div></div>';
    }).join('');
}

async function loadEpisodes(feedUrl, cardEl) {
    if (!feedUrl) return;
    const epDiv = document.getElementById('podcast-episodes');
    epDiv.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)"><div class="spinner"></div> Loading episodes...</div>';

    try {
        const res = await apiFetch('/api/media/podcasts/episodes?feed_url=' + encodeURIComponent(feedUrl) + '&limit=20');
        const data = await res.json();
        const episodes = data.episodes || [];
        if (!episodes.length) {
            epDiv.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)">No episodes found.</div>';
            return;
        }
        epDiv.innerHTML = '<div class="media-section-header">Episodes</div>' + episodes.map(ep => {
            const epItem = {title: ep.title, audio_url: ep.audio_url, duration: ep.duration, image: ep.image, name: ep.title};
            return '<div class="episode-item">'
                + '<button class="ep-play" onclick="mediaPlayer.play(' + JSON.stringify(epItem).replace(/"/g, '&quot;') + ')" title="Play"><i class="fas fa-play"></i></button>'
                + '<span class="ep-title">' + (ep.title || '').replace(/</g, '&lt;') + '</span>'
                + '<span class="ep-meta">' + [ep.duration, (ep.published || '').substring(0, 16)].filter(Boolean).join(' · ') + '</span>'
                + '</div>';
        }).join('');
    } catch (e) {
        epDiv.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)">Failed to load episodes.</div>';
    }
}

async function loadFavorites() {
    const container = document.getElementById('favorites-content');
    container.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)"><div class="spinner"></div></div>';

    try {
        const res = await apiFetch('/api/media/favorites');
        const data = await res.json();
        const favs = data.favorites || [];
        if (!favs.length) {
            container.innerHTML = '<div style="padding:40px 20px;text-align:center;color:var(--text-dim)"><i class="fas fa-heart" style="font-size:2em;margin-bottom:12px;display:block;opacity:0.3"></i>No favorites yet. Play some stations or podcasts and hit the heart button!</div>';
            return;
        }
        const radio = favs.filter(f => f.type === 'radio');
        const pods = favs.filter(f => f.type === 'podcast');
        let html = '';
        if (radio.length) {
            html += '<div class="media-section-header">Radio Stations</div><div class="media-grid">';
            radio.forEach(s => {
                const artHtml = s.favicon ? '<img src="' + s.favicon.replace(/"/g, '&quot;') + '" onerror="this.parentElement.innerHTML=\'<i class=\\\'fas fa-broadcast-tower\\\'></i>\'" />' : '<i class="fas fa-broadcast-tower"></i>';
                html += '<div class="media-card" data-url="' + (s.stream_url || '').replace(/"/g, '&quot;') + '">'
                    + '<div class="media-card-art">' + artHtml + '</div>'
                    + '<div class="media-card-info"><h4>' + (s.name || '').replace(/</g, '&lt;') + '</h4><p>' + (s.country || '').replace(/</g, '&lt;') + '</p></div>'
                    + '<div class="media-card-actions">'
                    + '<button class="play-btn" onclick="mediaPlayer.play(' + JSON.stringify(s).replace(/"/g, '&quot;') + ')" title="Play"><i class="fas fa-play"></i></button>'
                    + '<button class="fav-active" onclick="removeFavorite(' + JSON.stringify(s).replace(/"/g, '&quot;') + ')" title="Remove"><i class="fas fa-heart"></i></button>'
                    + '</div></div>';
            });
            html += '</div>';
        }
        if (pods.length) {
            html += '<div class="media-section-header">Podcasts</div><div class="media-grid">';
            pods.forEach(p => {
                const artHtml = p.artwork ? '<img src="' + p.artwork.replace(/"/g, '&quot;') + '" onerror="this.parentElement.innerHTML=\'<i class=\\\'fas fa-podcast\\\'></i>\'" />' : '<i class="fas fa-podcast"></i>';
                html += '<div class="media-card" style="cursor:pointer" onclick="loadEpisodes(\'' + (p.feed_url || '').replace(/'/g, "\\'") + '\', this); switchMediaTab(\'podcasts\'); document.querySelectorAll(\'.media-tab\')[1].click();">'
                    + '<div class="media-card-art">' + artHtml + '</div>'
                    + '<div class="media-card-info"><h4>' + (p.name || '').replace(/</g, '&lt;') + '</h4><p>' + (p.artist || '').replace(/</g, '&lt;') + '</p></div>'
                    + '<div class="media-card-actions">'
                    + '<button class="fav-active" onclick="event.stopPropagation(); removeFavorite(' + JSON.stringify(p).replace(/"/g, '&quot;') + ')" title="Remove"><i class="fas fa-heart"></i></button>'
                    + '</div></div>';
            });
            html += '</div>';
        }
        container.innerHTML = html;
    } catch (e) {
        container.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)">Failed to load favorites.</div>';
    }
}

async function loadMediaHistory() {
    const container = document.getElementById('history-content');
    container.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)"><div class="spinner"></div></div>';

    try {
        const res = await apiFetch('/api/media/history');
        const data = await res.json();
        const items = data.history || [];
        if (!items.length) {
            container.innerHTML = '<div style="padding:40px 20px;text-align:center;color:var(--text-dim)"><i class="fas fa-clock" style="font-size:2em;margin-bottom:12px;display:block;opacity:0.3"></i>No play history yet.</div>';
            return;
        }
        container.innerHTML = items.map(h => {
            const icon = h.type === 'radio' ? 'fa-broadcast-tower' : 'fa-podcast';
            const time = h.played_at ? formatDate(h.played_at) : '';
            return '<div class="episode-item">'
                + '<button class="ep-play" onclick="mediaPlayer.play(' + JSON.stringify(h).replace(/"/g, '&quot;') + ')" title="Play"><i class="fas fa-play"></i></button>'
                + '<i class="fas ' + icon + '" style="color:var(--text-dim);font-size:0.8rem"></i>'
                + '<span class="ep-title">' + (h.name || '').replace(/</g, '&lt;') + '</span>'
                + '<span class="ep-meta">' + time + '</span>'
                + '</div>';
        }).join('');
    } catch (e) {
        container.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-dim)">Failed to load history.</div>';
    }
}

async function toggleFavorite(item, btn) {
    try {
        const res = await apiFetch('/api/media/favorites/add', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(item)
        });
        const data = await res.json();
        if (data.success) {
            btn.classList.add('fav-active');
        } else {
            // Already exists — remove it
            await apiFetch('/api/media/favorites/remove', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify(item)
            });
            btn.classList.remove('fav-active');
        }
    } catch (e) { /* ignore */ }
}

async function removeFavorite(item) {
    try {
        await apiFetch('/api/media/favorites/remove', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(item)
        });
        loadFavorites();
    } catch (e) { /* ignore */ }
}

// ── Gallery Vault Functions ───────────────────────
let _galleryInitialized = false;
let _galleryData = [];
let _galleryUploadPath = '';

async function loadGallery() {
    if (!_galleryInitialized) {
        _galleryInitialized = true;
        setupDropZone();
    }
    await loadVault();
}

function switchGalleryTab(tab) {
    document.querySelectorAll('.gallery-tab').forEach(t => t.classList.remove('active'));
    document.querySelectorAll('.gallery-tab-content').forEach(c => c.style.display = 'none');
    event.currentTarget.classList.add('active');
    document.getElementById('gallery-' + tab).style.display = '';

    if (tab === 'vault') loadVault();
    if (tab === 'verify') loadVerifyDropdown();
}

async function loadVault() {
    const grid = document.getElementById('gallery-vault-grid');
    const detail = document.getElementById('gallery-vault-detail');
    detail.style.display = 'none';
    grid.style.display = '';

    try {
        const resp = await apiFetch('/api/gallery');
        const data = await resp.json();
        _galleryData = data.artworks || [];
        renderArtworkGrid(_galleryData);
    } catch (e) {
        grid.innerHTML = '<div class="gallery-empty"><i class="fas fa-images"></i><div>Could not load gallery</div></div>';
    }
}

function renderArtworkGrid(artworks) {
    const grid = document.getElementById('gallery-vault-grid');
    if (!artworks.length) {
        grid.innerHTML = '<div class="gallery-empty"><i class="fas fa-images"></i><div>No artwork registered yet</div><div style="font-size:0.8rem;margin-top:8px">Switch to the Register tab to add your first piece</div></div>';
        return;
    }
    grid.innerHTML = artworks.map(a => {
        const badgeClass = a.block_hash ? 'verified' : 'unverified';
        const badgeText = a.block_hash ? '&#10003; Chain' : '&#9888; Pending';
        const wmIcons = (a.watermark_types || []).map(t => {
            const icons = {visible: 'fa-eye', invisible: 'fa-eye-slash', certificate: 'fa-certificate'};
            return '<div class="wm-type-icon" title="' + t + '"><i class="fas ' + (icons[t] || 'fa-check') + '"></i></div>';
        }).join('');
        return '<div class="gallery-card" onclick="showArtworkDetail(\'' + a.artwork_id + '\')">'
            + '<img class="gallery-card-img" src="/api/gallery/thumbnail/' + a.artwork_id + '?api_key=' + encodeURIComponent(_apiKey) + '" alt="' + (a.title || '').replace(/"/g, '&quot;') + '" onerror="this.style.background=\'var(--bg-dark)\';this.alt=\'No preview\'">'
            + '<div class="gallery-card-badge">' + wmIcons + '<div class="chain-badge ' + badgeClass + '">' + badgeText + '</div></div>'
            + '<div class="gallery-card-overlay"><div class="title">' + (a.title || 'Untitled').replace(/</g, '&lt;') + '</div><div class="artist">' + (a.artist || '').replace(/</g, '&lt;') + '</div></div>'
            + '</div>';
    }).join('');
}

async function showArtworkDetail(id) {
    const grid = document.getElementById('gallery-vault-grid');
    const detail = document.getElementById('gallery-vault-detail');
    grid.style.display = 'none';
    detail.style.display = '';

    try {
        const resp = await apiFetch('/api/gallery/' + id);
        const a = await resp.json();
        const badgeClass = a.block_hash ? 'verified' : 'unverified';
        const badgeText = a.block_hash ? '&#10003; Verified' : '&#9888; Not notarized';

        detail.innerHTML = '<div style="margin-bottom:12px"><button class="btn btn-secondary" onclick="loadVault()"><i class="fas fa-arrow-left"></i> Back to Vault</button></div>'
            + '<div class="gallery-detail-header">'
            + '<img class="gallery-detail-img" src="/api/gallery/image/' + id + '?type=watermarked&api_key=' + encodeURIComponent(_apiKey) + '" alt="' + (a.title || '').replace(/"/g, '&quot;') + '">'
            + '<div class="gallery-detail-meta">'
            + '<h3>' + (a.title || 'Untitled').replace(/</g, '&lt;') + '</h3>'
            + '<div class="meta-row"><strong>Artist:</strong> ' + (a.artist || 'Unknown').replace(/</g, '&lt;') + '</div>'
            + '<div class="meta-row"><strong>Registered:</strong> ' + (a.registered_at || 'N/A').replace(/</g, '&lt;') + '</div>'
            + '<div class="meta-row"><strong>Medium:</strong> ' + (a.medium || 'N/A').replace(/</g, '&lt;') + '</div>'
            + '<div class="meta-row"><strong>Dimensions:</strong> ' + (a.dimensions || 'N/A').replace(/</g, '&lt;') + '</div>'
            + '<div class="meta-row"><strong>License:</strong> ' + (a.license || 'All Rights Reserved').replace(/</g, '&lt;') + '</div>'
            + '<div class="meta-row"><strong>Tags:</strong> ' + (a.tags || []).join(', ') + '</div>'
            + '<div class="meta-row"><strong>Watermarks:</strong> ' + (a.watermark_types || []).join(', ') + '</div>'
            + '<div class="meta-row"><strong>Chain:</strong> <span class="chain-badge ' + badgeClass + '">' + badgeText + '</span></div>'
            + (a.block_hash ? '<div class="meta-row"><strong>Block Hash:</strong> <span style="font-family:monospace;font-size:0.75rem;word-break:break-all">' + a.block_hash + '</span></div>' : '')
            + '<div class="meta-row"><strong>Original Hash:</strong> <span style="font-family:monospace;font-size:0.75rem;word-break:break-all">' + (a.original_hash || '') + '</span></div>'
            + '<div style="margin-top:12px; display:flex; gap:8px; flex-wrap:wrap">'
            + (a.certificate_path ? '<button class="btn btn-secondary" onclick="downloadCertificate(\'' + id + '\')"><i class="fas fa-file-alt"></i> Download Certificate</button>' : '')
            + '<button class="btn btn-secondary" onclick="verifyFromDetail(\'' + id + '\')"><i class="fas fa-shield-alt"></i> Verify</button>'
            + '</div>'
            + '</div></div>'
            + (a.description ? '<div style="padding:12px 0; color:var(--text-dim); font-size:0.9rem">' + a.description.replace(/</g, '&lt;') + '</div>' : '');
    } catch (e) {
        detail.innerHTML = '<div class="gallery-empty"><i class="fas fa-exclamation-triangle"></i><div>Failed to load artwork details</div></div>';
    }
}

function setupDropZone() {
    const zone = document.getElementById('gallery-upload-zone');
    if (!zone) return;
    zone.addEventListener('dragover', function(e) { e.preventDefault(); zone.classList.add('dragover'); });
    zone.addEventListener('dragleave', function() { zone.classList.remove('dragover'); });
    zone.addEventListener('drop', function(e) {
        e.preventDefault();
        zone.classList.remove('dragover');
        if (e.dataTransfer.files.length) {
            document.getElementById('gallery-file-input').files = e.dataTransfer.files;
            handleGalleryFile(document.getElementById('gallery-file-input'));
        }
    });
}

async function handleGalleryFile(input) {
    if (!input.files || !input.files[0]) return;
    const file = input.files[0];
    const formData = new FormData();
    formData.append('file', file);

    try {
        const resp = await apiFetch('/api/gallery/upload', { method: 'POST', body: formData });
        const data = await resp.json();
        if (data.success) {
            _galleryUploadPath = data.path;
            document.getElementById('gallery-upload-preview').style.display = '';
            document.getElementById('gallery-preview-img').src = '/api/gallery/thumbnail/' + data.temp_id + '?api_key=' + encodeURIComponent(_apiKey);
            document.getElementById('gallery-preview-name').textContent = file.name;
            document.getElementById('gallery-register-form').style.display = '';
            document.getElementById('gallery-register-result').style.display = 'none';
        }
    } catch (e) {
        console.error('Upload failed', e);
    }
}

async function registerArtwork() {
    if (!_galleryUploadPath) return;
    const btn = document.getElementById('gallery-register-btn');
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Registering...';

    const wmTypes = [];
    if (document.getElementById('gallery-wm-visible').checked) wmTypes.push('visible');
    if (document.getElementById('gallery-wm-invisible').checked) wmTypes.push('invisible');
    if (document.getElementById('gallery-wm-certificate').checked) wmTypes.push('certificate');

    const tags = document.getElementById('gallery-reg-tags').value.split(',').map(t => t.trim()).filter(Boolean);

    const payload = {
        image_path: _galleryUploadPath,
        title: document.getElementById('gallery-reg-title').value || 'Untitled',
        artist: document.getElementById('gallery-reg-artist').value || 'Unknown',
        description: document.getElementById('gallery-reg-description').value,
        medium: document.getElementById('gallery-reg-medium').value,
        dimensions: document.getElementById('gallery-reg-dimensions').value,
        license: document.getElementById('gallery-reg-license').value,
        tags: tags,
        watermark_types: wmTypes,
    };

    try {
        const resp = await apiFetch('/api/gallery/register', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(payload)
        });
        const data = await resp.json();
        const result = document.getElementById('gallery-register-result');
        result.style.display = '';
        if (data.success) {
            result.innerHTML = '<div style="background:var(--bg-input); border:1px solid var(--success); border-radius:8px; padding:16px;">'
                + '<div style="color:var(--success); font-weight:600; margin-bottom:8px"><i class="fas fa-check-circle"></i> Artwork Registered!</div>'
                + '<div style="font-size:0.85rem; color:var(--text-dim)">'
                + '<div>ID: <code>' + data.artwork_id + '</code></div>'
                + '<div>Watermarks: ' + (data.watermark_types || []).join(', ') + '</div>'
                + (data.block_hash ? '<div>Chain Block: <code style="font-size:0.75rem">' + data.block_hash.substring(0, 32) + '...</code></div>' : '<div style="color:var(--warning)">Chain not initialized — notarization pending</div>')
                + '</div></div>';
            // Reset form
            _galleryUploadPath = '';
            document.getElementById('gallery-register-form').style.display = 'none';
            document.getElementById('gallery-upload-preview').style.display = 'none';
            document.getElementById('gallery-file-input').value = '';
        } else {
            result.innerHTML = '<div style="color:var(--error); padding:12px"><i class="fas fa-exclamation-triangle"></i> ' + escapeHtml(data.error || 'Registration failed') + '</div>';
        }
    } catch (e) {
        document.getElementById('gallery-register-result').style.display = '';
        document.getElementById('gallery-register-result').innerHTML = '<div style="color:var(--error); padding:12px">Registration failed: ' + escapeHtml(e.message) + '</div>';
    } finally {
        btn.disabled = false;
        btn.innerHTML = '<i class="fas fa-lock"></i> Register &amp; Notarize';
    }
}

async function loadVerifyDropdown() {
    const sel = document.getElementById('gallery-verify-select');
    try {
        const resp = await apiFetch('/api/gallery');
        const data = await resp.json();
        const artworks = data.artworks || [];
        sel.innerHTML = '<option value="">— Choose artwork to verify —</option>'
            + artworks.map(a => '<option value="' + a.artwork_id + '">' + (a.title || 'Untitled').replace(/</g, '&lt;') + ' — ' + (a.artist || '').replace(/</g, '&lt;') + '</option>').join('');
    } catch (e) { /* ignore */ }
}

async function verifyArtwork(artworkId) {
    if (!artworkId) return;
    const result = document.getElementById('gallery-verify-result');
    result.style.display = '';
    result.innerHTML = '<div style="text-align:center;padding:24px;color:var(--text-dim)"><i class="fas fa-spinner fa-spin"></i> Verifying...</div>';

    try {
        const resp = await apiFetch('/api/gallery/verify/' + artworkId);
        const v = await resp.json();

        const statusBadge = v.verified
            ? '<span class="chain-badge verified" style="font-size:0.9rem;padding:6px 16px">&#10003; VERIFIED</span>'
            : '<span class="chain-badge unverified" style="font-size:0.9rem;padding:6px 16px">&#9888; UNVERIFIED</span>';

        let blockHtml = '';
        if (v.block) {
            blockHtml = '<div class="gallery-verify-block">'
                + '<div class="vr-row"><strong>Block Hash:</strong> <span>' + (v.block.block_hash || 'N/A') + '</span></div>'
                + '<div class="vr-row"><strong>Prev Hash:</strong> <span>' + (v.block.prev_hash || 'N/A') + '</span></div>'
                + '<div class="vr-row"><strong>Timestamp:</strong> <span>' + (v.block.timestamp || 'N/A') + '</span></div>'
                + '<div class="vr-row"><strong>Block Type:</strong> <span>' + (v.block.block_type || 'N/A') + '</span></div>'
                + '<div class="vr-row"><strong>Index:</strong> <span>' + (v.block.index !== undefined ? v.block.index : 'N/A') + '</span></div>'
                + '</div>';
        }

        result.innerHTML = '<div style="text-align:center; margin-bottom:16px">' + statusBadge + '</div>'
            + '<div style="font-size:0.85rem; color:var(--text-dim); margin-bottom:12px">'
            + '<div><strong>Hash Match:</strong> ' + (v.hash_match ? '<span style="color:var(--success)">&#10003; Yes</span>' : '<span style="color:var(--error)">&#10007; No</span>') + '</div>'
            + '<div><strong>Chain Valid:</strong> ' + (v.chain_valid ? '<span style="color:var(--success)">&#10003; Yes</span>' : '<span style="color:var(--warning)">&#9888; No</span>') + '</div>'
            + '<div style="margin-top:6px"><strong>Details:</strong> ' + (v.details || '').replace(/</g, '&lt;') + '</div>'
            + '</div>'
            + blockHtml;
    } catch (e) {
        result.innerHTML = '<div style="color:var(--error); text-align:center; padding:24px">Verification failed: ' + escapeHtml(e.message) + '</div>';
    }
}

async function verifyFromDetail(artworkId) {
    // Switch to verify tab and trigger verification
    document.querySelectorAll('.gallery-tab').forEach(t => t.classList.remove('active'));
    document.querySelectorAll('.gallery-tab-content').forEach(c => c.style.display = 'none');
    document.querySelectorAll('.gallery-tab')[2].classList.add('active');
    document.getElementById('gallery-verify').style.display = '';
    await loadVerifyDropdown();
    document.getElementById('gallery-verify-select').value = artworkId;
    verifyArtwork(artworkId);
}

function downloadCertificate(artworkId) {
    window.open('/api/gallery/certificate/' + artworkId + '?api_key=' + encodeURIComponent(_apiKey), '_blank');
}


