(function () {
    if (window.__MELON_LITE_DOWNLOAD_INITED) return;
    window.__MELON_LITE_DOWNLOAD_INITED = true;

    const state = {
        link: null,
        meta: null,
        fileHandle: null,
        controller: null,
        downloading: false
    };

    function qs(id) {
        return document.getElementById(id);
    }

    function supportsFilePicker() {
        return typeof window.showSaveFilePicker === 'function' && window.isSecureContext === true;
    }

    function formatBytes(bytes) {
        const value = Number(bytes || 0);
        if (!Number.isFinite(value) || value <= 0) return '-';
        const units = ['B', 'KB', 'MB', 'GB'];
        let size = value;
        let idx = 0;
        while (size >= 1024 && idx < units.length - 1) {
            size /= 1024;
            idx += 1;
        }
        return `${size.toFixed(idx === 0 ? 0 : 1)} ${units[idx]}`;
    }

    function cleanFilename(name, fallback) {
        let value = String(name || '').replace(/[\\/:*?"<>|]+/g, ' ').replace(/\s+/g, ' ').trim();
        if (!value) value = fallback || 'download';
        return value.slice(0, 180);
    }

    function ensureExtension(name, ext) {
        const cleanExt = String(ext || '').replace(/^\./, '').toLowerCase();
        let value = cleanFilename(name, cleanExt ? `download.${cleanExt}` : 'download');
        if (!cleanExt) return value;
        value = value.replace(/\.[A-Za-z0-9]{1,8}$/g, '');
        return `${value}.${cleanExt}`;
    }

    function setStatus(message, type) {
        const el = qs('download-status-text');
        if (!el) return;
        el.textContent = message || '';
        el.dataset.type = type || '';
    }

    function setBusy(isBusy) {
        state.downloading = isBusy;
        const start = qs('download-start-btn');
        const cancel = qs('download-cancel-btn');
        const close = qs('download-modal-close');
        const pick = qs('download-pick-location-btn');
        const input = qs('download-filename-input');
        if (start) start.disabled = isBusy;
        if (cancel) cancel.textContent = isBusy ? '중단' : '취소';
        if (close) close.disabled = isBusy;
        if (pick) pick.disabled = isBusy || !supportsFilePicker();
        if (input) input.disabled = isBusy;
    }

    function resetProgress() {
        const wrap = qs('download-progress-wrap');
        const bar = qs('download-progress-bar');
        const label = qs('download-progress-label');
        const percent = qs('download-progress-percent');
        if (wrap) wrap.hidden = true;
        if (bar) bar.style.width = '0%';
        if (label) label.textContent = '대기 중';
        if (percent) percent.textContent = '0%';
    }

    function updateProgress(loaded, total) {
        const wrap = qs('download-progress-wrap');
        const bar = qs('download-progress-bar');
        const label = qs('download-progress-label');
        const percent = qs('download-progress-percent');
        if (wrap) wrap.hidden = false;
        if (total > 0) {
            const ratio = Math.min(100, Math.max(0, Math.round((loaded / total) * 100)));
            if (bar) bar.style.width = `${ratio}%`;
            if (label) label.textContent = `${formatBytes(loaded)} / ${formatBytes(total)}`;
            if (percent) percent.textContent = `${ratio}%`;
        } else {
            if (bar) bar.style.width = '100%';
            if (label) label.textContent = `${formatBytes(loaded)} 받는 중`;
            if (percent) percent.textContent = '';
        }
    }

    function modal() {
        return qs('download-modal');
    }

    function showModal() {
        const el = modal();
        if (!el) return;
        el.hidden = false;
        el.style.display = 'flex';
        el.setAttribute('aria-hidden', 'false');
        document.body.classList.add('modal-open');
        document.body.classList.add('download-modal-open');
        setTimeout(() => {
            const input = qs('download-filename-input');
            if (input) input.focus();
        }, 40);
    }

    function closeModal(force) {
        if (state.downloading && !force) return;
        if (state.controller) {
            state.controller.abort();
            state.controller = null;
        }
        const el = modal();
        if (el) {
            el.hidden = true;
            el.style.display = 'none';
            el.setAttribute('aria-hidden', 'true');
        }
        document.body.classList.remove('modal-open');
        document.body.classList.remove('download-modal-open');
        state.link = null;
        state.meta = null;
        state.fileHandle = null;
        state.downloading = false;
        setBusy(false);
        resetProgress();
        setStatus('');
    }

    function metaUrlFromLink(link) {
        const url = new URL(link.getAttribute('href'), window.location.href);
        url.searchParams.set('meta', '1');
        return url;
    }

    async function loadMeta(link) {
        const response = await fetch(metaUrlFromLink(link).toString(), {
            credentials: 'same-origin',
            headers: {
                'Accept': 'application/json',
                'X-Requested-With': 'XMLHttpRequest'
            },
            cache: 'no-store'
        });
        const contentType = response.headers.get('Content-Type') || '';
        if (!response.ok || !contentType.includes('application/json')) {
            throw new Error('다운로드 정보를 불러오지 못했습니다.');
        }
        const payload = await response.json();
        if (!payload || payload.success !== true || !payload.data) {
            throw new Error(payload && payload.message ? payload.message : '다운로드 정보를 불러오지 못했습니다.');
        }
        return payload.data;
    }

    function hydrateModal(meta) {
        const title = qs('download-track-title');
        const trackMeta = qs('download-track-meta');
        const input = qs('download-filename-input');
        const location = qs('download-location-text');
        const pick = qs('download-pick-location-btn');
        const name = ensureExtension(meta.filename || meta.title || '', meta.extension || '');
        if (title) title.textContent = meta.title || '선택한 곡';
        if (trackMeta) {
            const parts = [];
            if (meta.artist) parts.push(meta.artist);
            if (meta.album) parts.push(meta.album);
            if (meta.file_size) parts.push(formatBytes(meta.file_size));
            trackMeta.textContent = parts.join(' · ') || '음원 파일';
        }
        if (input) input.value = name;
        if (supportsFilePicker()) {
            if (location) location.textContent = '저장 버튼을 누르거나 위치 선택으로 저장 위치를 지정할 수 있습니다.';
            if (pick) pick.hidden = false;
        } else {
            if (location) location.textContent = '이 브라우저는 저장 경로 직접 선택을 지원하지 않습니다. 파일명 지정 후 브라우저 다운로드로 저장합니다.';
            if (pick) pick.hidden = true;
        }
    }

    async function openModal(link) {
        state.link = link;
        state.meta = null;
        state.fileHandle = null;
        resetProgress();
        setBusy(false);
        setStatus('다운로드 정보를 불러오는 중입니다.');
        const input = qs('download-filename-input');
        if (input) input.value = '';
        const title = qs('download-track-title');
        const trackMeta = qs('download-track-meta');
        if (title) title.textContent = '선택한 곡';
        if (trackMeta) trackMeta.textContent = '파일 정보를 불러오는 중입니다.';
        showModal();
        try {
            const meta = await loadMeta(link);
            state.meta = meta;
            hydrateModal(meta);
            setStatus('');
        } catch (err) {
            setStatus(err.message || '다운로드 정보를 불러오지 못했습니다.', 'error');
        }
    }

    async function pickLocation() {
        if (!supportsFilePicker() || !state.meta) return;
        const input = qs('download-filename-input');
        const filename = ensureExtension(input ? input.value : state.meta.filename, state.meta.extension);
        try {
            state.fileHandle = await window.showSaveFilePicker({
                suggestedName: filename,
                types: [{
                    description: 'Audio file',
                    accept: { 'audio/*': [`.${state.meta.extension || 'mp3'}`] }
                }]
            });
            if (input && state.fileHandle.name) input.value = ensureExtension(state.fileHandle.name, state.meta.extension);
            const location = qs('download-location-text');
            if (location) location.textContent = `저장 위치 선택됨: ${state.fileHandle.name}`;
            setStatus('');
        } catch (err) {
            if (err && err.name !== 'AbortError') {
                setStatus('저장 위치를 선택하지 못했습니다.', 'warning');
            }
        }
    }

    function downloadUrl(filename) {
        const url = new URL(state.link.getAttribute('href'), window.location.href);
        url.searchParams.set('filename', filename);
        return url;
    }

    async function fetchForDownload(filename) {
        state.controller = new AbortController();
        const response = await fetch(downloadUrl(filename).toString(), {
            credentials: 'same-origin',
            cache: 'no-store',
            signal: state.controller.signal,
            headers: {
                'X-Requested-With': 'XMLHttpRequest'
            }
        });
        if (!response.ok) {
            let message = '다운로드를 시작하지 못했습니다.';
            try {
                const text = await response.text();
                if (text) message = text.slice(0, 200);
            } catch (err) {}
            throw new Error(message);
        }
        return response;
    }

    async function saveWithFilePicker(response) {
        const writable = await state.fileHandle.createWritable();
        const total = Number(response.headers.get('Content-Length') || state.meta.file_size || 0);
        let loaded = 0;
        if (!response.body || !response.body.getReader) {
            const blob = await response.blob();
            loaded = blob.size;
            updateProgress(loaded, total || loaded);
            await writable.write(blob);
            await writable.close();
            return;
        }
        const reader = response.body.getReader();
        try {
            while (true) {
                const result = await reader.read();
                if (result.done) break;
                loaded += result.value.byteLength;
                await writable.write(result.value);
                updateProgress(loaded, total);
            }
            await writable.close();
        } catch (err) {
            try { await writable.abort(); } catch (ignored) {}
            throw err;
        }
    }

    async function saveWithBlobFallback(response, filename) {
        const total = Number(response.headers.get('Content-Length') || state.meta.file_size || 0);
        let loaded = 0;
        const chunks = [];
        if (response.body && response.body.getReader) {
            const reader = response.body.getReader();
            while (true) {
                const result = await reader.read();
                if (result.done) break;
                chunks.push(result.value);
                loaded += result.value.byteLength;
                updateProgress(loaded, total);
            }
        } else {
            const blob = await response.blob();
            loaded = blob.size;
            updateProgress(loaded, total || loaded);
            chunks.push(blob);
        }
        const blob = new Blob(chunks, { type: response.headers.get('Content-Type') || 'application/octet-stream' });
        const objectUrl = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = objectUrl;
        a.download = filename;
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
        a.remove();
        setTimeout(() => URL.revokeObjectURL(objectUrl), 30000);
    }

    async function startDownload() {
        if (!state.link || !state.meta || state.downloading) return;
        const input = qs('download-filename-input');
        const filename = ensureExtension(input ? input.value : state.meta.filename, state.meta.extension);
        if (input) input.value = filename;
        setBusy(true);
        resetProgress();
        setStatus('다운로드를 준비하는 중입니다.');
        try {
            if (supportsFilePicker() && !state.fileHandle) {
                await pickLocation();
                if (!state.fileHandle) {
                    setBusy(false);
                    return;
                }
            }
            const response = await fetchForDownload(filename);
            setStatus('다운로드 중입니다.');
            if (supportsFilePicker() && state.fileHandle) {
                await saveWithFilePicker(response);
            } else {
                await saveWithBlobFallback(response, filename);
            }
            updateProgress(Number(state.meta.file_size || 0), Number(state.meta.file_size || 0));
            setStatus('다운로드가 완료되었습니다.', 'success');
            setTimeout(() => closeModal(true), 900);
        } catch (err) {
            if (err && err.name === 'AbortError') {
                setStatus('다운로드가 중단되었습니다.', 'warning');
            } else {
                setStatus(err && err.message ? err.message : '다운로드 중 오류가 발생했습니다.', 'error');
            }
            setBusy(false);
        } finally {
            state.controller = null;
        }
    }

    document.addEventListener('click', function (event) {
        const downloadLink = event.target.closest('a.download-song-btn[href]');
        if (downloadLink) {
            event.preventDefault();
            event.stopPropagation();
            openModal(downloadLink);
            return;
        }

        if (event.target.closest('#download-modal-close')) {
            event.preventDefault();
            closeModal(false);
            return;
        }

        if (event.target.closest('#download-cancel-btn')) {
            event.preventDefault();
            if (state.downloading && state.controller) {
                state.controller.abort();
                return;
            }
            closeModal(false);
            return;
        }

        if (event.target.closest('#download-pick-location-btn')) {
            event.preventDefault();
            pickLocation();
            return;
        }

        if (event.target.closest('#download-start-btn')) {
            event.preventDefault();
            startDownload();
            return;
        }

        const overlay = event.target.closest('#download-modal');
        if (overlay && event.target === overlay) {
            closeModal(false);
        }
    }, true);

    document.addEventListener('keydown', function (event) {
        if (event.key === 'Escape' && !modal()?.hidden) {
            event.preventDefault();
            closeModal(false);
        }
    });
})();
