/**
 * Melon Lite - HTML5 Audio ???뚮젅?댁뼱 ?쒖뼱 JS (4李??ъ깮 ?湲곗뿴 諛??뺤옣 ?뚮젅?댁뼱 怨좊룄??踰꾩쟾)
 */

document.addEventListener('DOMContentLoaded', function() {
    if (window.__MELON_LITE_PLAYER_INITED) return;
    window.__MELON_LITE_PLAYER_INITED = true;
    const appPlayerSettings = Object.assign({
        defaultVolume: 0.8,
        resumeEnabled: true,
        autoNextEnabled: true,
        historyEnabled: true,
        countRule: 'start',
        defaultRepeat: 'none',
        defaultShuffle: false,
        mobileCompact: false,
        mediaSessionEnabled: true,
        keyboardShortcutsEnabled: true,
        lazyLoadingEnabled: true,
        isLoggedIn: false,
        guestPreviewSeconds: 30
    }, window.APP_PLAYER_SETTINGS || {});
    const countedSongIds = new Set();
    const guestPreviewMode = appPlayerSettings.isLoggedIn !== true;
    const guestPreviewSeconds = Math.max(5, Number(appPlayerSettings.guestPreviewSeconds || 30));
    const TEXT_FALLBACKS = {
        title: '제목 없음',
        artist: '알 수 없는 아티스트',
        album: '',
        emptyQueue: '재생 대기열이 비어 있습니다.',
        noCurrentTrack: '재생 중인 곡이 없습니다.',
        noLyrics: '등록된 가사가 없습니다.',
        loadLyricsError: '가사를 불러오지 못했습니다.'
    };

    function safeText(value, fallback = '') {
        if (value === null || value === undefined) return fallback;
        const text = String(value);
        if (!text || text === 'null' || text === 'undefined') return fallback;
        return text;
    }

    function setElementText(element, value, fallback = '') {
        if (element) element.textContent = safeText(value, fallback);
    }
    // ==========================================================================
    // 1. DOM Elements
    // ==========================================================================
    const audio = document.getElementById('audio-player');
    if (!audio) return;
    const btnPlayPause = document.getElementById('btn-play-pause');
    
    // 硫붿씤 ?섎떒 怨좎젙 ?뚮젅?댁뼱 而⑦듃濡?    const btnPlayPause = document.getElementById('btn-play-pause');
    const btnPrev = document.getElementById('btn-prev');
    const btnNext = document.getElementById('btn-next');
    const btnShuffle = document.getElementById('btn-shuffle');
    const btnRepeat = document.getElementById('btn-repeat');
    const btnQueue = document.getElementById('btn-queue');
    const btnExpandPlayer = document.getElementById('btn-expand-player');
    
    const playerTitle = document.getElementById('player-title');
    const playerArtist = document.getElementById('player-artist');
    const timeCurrent = document.getElementById('time-current');
    const timeTotal = document.getElementById('time-total');
    const progressWrapper = document.getElementById('progress-wrapper');
    const progressBar = document.getElementById('progress-bar');
    
    const btnMute = document.getElementById('btn-mute');
    const volumeWrapper = document.getElementById('volume-wrapper');
    const volumeBar = document.getElementById('volume-bar');
    
    const playerAlbumImage = document.getElementById('player-album-image');
    const brandIcon = document.querySelector('.brand-icon');
    const albumArt = document.querySelector('.player-album-art');

    // 紐⑤컮???쒕줈??    const mobileHamburger = document.getElementById('mobile-hamburger');
    const mobileHamburger = document.getElementById('mobile-hamburger');
    const appSidebar = document.getElementById('app-sidebar');
    const sidebarOverlay = document.getElementById('sidebar-overlay');

    // ?뚮젅?대━?ㅽ듃 異붽? ?앹뾽 紐⑤떖
    const playlistModal = document.getElementById('playlist-modal');
    const modalClose = document.getElementById('modal-close');
    const modalSongId = document.getElementById('modal-song-id');
    const modalOptions = document.getElementById('modal-playlist-options');

    // 4李??좉퇋: ?ъ깮 ?湲곗뿴(Queue) ?ъ씠???⑤꼸 DOM
    const queuePanel = document.getElementById('queue-panel');
    const queueClose = document.getElementById('queue-close');
    const btnClearQueue = document.getElementById('btn-clear-queue');
    const queueListContainer = document.getElementById('queue-list-container');
    const queueCount = document.getElementById('queue-count');

    // 4李??좉퇋: ?꾩껜 ?붾㈃ ?뺤옣 ?뚮젅?댁뼱 紐⑤떖 DOM
    const expandPlayerOverlay = document.getElementById('expand-player-overlay');
    const expandPlayerClose = document.getElementById('expand-player-close');
    const expandAlbumImage = document.getElementById('expand-album-image');
    const expandPlayerTitle = document.getElementById('expand-player-title');
    const expandPlayerArtist = document.getElementById('expand-player-artist');
    const expandPlayerAlbum = document.getElementById('expand-player-album');
    const miniLyricsLine = document.getElementById('mini-lyrics-line');
    
    // ?뺤옣 ?뚮젅?댁뼱 ???쒖뼱
    const tabBtnQueue = document.getElementById('tab-btn-queue');
    const tabBtnLyrics = document.getElementById('tab-btn-lyrics');
    const expandTabQueueContent = document.getElementById('expand-tab-queue-content');
    const expandTabLyricsContent = document.getElementById('expand-tab-lyrics-content');
    const expandQueueList = document.getElementById('expand-queue-list');
    const expandLyricsFullText = document.getElementById('expand-lyrics-full-text');
    const expandBtnLyricsToggle = document.getElementById('expand-btn-lyrics-toggle');

    // ?뺤옣 ?뚮젅?댁뼱 ?섎떒 而⑦듃濡ㅻ윭
    const expandProgressWrapper = document.getElementById('expand-progress-wrapper');
    const expandProgressBar = document.getElementById('expand-progress-bar');
    const expandTimeCurrent = document.getElementById('expand-time-current');
    const expandTimeTotal = document.getElementById('expand-time-total');
    
    const expandBtnShuffle = document.getElementById('expand-btn-shuffle');
    const expandBtnPrev = document.getElementById('expand-btn-prev');
    const expandBtnPlayPause = document.getElementById('expand-btn-play-pause');
    const expandBtnNext = document.getElementById('expand-btn-next');
    const expandBtnRepeat = document.getElementById('expand-btn-repeat');
    
    const expandBtnLike = document.getElementById('expand-btn-like');
    const expandBtnAddPlaylist = document.getElementById('expand-btn-add-playlist');
    const expandBtnSongDetail = document.getElementById('expand-btn-song-detail');

    // ==========================================================================
    // 2. State Variables & LocalStorage Integration
    // ==========================================================================
    let isPlaying = false; // ?ъ깮 ?щ? ?뚮옒洹?    
    let playerState = {
        queue: [],           // ?ъ깮 ?湲곗뿴 (媛?怨≪쓽 id, title, artist, duration, loved)
        originalQueue: [],   // ?뷀뵆 ?댁젣 ?鍮꾩슜 ?먮낯 ?ъ깮 ?쒖꽌 ?湲곗뿴
        currentIndex: -1,
        currentSongId: null,
        shuffle: appPlayerSettings.defaultShuffle === true,
        repeatMode: ['none', 'all', 'one'].includes(appPlayerSettings.defaultRepeat) ? appPlayerSettings.defaultRepeat : 'none',
        currentTime: 0,
        volume: Number.isFinite(appPlayerSettings.defaultVolume) ? appPlayerSettings.defaultVolume : 0.8,
        muted: false,
        queueContext: null,
        expanded: false,
        previewMode: guestPreviewMode,
        wasPlaying: false,
        userActivated: false,
        lastUpdated: 0
    };
    let pendingRestoreTime = null;
    let lastMediaPositionUpdate = 0;
    let previewPromptShownFor = null;
    const streamFailureCounts = new Map();

    function showPlayerNotice(message, type = 'info') {
        if (window.showToast && window.showToast !== showPlayerNotice) {
            window.showToast(message, type);
            return;
        }
        let toast = document.getElementById('melon-lite-toast');
        if (!toast) {
            toast = document.createElement('div');
            toast.id = 'melon-lite-toast';
            toast.className = 'melon-lite-toast';
            toast.setAttribute('role', 'status');
            toast.setAttribute('aria-live', 'polite');
            document.body.appendChild(toast);
        }
        toast.textContent = message;
        toast.dataset.type = type;
        toast.classList.add('show');
        window.clearTimeout(toast.__hideTimer);
        toast.__hideTimer = window.setTimeout(() => toast.classList.remove('show'), 3600);
    }
    window.showToast = window.showToast || showPlayerNotice;

    function showGuestPreviewPrompt() {
        if (!guestPreviewMode) return;
        if (document.getElementById('guest-preview-prompt')) return;
        const track = currentTrack();
        const trackId = track ? String(track.id) : 'unknown';
        if (previewPromptShownFor === trackId) return;
        previewPromptShownFor = trackId;
        document.body.classList.add('guest-preview-ended');
        document.dispatchEvent(new CustomEvent('melonlite:guest-preview-ended', { detail: { trackId } }));
        const box = document.createElement('div');
        box.id = 'guest-preview-prompt';
        box.className = 'guest-preview-prompt preview-premium-modal';
        box.setAttribute('role', 'dialog');
        box.setAttribute('aria-modal', 'true');
        box.setAttribute('aria-live', 'polite');
        box.setAttribute('aria-labelledby', 'guest-preview-title');
        box.tabIndex = -1;

        const basePath = window.APP_BASE_PATH || './';
        const currentPath = `${window.location.pathname.replace(/^\/+/, '')}${window.location.search || ''}`;
        const returnPath = currentPath.replace(/^music\//, '') || 'index.php';
        const loginUrl = `${basePath}login.php?return=${encodeURIComponent(returnPath)}`;
        const coverUrl = track ? `${basePath}cover.php?id=${encodeURIComponent(track.id)}` : `${basePath}assets/img/default-cover.svg`;

        const media = document.createElement('div');
        media.className = 'guest-preview-media';
        const art = document.createElement('img');
        art.src = coverUrl;
        art.alt = '';
        art.loading = 'lazy';
        art.width = 56;
        art.height = 56;
        art.onerror = function () {
            this.onerror = null;
            this.src = `${basePath}assets/img/default-cover.svg`;
        };
        media.appendChild(art);

        const copy = document.createElement('div');
        copy.className = 'guest-preview-copy';
        const badge = document.createElement('span');
        badge.className = 'guest-preview-badge';
        badge.textContent = `${guestPreviewSeconds}초 미리듣기 완료`;
        const title = document.createElement('strong');
        title.id = 'guest-preview-title';
        title.textContent = '미리듣기가 종료되었습니다';
        const desc = document.createElement('span');
        desc.textContent = '로그인하면 전체 곡을 계속 감상할 수 있어요.';
        const now = document.createElement('em');
        now.className = 'guest-preview-track';
        now.textContent = track ? `${safeText(track.title, TEXT_FALLBACKS.title)} · ${safeText(track.artist, TEXT_FALLBACKS.artist)}` : '현재는 방문자 미리듣기 모드입니다.';
        copy.append(badge, title, desc, now);

        const actions = document.createElement('div');
        actions.className = 'guest-preview-actions';
        const login = document.createElement('a');
        login.className = 'btn btn-primary btn-sm guest-preview-login';
        login.href = loginUrl;
        login.textContent = '로그인하기';
        login.addEventListener('click', saveStateToStorage);
        const close = document.createElement('button');
        close.type = 'button';
        close.className = 'btn btn-secondary btn-sm';
        close.id = 'guest-preview-close';
        close.textContent = '계속 둘러보기';
        const dismiss = document.createElement('button');
        dismiss.type = 'button';
        dismiss.className = 'guest-preview-dismiss';
        dismiss.setAttribute('aria-label', '닫기');
        dismiss.innerHTML = '<i class="fas fa-times"></i>';
        actions.append(login, close);

        const card = document.createElement('div');
        card.className = 'guest-preview-card';
        card.append(dismiss, media, copy, actions);
        box.appendChild(card);
        document.body.appendChild(box);
        const closePrompt = function () {
            box.remove();
            document.body.classList.remove('guest-preview-ended');
        };
        close.addEventListener('click', closePrompt, { once: true });
        dismiss.addEventListener('click', closePrompt, { once: true });
        box.addEventListener('click', function (event) {
            if (event.target === box) closePrompt();
        });
        box.addEventListener('keydown', function (event) {
            if (event.key === 'Escape') closePrompt();
        });
        window.setTimeout(() => box.classList.add('show'), 20);
        login.focus({ preventScroll: true });
    }

    function updatePreviewBadge() {
        document.body.classList.toggle('guest-preview-mode', guestPreviewMode);
        let badge = document.getElementById('player-preview-badge');
        if (!guestPreviewMode) {
            if (badge) badge.remove();
            return;
        }
        if (!badge && playerArtist && playerArtist.parentElement) {
            badge = document.createElement('span');
            badge.id = 'player-preview-badge';
            badge.className = 'player-preview-badge';
            badge.textContent = `${guestPreviewSeconds}초 미리듣기`;
            playerArtist.parentElement.appendChild(badge);
        }
    }

    function closeExpandPlayer() {
        if (!expandPlayerOverlay) return;
        expandPlayerOverlay.style.display = 'none';
        document.body.classList.remove('expand-player-open');
        saveStateToStorage();
    }

    function describePlayError(error) {
        const name = error && error.name ? error.name : '';
        if (name === 'NotAllowedError') return '브라우저 정책 때문에 자동 재생이 막혔습니다. 재생 버튼을 눌러 이어듣기 하세요.';
        if (name === 'AbortError') return '재생 요청이 취소되었습니다. 다시 시도해 주세요.';
        if (name === 'NotSupportedError') return '이 브라우저에서 지원하지 않는 오디오 형식입니다.';
        return '재생을 시작하지 못했습니다. 네트워크나 파일 상태를 확인해 주세요.';
    }

    function requestPlay(options = {}) {
        const track = currentTrack();
        const promise = audio.play();
        if (!promise || typeof promise.then !== 'function') return Promise.resolve();
        return promise.then(() => {
            isPlaying = true;
            if (track) streamFailureCounts.delete(String(track.id));
            updatePlayButtonUI(true);
            updateMediaSessionPlaybackState();
            if (track) synchronizeActiveListUI(track.id);
            renderQueueUI();
            saveStateToStorage();
        }).catch(error => {
            const message = describePlayError(error);
            console.warn('Audio play failed:', error);
            isPlaying = false;
            playerState.wasPlaying = options.keepResume !== false;
            updatePlayButtonUI(false);
            if (btnPlayPause) {
                btnPlayPause.classList.add('resume-ready');
                btnPlayPause.title = '재생 버튼을 눌러 이어듣기';
            }
            updateMediaSessionPlaybackState();
            saveStateToStorage();
            showPlayerNotice(message, error && error.name === 'NotAllowedError' ? 'info' : 'error');
            if (options.autoNextOnFailure && error && error.name !== 'NotAllowedError' && error.name !== 'AbortError') {
                handleAudioStreamFailure(error);
            }
            return Promise.reject(error);
        });
    }

    function applyPendingRestoreTime() {
        if (pendingRestoreTime === null) return;
        const restoreTime = Math.max(0, parseFloat(pendingRestoreTime) || 0);
        pendingRestoreTime = null;
        if (!Number.isFinite(restoreTime) || restoreTime <= 0) return;
        try {
            const max = Number.isFinite(audio.duration) && audio.duration > 0 ? Math.max(0, audio.duration - 1) : restoreTime;
            audio.currentTime = Math.min(restoreTime, max);
            playerState.currentTime = audio.currentTime;
            if (timeCurrent) timeCurrent.textContent = formatTime(audio.currentTime);
            if (expandTimeCurrent) expandTimeCurrent.textContent = formatTime(audio.currentTime);
        } catch (err) {
            console.warn('Deferred seek restore failed:', err);
        }
    }

    function handleAudioStreamFailure(error) {
        const track = currentTrack();
        const trackId = track ? String(track.id) : 'unknown';
        const count = (streamFailureCounts.get(trackId) || 0) + 1;
        streamFailureCounts.set(trackId, count);
        isPlaying = false;
        updatePlayButtonUI(false);
        updateMediaSessionPlaybackState();
        showPlayerNotice('재생 중 문제가 발생했습니다. 다음 곡으로 넘어가거나 다시 시도해 주세요.', 'error');
        if (playerState.queue.length > 1 && count <= 2 && appPlayerSettings.autoNextEnabled) {
            window.setTimeout(() => playNext(), 700);
        }
        saveStateToStorage();
    }

    function normalizeTrack(track) {
        if (!track || !track.id) return null;
        return {
            id: String(track.id),
            title: safeText(track.title, TEXT_FALLBACKS.title),
            artist: safeText(track.artist, TEXT_FALLBACKS.artist),
            album: safeText(track.album, TEXT_FALLBACKS.album),
            duration: Math.max(0, parseInt(track.duration, 10) || 0),
            liked: track.liked === true || track.liked === '1'
        };
    }

    function sanitizeQueue(queue) {
        if (!Array.isArray(queue)) return [];
        const seen = new Set();
        return queue.map(normalizeTrack).filter(track => {
            if (!track || seen.has(track.id)) return false;
            seen.add(track.id);
            return true;
        });
    }

    // 濡쒖뺄 ?ㅽ넗由ъ??먯꽌 ?곹깭媛?蹂듭썝 ?쒕룄
    function loadStateFromStorage() {
        if (!appPlayerSettings.resumeEnabled) {
            try {
                localStorage.removeItem('melon_lite_state');
            } catch (err) {}
            return;
        }
        try {
            const savedState = localStorage.getItem('melon_lite_state');
            if (savedState) {
                const parsed = JSON.parse(savedState);
                const lastUpdated = parseInt(parsed.lastUpdated, 10) || 0;
                if (lastUpdated > 0 && Date.now() - lastUpdated > 1000 * 60 * 60 * 24 * 14) {
                    localStorage.removeItem('melon_lite_state');
                    return;
                }
                const queue = sanitizeQueue(parsed.queue || []);
                const originalQueue = sanitizeQueue(parsed.originalQueue || parsed.queue || []);
                let currentIndex = Number.parseInt(parsed.currentIndex, 10);
                if (!Number.isFinite(currentIndex)) currentIndex = -1;
                const currentSongId = parsed.currentSongId ? String(parsed.currentSongId) : null;
                if (currentSongId) {
                    const foundIndex = queue.findIndex(track => track.id === currentSongId);
                    currentIndex = foundIndex >= 0 ? foundIndex : -1;
                }
                if (currentIndex < -1 || currentIndex >= queue.length) currentIndex = -1;
                playerState.queue = queue;
                playerState.originalQueue = originalQueue.length ? originalQueue : queue;
                playerState.currentIndex = currentIndex;
                playerState.currentSongId = currentIndex >= 0 && queue[currentIndex] ? queue[currentIndex].id : null;
                playerState.shuffle = parsed.shuffle === true;
                playerState.repeatMode = ['none', 'all', 'one'].includes(parsed.repeatMode) ? parsed.repeatMode : 'none';
                playerState.currentTime = Math.max(0, parseFloat(parsed.currentTime) || 0);
                const savedVolume = parseFloat(parsed.volume);
                playerState.volume = Number.isFinite(savedVolume) ? Math.min(1, Math.max(0, savedVolume)) : playerState.volume;
                playerState.muted = parsed.muted === true;
                playerState.queueContext = parsed.queueContext || null;
                playerState.expanded = parsed.expanded === true;
                playerState.wasPlaying = parsed.wasPlaying === true;
                playerState.userActivated = parsed.userActivated === true;
                playerState.lastUpdated = lastUpdated;
                
                console.log("LocalStorage ?ъ깮 ?곹깭 蹂듭썝 ?꾨즺:", playerState);
            }
        } catch (err) {
            console.warn("LocalStorage ?곹깭 ?뚯떛 ?ㅻ쪟 (湲곕낯媛??ㅼ젙):", err);
            try { localStorage.removeItem('melon_lite_state'); } catch (storageErr) {}
        }
    }

    // ?곹깭媛믪쓣 濡쒖뺄 ?ㅽ넗由ъ????몄씠釉?    function saveStateToStorage() {
    function saveStateToStorage() {
        try {
            if (audio && Number.isFinite(audio.currentTime)) {
                playerState.currentTime = audio.currentTime;
            }
            playerState.wasPlaying = isPlaying || !audio.paused;
            playerState.muted = audio.muted === true;
            playerState.lastUpdated = Date.now();
            const track = currentTrack();
            localStorage.setItem('melon_lite_state', JSON.stringify({
                queue: playerState.queue,
                originalQueue: playerState.originalQueue,
                currentIndex: playerState.currentIndex,
                currentSongId: playerState.currentSongId,
                currentTitle: track ? safeText(track.title, TEXT_FALLBACKS.title) : '',
                currentArtist: track ? safeText(track.artist, TEXT_FALLBACKS.artist) : '',
                currentAlbum: track ? safeText(track.album, '') : '',
                shuffle: playerState.shuffle,
                repeatMode: playerState.repeatMode,
                currentTime: playerState.currentTime,
                volume: playerState.volume,
                muted: playerState.muted,
                queueContext: playerState.queueContext,
                expanded: expandPlayerOverlay && expandPlayerOverlay.style.display === 'flex',
                wasPlaying: playerState.wasPlaying,
                userActivated: playerState.userActivated,
                previewMode: guestPreviewMode,
                lastUpdated: playerState.lastUpdated
            }));
        } catch (err) {
            console.error("LocalStorage ?곹깭 ????먮윭:", err);
        }
    }

    function currentTrack() {
        if (playerState.currentIndex < 0 || playerState.currentIndex >= playerState.queue.length) return null;
        return playerState.queue[playerState.currentIndex] || null;
    }

    function updateMediaSessionMetadata(track) {
        if (!appPlayerSettings.mediaSessionEnabled || !('mediaSession' in navigator) || !window.MediaMetadata || !track) return;
        const coverUrl = `${window.APP_BASE_PATH}cover.php?id=${encodeURIComponent(track.id)}`;
        try {
            navigator.mediaSession.metadata = new MediaMetadata({
                title: safeText(track.title, TEXT_FALLBACKS.title),
                artist: safeText(track.artist, TEXT_FALLBACKS.artist),
                album: safeText(track.album, ''),
                artwork: [
                    { src: coverUrl, sizes: '96x96', type: 'image/png' },
                    { src: coverUrl, sizes: '192x192', type: 'image/png' },
                    { src: coverUrl, sizes: '512x512', type: 'image/png' }
                ]
            });
        } catch (err) {
            console.warn('Media Session metadata skipped:', err);
        }
    }

    function updateMediaSessionPlaybackState() {
        if (!appPlayerSettings.mediaSessionEnabled || !('mediaSession' in navigator)) return;
        try {
            navigator.mediaSession.playbackState = isPlaying ? 'playing' : 'paused';
            if ('setPositionState' in navigator.mediaSession && Number.isFinite(audio.duration) && audio.duration > 0) {
                navigator.mediaSession.setPositionState({
                    duration: audio.duration,
                    playbackRate: audio.playbackRate || 1,
                    position: Math.min(audio.currentTime || 0, audio.duration)
                });
            }
        } catch (err) {}
    }

    function setupMediaSessionHandlers() {
        if (!appPlayerSettings.mediaSessionEnabled || !('mediaSession' in navigator)) return;
        try {
            navigator.mediaSession.setActionHandler('play', () => togglePlay());
            navigator.mediaSession.setActionHandler('pause', () => pauseTrack());
            navigator.mediaSession.setActionHandler('previoustrack', () => playPrev());
            navigator.mediaSession.setActionHandler('nexttrack', () => playNext());
            navigator.mediaSession.setActionHandler('seekbackward', (details) => {
                audio.currentTime = Math.max(0, audio.currentTime - (details.seekOffset || 5));
            });
            navigator.mediaSession.setActionHandler('seekforward', (details) => {
                const max = Number.isFinite(audio.duration) ? audio.duration : audio.currentTime + 5;
                const target = Math.min(max, audio.currentTime + (details.seekOffset || 5));
                if (guestPreviewMode && target > guestPreviewSeconds) {
                    audio.currentTime = Math.min(guestPreviewSeconds, max);
                    showGuestPreviewPrompt();
                    return;
                }
                audio.currentTime = target;
            });
            navigator.mediaSession.setActionHandler('seekto', (details) => {
                const target = Number(details.seekTime) || 0;
                if (guestPreviewMode && target > guestPreviewSeconds) {
                    audio.currentTime = Math.min(guestPreviewSeconds, Number.isFinite(audio.duration) ? audio.duration : guestPreviewSeconds);
                    showGuestPreviewPrompt();
                    return;
                }
                if (details.fastSeek && 'fastSeek' in audio) audio.fastSeek(target);
                else audio.currentTime = target;
            });
        } catch (err) {
            console.warn('Media Session handlers skipped:', err);
        }
    }

    // ==========================================================================
    // 3. Initialize & Set Player UI state
    // ==========================================================================
    function initPlayerUI() {
        if (appPlayerSettings.mobileCompact) {
            document.body.classList.add('player-mobile-compact');
        }
        setupMediaSessionHandlers();
        // 蹂쇰ⅷ ?ㅼ젙
        audio.volume = playerState.volume;
        audio.muted = playerState.muted === true;
        if (volumeBar) {
            volumeBar.style.width = `${audio.muted ? 0 : playerState.volume * 100}%`;
        }
        updateVolumeIcon(playerState.volume);

        // ?뷀뵆 諛?諛섎났 紐⑤뱶 UI ?ㅼ젙
        updateShuffleUI();
        updateRepeatUI();

        // ?ъ깮 ?湲곗뿴 蹂듦뎄 諛?怨?濡쒕뱶
        if (playerState.queue.length > 0 && playerState.currentIndex >= 0 && playerState.currentIndex < playerState.queue.length) {
            const track = playerState.queue[playerState.currentIndex];
            loadTrackDataOnly(track, playerState.currentTime);
            if (playerState.wasPlaying && btnPlayPause) {
                btnPlayPause.classList.add('resume-ready');
                btnPlayPause.title = '이어 듣기';
            }
        }
        
        renderQueueUI();
        updateMediaSessionPlaybackState();
    }

    // ?ъ깮???숇컲?섏? ?딄퀬 怨??뺣낫留??뚮젅?댁뼱 ?ㅻ뜑/?곹깭諛붿뿉 ?명똿 (?댁뼱?ｊ린 以鍮?
    function loadTrackDataOnly(track, restoreTime = 0) {
        playerState.currentSongId = track.id;
        
        // ?띿뒪???뺣낫 ?명똿
        setElementText(playerTitle, track.title, TEXT_FALLBACKS.title);
        setElementText(playerArtist, track.artist, TEXT_FALLBACKS.artist);
        
        setElementText(expandPlayerTitle, track.title, TEXT_FALLBACKS.title);
        setElementText(expandPlayerAlbum, track.album, '');
        setElementText(expandPlayerArtist, track.artist, TEXT_FALLBACKS.artist);
        
        // ?⑤쾾?꾪듃 媛깆떊
        const coverUrl = `${window.APP_BASE_PATH}cover.php?id=${track.id}`;
        if (playerAlbumImage) playerAlbumImage.src = coverUrl;
        if (expandAlbumImage) expandAlbumImage.src = coverUrl;
        
        // ?ㅻ뵒??src 諛붿씤??        audio.src = `${window.APP_BASE_PATH}stream.php?id=${track.id}`;
        audio.src = `${window.APP_BASE_PATH}stream.php?id=${track.id}`;
        audio.load();
        
        // ?쒓컙 蹂듭썝
        const safeRestoreTime = Math.max(0, parseFloat(restoreTime) || 0);
        pendingRestoreTime = safeRestoreTime > 0 ? safeRestoreTime : null;
        if (timeCurrent) timeCurrent.textContent = formatTime(safeRestoreTime);
        if (expandTimeCurrent) expandTimeCurrent.textContent = formatTime(safeRestoreTime);
        updatePreviewBadge();
        
        // ?곸꽭?뺣낫 踰꾪듉 留곹겕 ?명똿
        if (expandBtnSongDetail) {
            expandBtnSongDetail.href = `${window.APP_BASE_PATH}song.php?id=${track.id}`;
        }

        // 媛???띾뱷 湲곕룞
        loadLyrics(track.id);

        // 醫뗭븘???곹깭 UI ?곕룞
        updateLikeButtonUI(track.id);
        updateMediaSessionMetadata(track);
        updateMediaSessionPlaybackState();
        
        // 紐⑸줉 ???쒖꽦???대옒???숆린??        synchronizeActiveListUI(track.id);
        
        synchronizeActiveListUI(track.id);
        saveStateToStorage();
    }

    // ==========================================================================
    // 4. Play / Pause & Queue Control
    // ==========================================================================
    
    // ?뱀젙 怨??ъ깮 ?ㅽ뻾
    function playTrack(index) {
        if (playerState.queue.length === 0 || index < 0 || index >= playerState.queue.length) return;
        playerState.userActivated = true;
        
        const track = playerState.queue[index];
        const isNewTrack = (playerState.currentIndex !== index || playerState.currentSongId !== track.id);
        
        playerState.currentIndex = index;
        playerState.currentSongId = track.id;
        
        if (isNewTrack) {
            // ?ㅻ뵒???뚯뒪 ?ㅼ젙 諛?利됱떆 ?ъ깮
            audio.src = `${window.APP_BASE_PATH}stream.php?id=${track.id}`;
            audio.load();
            playerState.currentTime = 0;
            pendingRestoreTime = null;
            
            // UI ?꾩껜 媛깆떊
            setElementText(playerTitle, track.title, TEXT_FALLBACKS.title);
            setElementText(playerArtist, track.artist, TEXT_FALLBACKS.artist);
            setElementText(expandPlayerTitle, track.title, TEXT_FALLBACKS.title);
            setElementText(expandPlayerAlbum, track.album, '');
            setElementText(expandPlayerArtist, track.artist, TEXT_FALLBACKS.artist);
            
            const coverUrl = `${window.APP_BASE_PATH}cover.php?id=${track.id}`;
            if (playerAlbumImage) playerAlbumImage.src = coverUrl;
            if (expandAlbumImage) expandAlbumImage.src = coverUrl;
            
            if (expandBtnSongDetail) {
                expandBtnSongDetail.href = `${window.APP_BASE_PATH}song.php?id=${track.id}`;
            }
            updatePreviewBadge();

            // 媛??鍮꾨룞湲?濡쒕뵫
            loadLyrics(track.id);
            updateLikeButtonUI(track.id);
            updateMediaSessionMetadata(track);
            
            // ?ъ깮 湲곕줉 移댁슫??2李?API ?몄텧)
            if (!guestPreviewMode && appPlayerSettings.countRule === 'start') {
                maybeIncrementPlayCount(track.id);
            }
        }
        
        requestPlay({ autoNextOnFailure: true, keepResume: true }).catch(() => {});
    }

    function pauseTrack() {
        audio.pause();
        isPlaying = false;
        updatePlayButtonUI(false);
        updateMediaSessionPlaybackState();
        playerState.currentTime = audio.currentTime;
        saveStateToStorage();
    }

    function togglePlay() {
        if (playerState.queue.length === 0) {
            // ?ъ깮 ?湲곗뿴??鍮꾩뼱?덈뒗 寃쎌슦 ?섏씠吏 ??怨〓뱾??湲곸뼱? ?湲곗뿴 ?뺤꽦 ?쒕룄
            const collected = collectPageSongs();
            if (collected.length > 0) {
                setQueueAndPlay(collected, 0);
            }
            return;
        }
        
        if (playerState.currentIndex === -1) {
            playTrack(0);
        } else {
            if (isPlaying) {
                pauseTrack();
            } else {
                playerState.userActivated = true;
                requestPlay({ keepResume: true }).catch(() => {});
            }
        }
    }

    // ?ㅼ쓬 怨??대룞 ?곗궛
    function playNext() {
        if (playerState.queue.length === 0) return;
        
        let nextIndex = playerState.currentIndex + 1;
        if (nextIndex >= playerState.queue.length) {
            if (playerState.repeatMode === 'all') {
                nextIndex = 0;
            } else {
                // 諛섎났 ?놁쓬 ???뺤?
                pauseTrack();
                audio.currentTime = 0;
                playerState.currentTime = 0;
                saveStateToStorage();
                return;
            }
        }
        playTrack(nextIndex);
    }

    // ?댁쟾 怨??대룞 ?곗궛 (3珥??댁긽 ?ъ깮以묒씠?덉쑝硫?怨?泥섏쓬 ?꾩튂濡? ?꾨땲硫?吏꾩쭨 ?댁쟾怨≪쑝濡?
    function playPrev() {
        if (playerState.queue.length === 0) return;
        
        if (audio.currentTime > 3) {
            audio.currentTime = 0;
            playerState.currentTime = 0;
            saveStateToStorage();
            return;
        }
        
        let prevIndex = playerState.currentIndex - 1;
        if (prevIndex < 0) {
            if (playerState.repeatMode === 'all') {
                prevIndex = playerState.queue.length - 1;
            } else {
                // 泥섏쓬 怨≪뿉???댁쟾怨??꾨Ⅴ硫?泥섏쓬遺???ㅼ떆 ?ъ깮
                audio.currentTime = 0;
                playerState.currentTime = 0;
                saveStateToStorage();
                return;
            }
        }
        playTrack(prevIndex);
    }

    // ?뷀뵆 諛?諛섎났 紐⑤뱶??留욎떠 ?湲곗뿴 ?뺣젹 ?ш뎄??    function toggleShuffle(forceValue = null) {
    function toggleShuffle(forceValue = null) {
        playerState.shuffle = (forceValue !== null) ? forceValue : !playerState.shuffle;
        
        if (playerState.shuffle) {
            // ?뷀뵆 ?쒖꽦?? ?꾩옱 ?ъ깮 以묒씤 怨≪쓣 蹂댁〈?섍퀬 ?섎㉧吏 怨〓뱾???쒕뜡?섍쾶 ?욎쓬
            if (playerState.queue.length > 1) {
                const currentTrack = playerState.currentIndex >= 0 ? playerState.queue[playerState.currentIndex] : null;
                let remainder = [...playerState.queue];
                
                if (currentTrack) {
                    remainder.splice(playerState.currentIndex, 1);
                }
                
                // Fisher-Yates Shuffle ?뚭퀬由ъ쬁
                for (let i = remainder.length - 1; i > 0; i--) {
                    const j = Math.floor(Math.random() * (i + 1));
                    [remainder[i], remainder[j]] = [remainder[j], remainder[i]];
                }
                
                if (currentTrack) {
                    playerState.queue = [currentTrack, ...remainder];
                    playerState.currentIndex = 0;
                } else {
                    playerState.queue = remainder;
                    playerState.currentIndex = -1;
                }
            }
        } else {
            // ?뷀뵆 鍮꾪솢?깊솕: ?먮낯 ?쒖꽌(originalQueue)濡?蹂듦뎄?섍퀬, ?꾩옱 ?곗＜ 怨≪쓽 ?몃뜳?ㅻ? 李얠븘 媛깆떊
            const currentSongId = playerState.currentSongId;
            playerState.queue = [...playerState.originalQueue];
            
            if (currentSongId) {
                const origIndex = playerState.queue.findIndex(t => t.id === currentSongId);
                playerState.currentIndex = (origIndex !== -1) ? origIndex : 0;
            }
        }
        
        updateShuffleUI();
        renderQueueUI();
        saveStateToStorage();
    }

    function toggleRepeatMode() {
        const modes = ['none', 'all', 'one'];
        const nextIdx = (modes.indexOf(playerState.repeatMode) + 1) % modes.length;
        playerState.repeatMode = modes[nextIdx];
        
        updateRepeatUI();
        saveStateToStorage();
    }

    // ==========================================================================
    // 5. ?湲곗뿴(Queue) UI 援ъ텞 諛??쒖뼱
    // ==========================================================================
    
    // ?꾩옱 ???섏씠吏???뚮뜑留곷맂 ?뚯븙 紐⑸줉(.song-item) ?꾩껜瑜?湲곸뼱?ㅺ린
    function collectPageSongs() {
        const songRows = document.querySelectorAll('.song-item');
        const collected = [];
        songRows.forEach(row => {
            collected.push({
                id: row.getAttribute('data-id'),
                title: row.getAttribute('data-title'),
                artist: row.getAttribute('data-artist') || TEXT_FALLBACKS.artist,
                album: row.getAttribute('data-album') || '',
                duration: parseInt(row.getAttribute('data-duration')) || 0
            });
        });
        return collected;
    }

    // ?쒖꽦 ?湲곗뿴??媛깆떊?섍퀬 ?곗＜ ?쒖옉
    function setQueueAndPlay(tracksList, startIndex = 0, isShuffleClick = false) {
        if (tracksList.length === 0) return;
        
        // ?먮낯 ?湲곗뿴 諛깆뾽
        playerState.originalQueue = [...tracksList];
        playerState.queue = [...tracksList];
        playerState.queueContext = document.body ? document.body.className : null;
        
        if (isShuffleClick) {
            playerState.shuffle = true;
            // ?꾩껜 ?뷀뵆 ?ъ깮 泥섎━
            for (let i = playerState.queue.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                [playerState.queue[i], playerState.queue[j]] = [playerState.queue[j], playerState.queue[i]];
            }
            playerState.currentIndex = 0;
        } else {
            playerState.shuffle = false;
            playerState.currentIndex = startIndex;
        }
        
        updateShuffleUI();
        updateRepeatUI();
        renderQueueUI();
        
        // ?대떦 ?몃뜳???곗＜ ?쒖옉
        playTrack(playerState.currentIndex);
    }

    function appendTracksToQueue(tracksList) {
        const tracks = sanitizeQueue(tracksList);
        if (tracks.length === 0) return 0;
        const existingIds = new Set(playerState.queue.map(track => String(track.id)));
        const appended = tracks.filter(track => !existingIds.has(String(track.id)));
        if (appended.length === 0) return 0;
        playerState.queue = playerState.queue.concat(appended);
        playerState.originalQueue = playerState.originalQueue.concat(appended);
        if (playerState.currentIndex < 0 && playerState.queue.length > 0) {
            playerState.currentIndex = 0;
        }
        renderQueueUI();
        saveStateToStorage();
        return appended.length;
    }

    // ?湲곗뿴 UI瑜??⑤꼸 ?묒そ???숈쟻?쇰줈 洹몃젮以?(?ъ씠???⑤꼸 諛??뺤옣 ?뚮젅?댁뼱 ?⑤꼸 ?숈떆 吏??
    function renderQueueUI() {
        if (queueCount) queueCount.textContent = playerState.queue.length;
        
        let html = '';
        if (playerState.queue.length === 0) {
            html = `<p class="queue-empty-text">${escapeHtml(TEXT_FALLBACKS.emptyQueue)}</p>`;
            if (queueListContainer) queueListContainer.innerHTML = html;
            if (expandQueueList) expandQueueList.innerHTML = html;
            return;
        }
        
        playerState.queue.forEach((track, idx) => {
            const isActive = (idx === playerState.currentIndex);
            const activeClass = isActive ? 'active' : '';
            const thumbUrl = `${window.APP_BASE_PATH}cover.php?id=${track.id}`;
            
            html += `
                <div class="queue-item ${activeClass}" data-index="${idx}">
                    <div class="queue-item-thumb">
                        <img src="${thumbUrl}" alt="Cover" loading="lazy" width="44" height="44" onerror="this.onerror=null;this.src='${window.APP_BASE_PATH}assets/img/default-cover.svg';">
                    </div>
                    <div class="queue-item-meta">
                        <div class="queue-item-title">${escapeHtml(track.title)}</div>
                        <div class="queue-item-artist">${escapeHtml(track.artist)}</div>
                    </div>
                    <div class="queue-item-duration">${formatTime(track.duration)}</div>
                    <button type="button" class="queue-item-remove" data-index="${idx}" title="?쒖쇅">
                        <i class="fas fa-trash-alt"></i>
                    </button>
                </div>
            `;
        });

        // 1. ?ъ씠???湲곗뿴 ?뚮뜑留?        if (queueListContainer) {
        if (queueListContainer) {
            queueListContainer.innerHTML = html;
            bindQueueItemEvents(queueListContainer);
        }
        
        // 2. ?뺤옣 ?뚮젅?댁뼱 ?湲곗뿴 ?뚮뜑留?        if (expandQueueList) {
        if (expandQueueList) {
            expandQueueList.innerHTML = html;
            bindQueueItemEvents(expandQueueList);
        }
    }

    // ?湲곗뿴 由ъ뒪???꾩씠???대┃ 諛???젣 ?몃뱾??諛붿씤??    function bindQueueItemEvents(container) {
    function bindQueueItemEvents(container) {
        const items = container.querySelectorAll('.queue-item');
        items.forEach(item => {
            // 怨??대┃ ???湲곗뿴???대떦 怨≪쑝濡??몃뜳???대룞?섏뿬 ?ъ깮
            item.addEventListener('click', function(e) {
                // ?곕젅湲고넻 ?쒖쇅 踰꾪듉 ?대┃ ?쒖뿉???ъ깮?섏? ?딆쓬
                if (e.target.closest('.queue-item-remove')) return;
                
                const idx = parseInt(this.getAttribute('data-index'));
                playTrack(idx);
            });
        });

        // 媛쒕퀎 怨??쒓굅 ?대깽??諛붿씤??        const removeButtons = container.querySelectorAll('.queue-item-remove');
        const removeButtons = container.querySelectorAll('.queue-item-remove');
        removeButtons.forEach(btn => {
            btn.addEventListener('click', function(e) {
                e.stopPropagation();
                const idx = parseInt(this.getAttribute('data-index'));
                removeTrackFromQueue(idx);
            });
        });
    }

    // ?湲곗뿴?먯꽌 ?⑥씪 怨??쒓굅 泥섎━
    function removeTrackFromQueue(index) {
        if (index < 0 || index >= playerState.queue.length) return;
        
        const removedTrack = playerState.queue[index];
        const isRemovingCurrent = (index === playerState.currentIndex);
        
        // ?湲곗뿴?먯꽌 ?쒓굅
        playerState.queue.splice(index, 1);
        
        // ?먮낯 諛깆뾽 ?湲곗뿴?먯꽌???쒓굅
        const origIdx = playerState.originalQueue.findIndex(t => t.id === removedTrack.id);
        if (origIdx !== -1) {
            playerState.originalQueue.splice(origIdx, 1);
        }

        // ?몃뜳??蹂댁젙
        if (isRemovingCurrent) {
            if (playerState.queue.length === 0) {
                // ?湲곗뿴???꾩쟾??鍮꾩뼱踰꾨┛ 寃쎌슦
                playerState.currentIndex = -1;
                playerState.currentSongId = null;
                pauseTrack();
                resetPlayerInfo();
            } else {
                // ?ㅼ뿉 怨≪씠 ?덉쑝硫?洹??몃뜳?ㅻ? ?ъ깮, ?꾨땲硫??댁쟾 ?몃뜳??                if (playerState.currentIndex >= playerState.queue.length) {
                if (playerState.currentIndex >= playerState.queue.length) {
                    playerState.currentIndex = playerState.queue.length - 1;
                }
                playTrack(playerState.currentIndex);
            }
        } else {
            // ?꾩옱 怨〓낫???욎そ 怨≪씠 ??젣?섏뿀?ㅻ㈃ ?몃뜳???고겕由щ㉫??蹂댁젙
            if (index < playerState.currentIndex) {
                playerState.currentIndex--;
            }
        }
        
        renderQueueUI();
        saveStateToStorage();
    }

    // ?湲곗뿴 ?꾩쟾 鍮꾩슦湲?    function clearQueue() {
        // legacy clearQueue confirmation kept inside the real handler below
        
    function clearQueue() {
        if (!confirm("재생 대기열을 비울까요?")) return;
        playerState.queue = [];
        playerState.originalQueue = [];
        playerState.currentIndex = -1;
        playerState.currentSongId = null;
        
        pauseTrack();
        resetPlayerInfo();
        renderQueueUI();
        saveStateToStorage();
    }

    function resetPlayerInfo() {
        setElementText(playerTitle, TEXT_FALLBACKS.noCurrentTrack);
        setElementText(playerArtist, "-");
        setElementText(expandPlayerTitle, TEXT_FALLBACKS.noCurrentTrack);
        setElementText(expandPlayerArtist, "-");
        
        const defaultCover = `${window.APP_BASE_PATH}assets/img/default-cover.svg`;
        if (playerAlbumImage) playerAlbumImage.src = defaultCover;
        if (expandAlbumImage) expandAlbumImage.src = defaultCover;
        
        progressBar.style.width = '0%';
        if (expandProgressBar) expandProgressBar.style.width = '0%';
        timeCurrent.textContent = '00:00';
        timeTotal.textContent = '00:00';
        if (expandTimeCurrent) expandTimeCurrent.textContent = '00:00';
        if (expandTimeTotal) expandTimeTotal.textContent = '00:00';
        if (miniLyricsLine) miniLyricsLine.textContent = '';
        if (expandLyricsFullText) expandLyricsFullText.innerHTML = '<p class="queue-empty-text">곡을 먼저 선택해 주세요.</p>';
        
        // 紐⑸줉 ?쒖꽦 ?대옒?ㅻ룄 ?꾨? ?댁젣
        document.querySelectorAll('.song-item').forEach(el => el.classList.remove('playing'));
    }

    // ==========================================================================
    // 6. 鍮꾨룞湲?媛???띾뱷 諛??숈쟻 ?뚮뜑留?    // ==========================================================================
    function loadLyrics(songId) {
        if (!songId) return;
        
        fetch(`${window.APP_BASE_PATH}api/get_lyrics.php?song_id=${songId}`)
            .then(res => res.json())
            .then(data => {
                if (data.success && data.lyrics) {
                    const cleanLyrics = data.lyrics;
                    const escapeHtml = (value) => String(value || '')
                        .replace(/&/g, '&amp;')
                        .replace(/</g, '&lt;')
                        .replace(/>/g, '&gt;')
                        .replace(/"/g, '&quot;')
                        .replace(/'/g, '&#039;');
                    
                    // 媛????諛붿씤??(nl2br ???以꾨컮轅?html 泥섎━)
                    if (expandLyricsFullText) {
                        expandLyricsFullText.innerHTML = `
                            <div style="padding: 10px 0;">
                                ${escapeHtml(cleanLyrics).replace(/\r?\n/g, '<br>')}
                            </div>
                        `;
                    }
                    
                    // 誘몃땲 ?꾨━酉???以?媛??(泥?以??몄텧)
                    if (miniLyricsLine) {
                        const lines = cleanLyrics.split('\n');
                        miniLyricsLine.textContent = lines[0] || '가사 정보 있음';
                    }
                } else {
                    // 媛???놁쓣 ??                    const noLyricsHtml = '<p class="queue-empty-text">?깅줉??媛?ш? ?놁뒿?덈떎. ?곸꽭?섏씠吏?먯꽌 媛?щ? 異붽???蹂댁꽭??</p>';
                    const noLyricsHtml = '<p class="queue-empty-text">등록된 가사가 없습니다. 상세 페이지에서 가사를 추가해 보세요.</p>';
                    if (expandLyricsFullText) {
                        expandLyricsFullText.innerHTML = noLyricsHtml;
                    }
                    if (miniLyricsLine) {
                        miniLyricsLine.textContent = TEXT_FALLBACKS.noLyrics;
                    }
                }
            })
            .catch(err => {
                console.error("Lyrics Load Error:", err);
                if (miniLyricsLine) miniLyricsLine.textContent = TEXT_FALLBACKS.loadLyricsError;
            });
    }

    // ==========================================================================
    // 7. UI Helpers / Sync State Elements
    // ==========================================================================
    
    function updateShuffleUI() {
        const shuffleOn = playerState.shuffle;
        
        if (btnShuffle) btnShuffle.classList.toggle('active', shuffleOn);
        if (expandBtnShuffle) expandBtnShuffle.classList.toggle('active', shuffleOn);
        
        const titleText = shuffleOn ? "셔플 재생 켜짐" : "셔플 재생";
        if (btnShuffle) btnShuffle.title = titleText;
        if (expandBtnShuffle) expandBtnShuffle.title = titleText;
    }

    function updateRepeatUI() {
        const mode = playerState.repeatMode;
        const btns = [btnRepeat, expandBtnRepeat];
        
        btns.forEach(btn => {
            if (!btn) return;
            
            if (mode === 'none') {
                btn.classList.remove('active');
                btn.innerHTML = '<i class="fas fa-redo"></i>';
                btn.title = "반복 재생 꺼짐";
            } else if (mode === 'all') {
                btn.classList.add('active');
                btn.innerHTML = '<i class="fas fa-redo"></i>';
                btn.title = "반복 재생 (전체 반복)";
            } else if (mode === 'one') {
                btn.classList.add('active');
                btn.innerHTML = '<i class="fas fa-redo"></i><span style="font-size:9px; position:absolute; top:-2px; right:-2px; background:#00CD3C; color:#000; font-weight:700; width:12px; height:12px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center;">1</span>';
                btn.title = "반복 재생 (한 곡 반복)";
            }
        });
    }

    function updatePlayButtonUI(playing) {
        const playHtml = playing ? '<i class="fas fa-pause"></i>' : '<i class="fas fa-play"></i>';
        const titleText = playing ? '일시정지' : '재생';
        
        if (btnPlayPause) {
            btnPlayPause.innerHTML = playHtml;
            btnPlayPause.title = titleText;
        }
        if (expandBtnPlayPause) {
            expandBtnPlayPause.innerHTML = playHtml;
            expandBtnPlayPause.title = titleText;
        }
        
        if (brandIcon) {
            brandIcon.style.animationPlayState = playing ? 'running' : 'paused';
        }
        if (albumArt) {
            albumArt.classList.toggle('playing', playing);
        }

        // 紐⑸줉 ?됱뿉 ?몄텧???ъ깮 ?꾩씠肄??숆린??        document.querySelectorAll('.song-item').forEach(el => {
        document.querySelectorAll('.song-item').forEach(el => {
            const elId = el.getAttribute('data-id');
            const rowIcon = el.querySelector('.play-row-btn i');
            if (rowIcon) {
                if (playing && elId === playerState.currentSongId) {
                    rowIcon.className = 'fas fa-pause';
                } else {
                    rowIcon.className = 'fas fa-play';
                }
            }
        });
    }

    // 醫뗭븘???섑듃) UI ?곕룞
    function updateLikeButtonUI(songId) {
        if (!songId) return;
        
        // ?곸꽭?섏씠吏???섑듃媛 ?뚮뜑留곷맂 ?곹깭????媛깆떊
        const pageLikeBtn = document.querySelector(`.song-detail-art-card .like-btn`);
        
        // ?뺤옣 ?뚮젅?댁뼱???섑듃 媛깆떊
        if (expandBtnLike) {
            const isLiked = isSongLikedInQueue(songId);
            if (isLiked) {
                expandBtnLike.classList.add('liked');
                expandBtnLike.innerHTML = '<i class="fas fa-heart" style="color: #ff3b30;"></i> 좋아요';
                if (pageLikeBtn) {
                    pageLikeBtn.classList.add('liked');
                    pageLikeBtn.innerHTML = '<i class="fas fa-heart"></i>';
                }
            } else {
                expandBtnLike.classList.remove('liked');
                expandBtnLike.innerHTML = '<i class="far fa-heart"></i> 좋아요';
                if (pageLikeBtn) {
                    pageLikeBtn.classList.remove('liked');
                    pageLikeBtn.innerHTML = '<i class="far fa-heart"></i>';
                }
            }
        }
    }

    function isSongLikedInQueue(songId) {
        // ?湲곗뿴?대굹 ?꾩옱 ?붾㈃ ?곗씠???띿꽦?쇰줈遺???먮떒
        const songRow = document.querySelector(`.song-item[data-id="${songId}"]`);
        if (songRow) {
            return songRow.getAttribute('data-liked') === '1';
        }
        return false;
    }

    // ?꾩옱 ?ъ깮 怨?紐⑸줉 ?섏씠?쇱씠???쒖꽦??    function synchronizeActiveListUI(songId) {
    function synchronizeActiveListUI(songId) {
        document.querySelectorAll('.song-item').forEach(row => {
            const rowId = row.getAttribute('data-id');
            if (rowId === songId) {
                row.classList.add('playing');
            } else {
                row.classList.remove('playing');
            }
        });
    }

    // ==========================================================================
    // 8. Event Listeners for Player Control Actions
    // ==========================================================================
    if (btnPlayPause) btnPlayPause.addEventListener('click', togglePlay);
    if (expandBtnPlayPause) expandBtnPlayPause.addEventListener('click', togglePlay);
    
    if (btnNext) btnNext.addEventListener('click', playNext);
    if (expandBtnNext) expandBtnNext.addEventListener('click', playNext);
    
    if (btnPrev) btnPrev.addEventListener('click', playPrev);
    if (expandBtnPrev) expandBtnPrev.addEventListener('click', playPrev);
    
    if (btnShuffle) btnShuffle.addEventListener('click', () => toggleShuffle());
    if (expandBtnShuffle) expandBtnShuffle.addEventListener('click', () => toggleShuffle());
    
    if (btnRepeat) btnRepeat.addEventListener('click', toggleRepeatMode);
    if (expandBtnRepeat) expandBtnRepeat.addEventListener('click', toggleRepeatMode);

    // ?ъ깮 ?湲곗뿴 ?쒕줈???좉?
    if (btnQueue) {
        btnQueue.addEventListener('click', function(e) {
            e.stopPropagation();
            if (queuePanel.style.display === 'none' || queuePanel.style.display === '') {
                queuePanel.style.display = 'flex';
                renderQueueUI();
            } else {
                queuePanel.style.display = 'none';
            }
        });
    }

    if (queueClose) {
        queueClose.addEventListener('click', function() {
            queuePanel.style.display = 'none';
        });
    }

    if (btnClearQueue) {
        btnClearQueue.addEventListener('click', clearQueue);
    }

    // ?쒕줈??諛??곸뿭 ?곗튂 ???リ린
    window.addEventListener('click', function(e) {
        if (queuePanel && queuePanel.style.display === 'flex' && !queuePanel.contains(e.target) && e.target !== btnQueue && !e.target.closest('#btn-queue')) {
            queuePanel.style.display = 'none';
        }
    });

    // ?뺤옣 ?뚮젅?댁뼱 紐⑤떖 ?쒖뼱
    if (btnExpandPlayer) {
        btnExpandPlayer.addEventListener('click', function() {
            if (!expandPlayerOverlay) {
                showPlayerNotice('확장 플레이어를 열 수 없습니다. 기본 플레이어로 계속 재생합니다.', 'info');
                return;
            }
            expandPlayerOverlay.style.display = 'flex';
            document.body.classList.add('expand-player-open');
            renderQueueUI();
            
            // ?뺤옣 ?뚮젅?댁뼱 ?ㅽ뵂 ??吏꾪뻾 ?곹깭 利됱떆 ?移??숆린??            if (audio.duration) {
            if (audio.duration) {
                const pct = (audio.currentTime / audio.duration) * 100;
                if (expandProgressBar) expandProgressBar.style.width = `${pct}%`;
                if (expandTimeCurrent) expandTimeCurrent.textContent = formatTime(audio.currentTime);
                if (expandTimeTotal) expandTimeTotal.textContent = formatTime(audio.duration);
            }
        });
    }

    if (expandPlayerClose) {
        expandPlayerClose.addEventListener('click', closeExpandPlayer);
    }
    if (expandPlayerOverlay) {
        expandPlayerOverlay.addEventListener('click', function(event) {
            if (event.target === expandPlayerOverlay) {
                closeExpandPlayer();
            }
        });
    }

    if (expandBtnSongDetail) {
        expandBtnSongDetail.addEventListener('click', function() {
            saveStateToStorage();
            closeExpandPlayer();
        });
    }

    // ?뺤옣 ?뚮젅?댁뼱 ???ㅼ쐞移?諛붿씤??    if (tabBtnQueue && tabBtnLyrics) {
    if (tabBtnQueue && tabBtnLyrics) {
        tabBtnQueue.addEventListener('click', function() {
            tabBtnQueue.classList.add('active');
            tabBtnLyrics.classList.remove('active');
            if (expandTabQueueContent) expandTabQueueContent.style.display = 'block';
            if (expandTabLyricsContent) expandTabLyricsContent.style.display = 'none';
        });
        
        tabBtnLyrics.addEventListener('click', function() {
            tabBtnLyrics.classList.add('active');
            tabBtnQueue.classList.remove('active');
            if (expandTabLyricsContent) expandTabLyricsContent.style.display = 'block';
            if (expandTabQueueContent) expandTabQueueContent.style.display = 'none';
        });
        
        if (expandBtnLyricsToggle) {
            expandBtnLyricsToggle.addEventListener('click', function() {
                tabBtnLyrics.click();
            });
        }
    }

    // ?뺤옣 ?뚮젅?댁뼱 ??醫뗭븘??諛??뚮젅?대━?ㅽ듃 ?닿린 踰꾪듉 ?곕룞
    if (expandBtnLike) {
        expandBtnLike.addEventListener('click', function() {
            if (playerState.currentSongId) {
                // ?꾩옱 濡쒕뵫??怨?ID 湲곗??쇰줈 鍮꾨룞湲??좉?
                const pageSongIdx = playerState.queue.findIndex(t => t.id === playerState.currentSongId);
                toggleLike(playerState.currentSongId, pageSongIdx);
            }
        });
    }

    if (expandBtnAddPlaylist) {
        expandBtnAddPlaylist.addEventListener('click', function() {
            if (playerState.currentSongId) {
                openPlaylistModal(playerState.currentSongId);
            }
        });
    }

    // ==========================================================================
    // 9. ?ㅻ뵒???대깽??由ъ뒪??諛?5珥?二쇨린 ?꾩튂 諛깆뾽
    // ==========================================================================
    audio.addEventListener('timeupdate', function() {
        if (audio.duration) {
            if (guestPreviewMode && audio.currentTime >= guestPreviewSeconds) {
                audio.pause();
                try { audio.currentTime = Math.min(guestPreviewSeconds, audio.duration || guestPreviewSeconds); } catch (err) {}
                playerState.currentTime = guestPreviewSeconds;
                saveStateToStorage();
                showGuestPreviewPrompt();
                return;
            }
            const pct = (audio.currentTime / audio.duration) * 100;
            
            // 硫붿씤 ?쒗겕諛??숆린??            progressBar.style.width = `${pct}%`;
            progressBar.style.width = `${pct}%`;
            timeCurrent.textContent = formatTime(audio.currentTime);
            
            // ?뺤옣 ?뚮젅?댁뼱 ?쒗겕諛??숆린??(?ㅽ뵂 ?곹깭???뚮쭔)
            if (expandPlayerOverlay.style.display === 'flex') {
                expandProgressBar.style.width = `${pct}%`;
                expandTimeCurrent.textContent = formatTime(audio.currentTime);
            }

            if (!guestPreviewMode && playerState.currentSongId && appPlayerSettings.countRule === '30s' && audio.currentTime >= 30) {
                maybeIncrementPlayCount(playerState.currentSongId);
            }
            if (!guestPreviewMode && playerState.currentSongId && appPlayerSettings.countRule === 'half' && pct >= 50) {
                maybeIncrementPlayCount(playerState.currentSongId);
            }
            if (Date.now() - lastMediaPositionUpdate > 2000) {
                lastMediaPositionUpdate = Date.now();
                updateMediaSessionPlaybackState();
            }
        }
    });

    audio.addEventListener('loadedmetadata', function() {
        applyPendingRestoreTime();
        if (audio.duration && audio.currentTime > audio.duration - 1) {
            audio.currentTime = 0;
            playerState.currentTime = 0;
        }
        timeTotal.textContent = formatTime(audio.duration);
        if (expandTimeTotal) expandTimeTotal.textContent = formatTime(audio.duration);
        updateMediaSessionPlaybackState();
    });

    audio.addEventListener('play', function() {
        isPlaying = true;
        playerState.userActivated = true;
        if (btnPlayPause) btnPlayPause.classList.remove('resume-ready');
        updatePlayButtonUI(true);
        updateMediaSessionPlaybackState();
        saveStateToStorage();
    });

    audio.addEventListener('pause', function() {
        isPlaying = false;
        updatePlayButtonUI(false);
        updateMediaSessionPlaybackState();
        saveStateToStorage();
    });

    audio.addEventListener('error', function() {
        console.warn('Audio stream error; attempting next track if available.', audio.error);
        handleAudioStreamFailure(audio.error || new Error('audio error'));
    });

    audio.addEventListener('ended', function() {
        if (guestPreviewMode) {
            pauseTrack();
            showGuestPreviewPrompt();
            return;
        }
        if (playerState.repeatMode === 'one') {
            audio.currentTime = 0;
            requestPlay({ keepResume: true }).catch(() => {});
        } else if (appPlayerSettings.autoNextEnabled) {
            playNext();
        } else {
            pauseTrack();
        }
    });

    // 5珥?二쇨린?곸씤 ?쒓컙 濡쒖뺄?ㅽ넗由ъ? 諛깆뾽
    setInterval(function() {
        if (isPlaying && audio.currentTime > 0) {
            playerState.currentTime = audio.currentTime;
            saveStateToStorage();
        }
    }, 5000);

    window.addEventListener('beforeunload', saveStateToStorage);
    window.addEventListener('pagehide', saveStateToStorage);
    document.addEventListener('melonlite:page-ready', function () {
        const prompt = document.getElementById('guest-preview-prompt');
        if (prompt) prompt.remove();
        document.body.classList.remove('guest-preview-ended');
    });
    window.addEventListener('pageshow', function(event) {
        if (event.persisted) {
            isPlaying = !audio.paused;
            updatePlayButtonUI(isPlaying);
            updateMediaSessionMetadata(currentTrack());
            updateMediaSessionPlaybackState();
            synchronizeActiveListUI(playerState.currentSongId);
            saveStateToStorage();
        }
    });
    document.addEventListener('visibilitychange', function() {
        if (document.visibilityState === 'hidden') {
            saveStateToStorage();
        } else {
            isPlaying = !audio.paused;
            updatePlayButtonUI(isPlaying);
            updateMediaSessionPlaybackState();
        }
    });

    // ?쒗겕諛??대┃ ?쒖뼱 (硫붿씤 & ?뺤옣 ?移??묒옱)
    function seekAudio(e, wrapperElement) {
        if (!audio.duration) return;
        const rect = wrapperElement.getBoundingClientRect();
        const clickX = e.clientX - rect.left;
        const width = rect.width;
        const percentage = clickX / width;
        try {
            const targetTime = guestPreviewMode ? Math.min(percentage * audio.duration, guestPreviewSeconds) : percentage * audio.duration;
            audio.currentTime = targetTime;
            playerState.currentTime = audio.currentTime;
            if (guestPreviewMode && percentage * audio.duration > guestPreviewSeconds) {
                showPlayerNotice('비로그인 상태에서는 30초까지만 미리듣기할 수 있습니다.', 'info');
            }
            updateMediaSessionPlaybackState();
            saveStateToStorage();
        } catch (err) {
            console.warn('Seek failed:', err);
            showPlayerNotice('탐색 위치를 적용하지 못했습니다. 잠시 후 다시 시도해 주세요.', 'error');
        }
    }

    if (progressWrapper) {
        progressWrapper.addEventListener('click', function(e) {
            seekAudio(e, this);
        });
    }
    if (expandProgressWrapper) {
        expandProgressWrapper.addEventListener('click', function(e) {
            seekAudio(e, this);
        });
    }

    // 蹂쇰ⅷ 議곗젅
    if (volumeWrapper) {
        volumeWrapper.addEventListener('click', function(e) {
            const rect = volumeWrapper.getBoundingClientRect();
            const clickX = e.clientX - rect.left;
            const width = rect.width;
            let percentage = clickX / width;
            
            if (percentage < 0) percentage = 0;
            if (percentage > 1) percentage = 1;
            
            audio.volume = percentage;
            volumeBar.style.width = `${percentage * 100}%`;
            
            if (audio.muted) {
                audio.muted = false;
                btnMute.className = 'fas fa-volume-up volume-icon';
            }
            
            playerState.volume = percentage;
            updateVolumeIcon(percentage);
            saveStateToStorage();
        });
    }

    if (btnMute) {
        btnMute.addEventListener('click', function() {
            if (audio.muted) {
                audio.muted = false;
                volumeBar.style.width = `${playerState.volume * 100}%`;
                audio.volume = playerState.volume;
                updateVolumeIcon(playerState.volume);
            } else {
                audio.muted = true;
                volumeBar.style.width = '0%';
                btnMute.className = 'fas fa-volume-mute volume-icon';
            }
            playerState.muted = audio.muted === true;
            saveStateToStorage();
        });
    }

    function updateVolumeIcon(volume) {
        if (volume === 0) {
            btnMute.className = 'fas fa-volume-mute volume-icon';
        } else if (volume < 0.5) {
            btnMute.className = 'fas fa-volume-down volume-icon';
        } else {
            btnMute.className = 'fas fa-volume-up volume-icon';
        }
    }

    // ==========================================================================
    // 10. 紐⑸줉蹂?"?꾩껜 ?ъ깮" 諛?"?뷀뵆 ?ъ깮" 踰꾪듉 ?대깽??諛붿씤??    // ==========================================================================
    const btnPlayAll = document.querySelector('.btn-play-all');
    const btnShuffleAll = document.querySelector('.btn-shuffle-all');
    const btnAddPageToQueue = document.querySelector('.btn-add-page-to-queue');

    if (btnPlayAll) {
        btnPlayAll.dataset.playerBound = '1';
        btnPlayAll.addEventListener('click', function() {
            const tracks = collectPageSongs();
            if (tracks.length > 0) {
                setQueueAndPlay(tracks, 0, false);
            } else {
                alert("재생할 음악 목록이 없습니다.");
            }
        });
    }

    if (btnShuffleAll) {
        btnShuffleAll.dataset.playerBound = '1';
        btnShuffleAll.addEventListener('click', function() {
            const tracks = collectPageSongs();
            if (tracks.length > 0) {
                setQueueAndPlay(tracks, 0, true);
            } else {
                alert("재생할 음악 목록이 없습니다.");
            }
        });
    }

    if (btnAddPageToQueue) {
        btnAddPageToQueue.dataset.playerBound = '1';
        btnAddPageToQueue.addEventListener('click', function() {
            const tracks = collectPageSongs();
            const addedCount = appendTracksToQueue(tracks);
            if (addedCount > 0) {
                alert(`${addedCount}곡을 현재 대기열에 추가했습니다.`);
            } else {
                alert("새로 추가할 곡이 없습니다.");
            }
        });
    }

    function bindPageActionButtons() {
        document.querySelectorAll('.btn-play-all').forEach(button => {
            if (button.dataset.playerBound === '1') return;
            button.dataset.playerBound = '1';
            button.addEventListener('click', function() {
                const tracks = collectPageSongs();
                if (tracks.length > 0) {
                    setQueueAndPlay(tracks, 0, false);
                } else {
                    alert("재생할 음악 목록이 없습니다.");
                }
            });
        });

        document.querySelectorAll('.btn-shuffle-all').forEach(button => {
            if (button.dataset.playerBound === '1') return;
            button.dataset.playerBound = '1';
            button.addEventListener('click', function() {
                const tracks = collectPageSongs();
                if (tracks.length > 0) {
                    setQueueAndPlay(tracks, 0, true);
                } else {
                    alert("재생할 음악 목록이 없습니다.");
                }
            });
        });

        document.querySelectorAll('.btn-add-page-to-queue').forEach(button => {
            if (button.dataset.playerBound === '1') return;
            button.dataset.playerBound = '1';
            button.addEventListener('click', function() {
                const addedCount = appendTracksToQueue(collectPageSongs());
                alert(addedCount > 0 ? `${addedCount}곡을 현재 대기열에 추가했습니다.` : "새로 추가할 곡이 없습니다.");
            });
        });
    }

    // 媛쒕퀎 怨?紐⑸줉 ???ъ깮踰꾪듉 ?곕룞 ?ъ젙??    function bindPageListPlay() {
    function bindPageListPlay() {
        const songRows = document.querySelectorAll('.song-item');
        songRows.forEach((row, index) => {
            const playBtn = row.querySelector('.play-row-btn');
            if (playBtn) {
                // 湲곗〈 ?몃씪??由ъ뒪?덇? ?덈떎硫?吏?곌굅????뼱?곌린 ?꾪빐 ?덈줈 ?대줎?섏뿬 援먯껜
                const newBtn = playBtn.cloneNode(true);
                playBtn.parentNode.replaceChild(newBtn, playBtn);
                
                newBtn.addEventListener('click', function(e) {
                    e.stopPropagation();
                    const tracks = collectPageSongs();
                    // ?대┃???됱쓽 怨?ID
                    const songId = row.getAttribute('data-id');
                    const targetIdx = tracks.findIndex(t => t.id === songId);
                    
                    // ?꾩옱 ?ъ깮 紐⑸줉 ?꾩껜瑜??湲곗뿴濡??밴퀬 ?좏깮???몃뜳?ㅻ줈 ?곗＜ ?쒖옉
                    setQueueAndPlay(tracks, targetIdx !== -1 ? targetIdx : 0, false);
                });
            }
            
            // 醫뗭븘???좉? 踰꾪듉 諛붿씤???ъ젙??            const likeBtn = row.querySelector('.like-btn');
            const likeBtn = row.querySelector('.like-btn');
            if (likeBtn) {
                const newLikeBtn = likeBtn.cloneNode(true);
                likeBtn.parentNode.replaceChild(newLikeBtn, likeBtn);
                newLikeBtn.addEventListener('click', function(e) {
                    e.stopPropagation();
                    const songId = row.getAttribute('data-id');
                    toggleLike(songId, index);
                });
            }
        });
    }

    window.MelonLiteRebindPlayerPage = function () {
        try {
            bindPageActionButtons();
            bindPageListPlay();
            synchronizeActiveListUI(playerState.currentSongId);
        } catch (err) {
            console.error('Player page rebind failed:', err);
        }
    };

    window.AppPlayer = window.AppPlayer || {};
    window.AppPlayer.playTrackObject = function (track) {
        const normalized = normalizeTrack(track);
        if (!normalized || !normalized.id) return;
        setQueueAndPlay([normalized], 0, false);
    };
    window.AppPlayer.appendTracks = function (tracks) {
        return appendTracksToQueue(Array.isArray(tracks) ? tracks : []);
    };

    // ==========================================================================
    // 11. 2李?3李??닿? API ?곕룞
    // ==========================================================================
    function maybeIncrementPlayCount(songId) {
        if (guestPreviewMode) return;
        if (!appPlayerSettings.historyEnabled || countedSongIds.has(String(songId))) return;
        countedSongIds.add(String(songId));
        incrementPlayCount(songId);
    }

    function incrementPlayCount(songId) {
        const formData = new FormData();
        formData.append('song_id', songId);
        if (window.APP_CSRF_TOKEN) formData.append('csrf_token', window.APP_CSRF_TOKEN);
        
        fetch(`${window.APP_BASE_PATH}api/play_count.php`, {
            method: 'POST',
            headers: window.APP_CSRF_TOKEN ? { 'X-CSRF-Token': window.APP_CSRF_TOKEN } : {},
            body: formData
        })
        .then(res => res.json())
        .then(data => {
            if (data.success) {
                const countTd = document.querySelector(`.song-item[data-id="${songId}"] .play-count-td`);
                if (countTd) {
                    let currentCount = parseInt(countTd.innerText.replace(/,/g, '')) || 0;
                    countTd.innerText = (currentCount + 1).toLocaleString();
                }
            }
        })
        .catch(err => console.error("Play count api error:", err));
    }

    function toggleLike(songId, index) {
        const formData = new FormData();
        formData.append('song_id', songId);
        if (window.APP_CSRF_TOKEN) formData.append('csrf_token', window.APP_CSRF_TOKEN);
        
        fetch(`${window.APP_BASE_PATH}api/toggle_like.php`, {
            method: 'POST',
            headers: window.APP_CSRF_TOKEN ? { 'X-CSRF-Token': window.APP_CSRF_TOKEN } : {},
            body: formData
        })
        .then(res => res.json())
        .then(data => {
            if (data.success) {
                // UI ?곸쓽 醫뗭븘???곗씠???띿꽦 諛??섑듃 媛깆떊
                const songRows = document.querySelectorAll(`.song-item[data-id="${songId}"]`);
                songRows.forEach(row => {
                    row.setAttribute('data-liked', data.liked ? '1' : '0');
                    const rowLikeBtn = row.querySelector('.like-btn');
                    if (rowLikeBtn) {
                        rowLikeBtn.classList.toggle('liked', data.liked);
                        rowLikeBtn.innerHTML = data.liked ? '<i class="fas fa-heart"></i>' : '<i class="far fa-heart"></i>';
                    }
                });

                // ?湲곗뿴 諛??곸꽭?섏씠吏 踰꾪듉 媛깆떊
                updateLikeButtonUI(songId);
                
                // 留뚯빟 醫뗭븘???섏씠吏?쇰㈃ ?붾㈃?먯꽌 諛곗젣
                if (window.location.pathname.includes('liked.php') && !data.liked) {
                    songRows.forEach(row => {
                        row.style.transition = 'opacity 0.3s ease';
                        row.style.opacity = '0';
                        setTimeout(() => {
                            row.remove();
                            // ?湲곗뿴 ?숆린???쒓굅 泥섎━
                            const queueIdx = playerState.queue.findIndex(t => t.id === songId);
                            if (queueIdx !== -1) {
                                removeTrackFromQueue(queueIdx);
                            }
                        }, 300);
                    });
                }
            } else {
                alert("좋아요 반영 실패: " + data.message);
            }
        })
        .catch(err => console.error("Like toggle api error:", err));
    }

    // ?뚮젅?대━?ㅽ듃 紐⑤떖 ?닿린
    function openPlaylistModal(songId) {
        modalSongId.value = songId;
        playlistModal.style.display = 'flex';
        modalOptions.innerHTML = '<p class="loading-text">플레이리스트 목록을 불러오는 중...</p>';
        
        fetch(`${window.APP_BASE_PATH}api/get_playlists.php`)
            .then(res => res.json())
            .then(data => {
                if (data.success) {
                    if (data.playlists.length === 0) {
                        modalOptions.innerHTML = '<p class="empty-text">보유한 플레이리스트가 없습니다.</p>';
                    } else {
                        let html = '';
                        data.playlists.forEach(pl => {
                            html += `
                                <div class="playlist-option-item" data-playlist-id="${pl.id}">
                                    <span class="playlist-option-name">${escapeHtml(pl.name)}</span>
                                    <span class="playlist-option-count">${pl.song_count}곡 수록</span>
                                </div>
                            `;
                        });
                        modalOptions.innerHTML = html;
                        
                        modalOptions.querySelectorAll('.playlist-option-item').forEach(item => {
                            item.addEventListener('click', function() {
                                const plId = this.getAttribute('data-playlist-id');
                                addTrackToPlaylist(plId, songId);
                            });
                        });
                    }
                } else {
                    modalOptions.innerHTML = '<p class="empty-text">조회 실패</p>';
                }
            })
            .catch(err => {
                console.error(err);
                modalOptions.innerHTML = '<p class="empty-text">오류 발생</p>';
            });
    }

    function closePlaylistModal() {
        playlistModal.style.display = 'none';
        modalSongId.value = '';
    }

    function addTrackToPlaylist(playlistId, songId) {
        const formData = new FormData();
        formData.append('playlist_id', playlistId);
        formData.append('song_id', songId);
        if (window.APP_CSRF_TOKEN) formData.append('csrf_token', window.APP_CSRF_TOKEN);
        
        fetch(`${window.APP_BASE_PATH}api/add_to_playlist.php`, {
            method: 'POST',
            headers: window.APP_CSRF_TOKEN ? { 'X-CSRF-Token': window.APP_CSRF_TOKEN } : {},
            body: formData
        })
        .then(res => res.json())
        .then(data => {
            if (data.success) {
                alert("플레이리스트에 곡을 추가했습니다.");
                closePlaylistModal();
            } else {
                alert(data.message);
            }
        })
        .catch(err => console.error(err));
    }

    if (modalClose) modalClose.addEventListener('click', closePlaylistModal);
    window.addEventListener('click', function(e) {
        if (e.target === playlistModal) {
            closePlaylistModal();
        }
    });

    // ==========================================================================
    // 12. 紐⑤컮???쒕줈???꾨쾭嫄?硫붾돱 諛붿씤??(3李?肄붾뱶 ?좎?)
    // ==========================================================================
    if (mobileHamburger && appSidebar && sidebarOverlay && mobileHamburger.dataset.sidebarBound !== '1') {
        mobileHamburger.addEventListener('click', function() {
            appSidebar.classList.add('open');
            sidebarOverlay.classList.add('open');
        });
        
        sidebarOverlay.addEventListener('click', function() {
            appSidebar.classList.remove('open');
            sidebarOverlay.classList.remove('open');
        });
        
        appSidebar.querySelectorAll('.nav-item').forEach(item => {
            item.addEventListener('click', function() {
                appSidebar.classList.remove('open');
                sidebarOverlay.classList.remove('open');
            });
        });
    }

    document.addEventListener('keydown', function(e) {
        if (!appPlayerSettings.keyboardShortcutsEnabled) return;
        const active = document.activeElement;
        const tagName = active && active.tagName ? active.tagName.toUpperCase() : '';
        if (['INPUT', 'TEXTAREA', 'SELECT'].includes(tagName) || (active && active.isContentEditable)) return;

        const key = e.key.toLowerCase();
        if (e.code === 'Space') {
            e.preventDefault();
            togglePlay();
        } else if (e.key === 'ArrowRight') {
            e.preventDefault();
            audio.currentTime = Math.min(Number.isFinite(audio.duration) ? audio.duration : audio.currentTime + 5, audio.currentTime + 5);
            updateMediaSessionPlaybackState();
        } else if (e.key === 'ArrowLeft') {
            e.preventDefault();
            audio.currentTime = Math.max(0, audio.currentTime - 5);
            updateMediaSessionPlaybackState();
        } else if (key === 'n') {
            playNext();
        } else if (key === 'p') {
            playPrev();
        } else if (key === 'l' && playerState.currentSongId) {
            toggleLike(playerState.currentSongId, playerState.currentIndex);
        } else if (key === 's') {
            toggleShuffle();
        } else if (key === 'r') {
            toggleRepeatMode();
        }
    });

    // HTML Escape Helper
    function escapeHtml(text) {
        if (!text) return '';
        return text
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/"/g, "&quot;")
            .replace(/'/g, "&#039;");
    }

    // Time Format Helper (seconds -> mm:ss)
    function formatTime(seconds) {
        if (isNaN(seconds) || seconds === Infinity) return '00:00';
        const mins = Math.floor(seconds / 60);
        const secs = Math.floor(seconds % 60);
        return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
    }

    // ==========================================================================
    // 13. Run Core
    // ==========================================================================
    loadStateFromStorage();
    initPlayerUI();
    bindPageActionButtons();
    bindPageListPlay();
});
