(function() {
  const M = window.MusicRoom;
  
  document.addEventListener("DOMContentLoaded", () => {
    const addBtn = M.$("#btn-add");
    const addPanel = M.$("#add-panel");
    const addCloseBtn = M.$("#btn-add-close");
    const uploadFilesBtn = M.$("#btn-upload-files");
    const fileInput = M.$("#file-input");
    const dropzone = M.$("#upload-dropzone");
    const libraryPanel = M.$("#library-panel");
    const tasksList = M.$("#tasks-list");
    const tasksEmpty = M.$("#tasks-empty");
    
    // Slow queue section elements (created dynamically)
    let slowQueueSection = null;
    let slowQueuePollInterval = null;
    
    if (!addBtn || !fileInput || !dropzone) return;
    
    function openPanel() {
      addPanel.classList.remove("hidden", "closing");
      addBtn.classList.add("hidden");
    }
    
    function closePanel() {
      addPanel.classList.add("closing");
      addBtn.classList.remove("hidden");
      addPanel.addEventListener("animationend", () => {
        if (addPanel.classList.contains("closing")) {
          addPanel.classList.add("hidden");
          addPanel.classList.remove("closing");
        }
      }, { once: true });
    }
    
    // Open add panel
    addBtn.onclick = () => {
      if (!M.currentUser) {
        M.showToast("Sign in to add tracks");
        return;
      }
      openPanel();
    };
    
    // Close add panel
    addCloseBtn.onclick = () => {
      closePanel();
    };
    
    // Upload files option
    uploadFilesBtn.onclick = () => {
      fileInput.click();
    };
    
    // Fetch from URL option
    const fetchUrlBtn = M.$("#btn-fetch-url");
    const fetchDialog = M.$("#fetch-dialog");
    const fetchCloseBtn = M.$("#btn-fetch-close");
    const fetchUrlInput = M.$("#fetch-url-input");
    const fetchSubmitBtn = M.$("#btn-fetch-submit");
    
    function openFetchDialog() {
      closePanel();
      fetchDialog.classList.remove("hidden", "closing");
      fetchUrlInput.value = "";
      fetchUrlInput.focus();
    }
    
    function closeFetchDialog() {
      fetchDialog.classList.add("closing");
      fetchDialog.addEventListener("animationend", () => {
        if (fetchDialog.classList.contains("closing")) {
          fetchDialog.classList.add("hidden");
          fetchDialog.classList.remove("closing");
        }
      }, { once: true });
    }
    
    if (fetchUrlBtn) {
      fetchUrlBtn.onclick = openFetchDialog;
    }
    
    if (fetchCloseBtn) {
      fetchCloseBtn.onclick = closeFetchDialog;
    }
    
    if (fetchSubmitBtn) {
      fetchSubmitBtn.onclick = async () => {
        const url = fetchUrlInput.value.trim();
        if (!url) {
          M.showToast("Please enter a URL");
          return;
        }
        closeFetchDialog();
        M.showToast("Checking URL...");
        
        try {
          const res = await fetch("/api/fetch", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ url })
          });
          
          if (res.ok) {
            const data = await res.json();
            
            if (data.type === "playlist") {
              const queuePlaylist = async () => {
                const confirmRes = await fetch("/api/fetch/confirm", {
                  method: "POST",
                  headers: { "Content-Type": "application/json" },
                  body: JSON.stringify({ items: data.items, playlistTitle: data.title })
                });
                
                if (confirmRes.ok) {
                  const confirmData = await confirmRes.json();
                  M.showToast(`${confirmData.message} → "${confirmData.playlistName}"`);
                  // Refresh playlists to show the new one
                  if (M.playlists?.load) M.playlists.load();
                  // Refresh slow queue display
                  pollSlowQueue();
                } else {
                  const err = await confirmRes.json().catch(() => ({}));
                  M.showToast(err.error || "Failed to queue playlist", "error");
                }
              };

              M.showConfirmToast(
                `Download playlist "${data.title}" with ${data.count} items? Items download slowly and a playlist will be created automatically.`,
                queuePlaylist,
                { confirmText: "Download", duration: 20000 }
              );
            } else if (data.type === "single") {
              M.showToast(`Queued: ${data.title}`);
              // Task will be created by WebSocket progress messages
            } else {
              M.showToast(data.message || "Fetch started");
            }
          } else {
            const err = await res.json().catch(() => ({}));
            M.showToast(err.error || "Fetch failed", "error");
          }
        } catch (e) {
          M.showToast("Fetch failed", "error");
        }
      };
    }
    
    if (fetchUrlInput) {
      fetchUrlInput.onkeydown = (e) => {
        if (e.key === "Enter") fetchSubmitBtn.click();
        if (e.key === "Escape") closeFetchDialog();
      };
    }
    
    // File input change
    fileInput.onchange = () => {
      if (fileInput.files.length > 0) {
        closePanel();
        uploadFiles(fileInput.files);
        fileInput.value = "";
      }
    };
    
    // Drag and drop on library panel
    let dragCounter = 0;
    
    libraryPanel.ondragenter = (e) => {
      if (!M.currentUser) return;
      if (!e.dataTransfer.types.includes("Files")) return;
      e.preventDefault();
      dragCounter++;
      dropzone.classList.remove("hidden");
    };
    
    libraryPanel.ondragleave = (e) => {
      e.preventDefault();
      dragCounter--;
      if (dragCounter === 0) {
        dropzone.classList.add("hidden");
      }
    };
    
    libraryPanel.ondragover = (e) => {
      if (!M.currentUser) return;
      if (!e.dataTransfer.types.includes("Files")) return;
      e.preventDefault();
      e.dataTransfer.dropEffect = "copy";
    };
    
    libraryPanel.ondrop = (e) => {
      e.preventDefault();
      dragCounter = 0;
      dropzone.classList.add("hidden");
      
      if (!M.currentUser) {
        M.showToast("Sign in to upload");
        return;
      }
      
      const files = e.dataTransfer.files;
      if (files.length > 0) {
        uploadFiles(files);
      }
    };
    
    // Task management
    const fetchTasks = new Map(); // Map<id, taskHandle>
    
    function updateTasksEmpty() {
      const hasActiveTasks = tasksList.children.length > 0;
      const hasSlowQueue = slowQueueSection && !slowQueueSection.classList.contains("hidden");
      tasksEmpty.classList.toggle("hidden", hasActiveTasks || hasSlowQueue);
    }
    
    // Slow queue display
    function createSlowQueueSection() {
      if (slowQueueSection) return slowQueueSection;
      
      slowQueueSection = document.createElement("div");
      slowQueueSection.className = "slow-queue-section hidden";
      slowQueueSection.innerHTML = `
        <div class="slow-queue-header">
          <span class="slow-queue-title">Playlist Queue</span>
          <span class="slow-queue-timer"></span>
          <button class="slow-queue-cancel-all" title="Cancel all">Cancel All</button>
        </div>
        <div class="slow-queue-list"></div>
      `;
      
      // Wire up cancel all button
      slowQueueSection.querySelector(".slow-queue-cancel-all").onclick = async () => {
        try {
          const res = await fetch("/api/fetch", { method: "DELETE" });
          if (res.ok) {
            const data = await res.json();
            M.showToast(data.message);
            pollSlowQueue();
          } else {
            M.showToast("Failed to cancel", "error");
          }
        } catch (e) {
          M.showToast("Failed to cancel", "error");
        }
      };
      
      // Insert before tasks-empty
      tasksEmpty.parentNode.insertBefore(slowQueueSection, tasksEmpty);
      return slowQueueSection;
    }
    
    function formatTime(seconds) {
      if (seconds <= 0) return "now";
      const mins = Math.floor(seconds / 60);
      const secs = seconds % 60;
      if (mins > 0) return `${mins}m ${secs}s`;
      return `${secs}s`;
    }
    
    const QUEUE_PREVIEW_COUNT = 5;
    let showAllQueue = false;
    
    function updateSlowQueueDisplay(slowQueue, slowQueueNextIn) {
      const section = createSlowQueueSection();
      const queuedItems = slowQueue.filter(i => i.status === "queued");
      
      if (queuedItems.length === 0) {
        section.classList.add("hidden");
        showAllQueue = false;
        updateTasksEmpty();
        return;
      }
      
      section.classList.remove("hidden");
      
      // Update header with count and timer
      const timerEl = section.querySelector(".slow-queue-timer");
      timerEl.textContent = `${queuedItems.length} queued · next in ${formatTime(slowQueueNextIn)}`;
      
      // Determine how many items to show
      const itemsToShow = showAllQueue ? queuedItems : queuedItems.slice(0, QUEUE_PREVIEW_COUNT);
      const hiddenCount = queuedItems.length - itemsToShow.length;
      
      // Group items by playlist
      const byPlaylist = new Map();
      for (const item of itemsToShow) {
        const key = item.playlistId || "__none__";
        if (!byPlaylist.has(key)) {
          byPlaylist.set(key, { name: item.playlistName, items: [] });
        }
        byPlaylist.get(key).items.push(item);
      }
      
      // Update list
      const listEl = section.querySelector(".slow-queue-list");
      let html = "";
      
      for (const [playlistId, group] of byPlaylist) {
        if (group.name) {
          html += `<div class="slow-queue-playlist-header">📁 ${group.name}</div>`;
        }
        html += group.items.map((item, i) => {
          const isNext = queuedItems.indexOf(item) === 0;
          return `
            <div class="slow-queue-item${isNext ? ' next' : ''}" data-id="${item.id}">
              <span class="slow-queue-item-icon">${isNext ? '⏳' : '·'}</span>
              <span class="slow-queue-item-title">${item.title}</span>
              <button class="slow-queue-cancel" title="Cancel">✕</button>
            </div>
          `;
        }).join("");
      }
      
      // Add show more/less button if needed
      if (queuedItems.length > QUEUE_PREVIEW_COUNT) {
        if (showAllQueue) {
          html += `<button class="slow-queue-show-toggle">Show less</button>`;
        } else {
          html += `<button class="slow-queue-show-toggle">Show ${hiddenCount} more...</button>`;
        }
      }
      
      listEl.innerHTML = html;
      
      // Add cancel handlers
      listEl.querySelectorAll(".slow-queue-cancel").forEach(btn => {
        btn.onclick = async (e) => {
          e.stopPropagation();
          const itemEl = btn.closest(".slow-queue-item");
          const itemId = itemEl.dataset.id;
          try {
            const res = await fetch(`/api/fetch/${itemId}`, { method: "DELETE" });
            if (res.ok) {
              itemEl.remove();
              pollSlowQueue();
            } else {
              M.showToast("Cannot cancel item", "error");
            }
          } catch (e) {
            M.showToast("Failed to cancel", "error");
          }
        };
      });
      
      // Add show more/less handler
      const toggleBtn = listEl.querySelector(".slow-queue-show-toggle");
      if (toggleBtn) {
        toggleBtn.onclick = () => {
          showAllQueue = !showAllQueue;
          updateSlowQueueDisplay(slowQueue, slowQueueNextIn);
        };
      }
      
      updateTasksEmpty();
    }
    
    async function pollSlowQueue() {
      if (!M.currentUser || M.currentUser.isGuest) return;
      
      try {
        const res = await fetch("/api/fetch");
        if (res.ok) {
          const data = await res.json();
          updateSlowQueueDisplay(data.slowQueue || [], data.slowQueueNextIn || 0);
        }
      } catch (e) {
        // Ignore poll errors
      }
    }
    
    function startSlowQueuePoll() {
      if (slowQueuePollInterval) return;
      pollSlowQueue();
      slowQueuePollInterval = setInterval(pollSlowQueue, 5000);
    }
    
    function stopSlowQueuePoll() {
      if (slowQueuePollInterval) {
        clearInterval(slowQueuePollInterval);
        slowQueuePollInterval = null;
      }
      if (slowQueueSection) {
        slowQueueSection.classList.add("hidden");
        updateTasksEmpty();
      }
    }
    
    // Expose start/stop for auth module to call
    M.startSlowQueuePoll = startSlowQueuePoll;
    M.stopSlowQueuePoll = stopSlowQueuePoll;
    
    // Handle WebSocket fetch progress messages
    M.handleFetchProgress = function(data) {
      let task = fetchTasks.get(data.id);
      
      // Create task if we don't have one for this id
      if (!task && data.status !== "complete" && data.status !== "error") {
        task = createTask(data.title || "Downloading...", data.id);
      }
      
      if (!task) return;
      
      if (data.status === "downloading" || data.status === "queued") {
        task.setProgress(data.progress || 0);
      } else if (data.status === "complete") {
        task.setComplete();
        fetchTasks.delete(data.id);
        // Refresh slow queue on completion
        pollSlowQueue();
      } else if (data.status === "error") {
        task.setError(data.error || "Failed");
        fetchTasks.delete(data.id);
        // Refresh slow queue on error
        pollSlowQueue();
      }
    };
    
    function createTask(filename, fetchId) {
      const task = document.createElement("div");
      task.className = "task-item";
      task.innerHTML = `
        <span class="task-spinner"></span>
        <span class="task-icon"></span>
        <span class="task-name">${filename}</span>
        <span class="task-progress">0%</span>
        <div class="task-bar" style="width: 0%"></div>
      `;
      tasksList.appendChild(task);
      updateTasksEmpty();
      
      // Switch to tasks tab
      const tasksTab = document.querySelector('.panel-tab[data-tab="tasks"]');
      if (tasksTab) tasksTab.click();
      
      const taskHandle = {
        setProgress(percent) {
          task.querySelector(".task-progress").textContent = `${Math.round(percent)}%`;
          task.querySelector(".task-bar").style.width = `${percent}%`;
        },
        setComplete() {
          task.classList.add("complete");
          task.querySelector(".task-progress").textContent = "Done";
          task.querySelector(".task-bar").style.width = "100%";
          // Remove after delay
          setTimeout(() => {
            task.remove();
            updateTasksEmpty();
          }, 3000);
        },
        setError(msg) {
          task.classList.add("error");
          task.querySelector(".task-progress").textContent = msg || "Failed";
          // Remove after delay
          setTimeout(() => {
            task.remove();
            updateTasksEmpty();
          }, 5000);
        }
      };
      
      // Store fetch tasks for WebSocket updates
      if (fetchId) {
        fetchTasks.set(fetchId, taskHandle);
      }
      
      return taskHandle;
    }
    
    function uploadFile(file) {
      return new Promise((resolve) => {
        const task = createTask(file.name);
        const xhr = new XMLHttpRequest();
        const formData = new FormData();
        formData.append("file", file);
        
        xhr.upload.onprogress = (e) => {
          if (e.lengthComputable) {
            const percent = (e.loaded / e.total) * 100;
            task.setProgress(percent);
          }
        };
        
        xhr.onload = () => {
          if (xhr.status === 200) {
            task.setComplete();
            resolve({ success: true });
          } else if (xhr.status === 409) {
            task.setError("Duplicate");
            resolve({ success: false, duplicate: true });
          } else {
            task.setError("Failed");
            resolve({ success: false });
          }
        };
        
        xhr.onerror = () => {
          task.setError("Error");
          resolve({ success: false });
        };
        
        xhr.open("POST", "/api/upload");
        xhr.send(formData);
      });
    }
    
    async function uploadFiles(files) {
      const validExts = [".mp3", ".ogg", ".flac", ".wav", ".m4a", ".aac", ".opus", ".wma", ".mp4"];
      const audioFiles = [...files].filter(f => {
        const ext = f.name.toLowerCase().match(/\.[^.]+$/)?.[0];
        return ext && validExts.includes(ext);
      });
      
      if (audioFiles.length === 0) {
        M.showToast("No valid audio files");
        return;
      }
      
      let uploaded = 0;
      let failed = 0;
      
      // Upload files in parallel (max 3 concurrent)
      const concurrency = 3;
      const queue = [...audioFiles];
      const active = [];
      
      while (queue.length > 0 || active.length > 0) {
        while (active.length < concurrency && queue.length > 0) {
          const file = queue.shift();
          const promise = uploadFile(file).then(result => {
            if (result.success) uploaded++;
            else failed++;
            active.splice(active.indexOf(promise), 1);
          });
          active.push(promise);
        }
        if (active.length > 0) {
          await Promise.race(active);
        }
      }
      
      if (uploaded > 0) {
        M.showToast(`Uploaded ${uploaded} track${uploaded > 1 ? 's' : ''}${failed > 0 ? `, ${failed} failed` : ''}`);
      } else if (failed > 0) {
        M.showToast(`Upload failed`);
      }
    }
  });
})();
