/**
 * ================================================================
 * NEOMORPH PLAYER – admin.js
 * Logika halaman admin untuk mengelola playlist musik
 * ================================================================
 * Fitur:
 *  - Dashboard statistik (total lagu, genre, durasi, artis)
 *  - Tabel lagu: tampil, cari, filter genre, sort kolom
 *  - Drag-and-drop urutan lagu
 *  - Tambah lagu baru (form + validasi)
 *  - Edit lagu (isi ulang form)
 *  - Hapus lagu (konfirmasi modal)
 *  - Hapus banyak lagu sekaligus
 *  - Export playlist ke JSON
 *  - Import playlist dari JSON
 *  - Reset ke playlist default
 *  - Preview cover canvas realtime
 *  - Preset warna gradient
 *  - Dark / Light mode
 *  - Semua data dari/ke localStorage (sinkron dengan player)
 * ================================================================
 */

/* ============================================================
   0. PENGAMAN LOGIN (AUTH GUARD)
============================================================ */
if (sessionStorage.getItem('nm_admin_logged_in') !== 'true') {
  window.location.href = 'login.html';
}

/* ============================================================
   1. PLAYLIST DEFAULT (sama dengan script.js player)
   Digunakan sebagai fallback saat reset
============================================================ */
const DEFAULT_PLAYLIST = [
  { id:1, title:"Neon Dreams",    artist:"Synthwave Studio",  album:"Digital Horizons", genre:"Synthwave",  duration:"3:42", durationSec:222, src:"assets/music/song1.mp3", image:"", color1:"#7c5cbf", color2:"#e44d7b" },
  { id:2, title:"Midnight Pulse", artist:"Luna Beats",        album:"Dark Frequency",   genre:"Electronic", duration:"4:15", durationSec:255, src:"assets/music/song2.mp3", image:"", color1:"#06b6d4", color2:"#3b82f6" },
  { id:3, title:"Golden Hour",    artist:"Aria Waves",        album:"Sunset Sessions",  genre:"Chill",      duration:"3:58", durationSec:238, src:"assets/music/song3.mp3", image:"", color1:"#f59e0b", color2:"#ef4444" },
  { id:4, title:"Cosmic Journey", artist:"Stellar Sound",     album:"Universe",         genre:"Ambient",    duration:"5:20", durationSec:320, src:"assets/music/song4.mp3", image:"", color1:"#8b5cf6", color2:"#06b6d4" },
  { id:5, title:"Urban Flow",     artist:"City Beats",        album:"Metropolitan",     genre:"Hip-Hop",    duration:"3:30", durationSec:210, src:"assets/music/song5.mp3", image:"", color1:"#10b981", color2:"#3b82f6" },
  { id:6, title:"Tropical Breeze",artist:"Island Groove",     album:"Paradise",         genre:"Pop",        duration:"2:55", durationSec:175, src:"assets/music/song6.mp3", image:"", color1:"#f97316", color2:"#eab308" },
  { id:7, title:"Deep Space",     artist:"Nebula Orchestra",  album:"Infinity",         genre:"Orchestral", duration:"6:10", durationSec:370, src:"assets/music/song7.mp3", image:"", color1:"#1d4ed8", color2:"#7c3aed" },
  { id:8, title:"Electric Soul",  artist:"Voltage Band",      album:"Power Surge",      genre:"Rock",       duration:"4:02", durationSec:242, src:"assets/music/song8.mp3", image:"", color1:"#dc2626", color2:"#ea580c" }
];

/* ============================================================
   2. PRESET WARNA GRADIENT
============================================================ */
const COLOR_PRESETS = [
  { c1:"#7c5cbf", c2:"#e44d7b", label:"Purple Rose" },
  { c1:"#06b6d4", c2:"#3b82f6", label:"Ocean Blue"  },
  { c1:"#f59e0b", c2:"#ef4444", label:"Sunset"      },
  { c1:"#8b5cf6", c2:"#06b6d4", label:"Aurora"      },
  { c1:"#10b981", c2:"#3b82f6", label:"Emerald Sea" },
  { c1:"#f97316", c2:"#eab308", label:"Golden"      },
  { c1:"#1d4ed8", c2:"#7c3aed", label:"Deep Space"  },
  { c1:"#dc2626", c2:"#ea580c", label:"Fire"        },
  { c1:"#ec4899", c2:"#a855f7", label:"Candy"       },
  { c1:"#14b8a6", c2:"#84cc16", label:"Nature"      }
];

/* ============================================================
   3. STATE
============================================================ */
const adminState = {
  playlist:     [],
  currentPage:  'dashboard',
  sortField:    'title',
  sortAsc:      true,
  filterText:   '',
  filterGenre:  '',
  editingId:    null,          // ID lagu yang sedang diedit
  selectedRows: new Set(),     // Set ID lagu yang dipilih
  dragSrcIndex: null           // Indeks baris yang sedang di-drag
};

/* ============================================================
   4. DOM REFERENSI
============================================================ */
const A = {
  body:          document.getElementById('app-body'),
  themeToggle:   document.getElementById('theme-toggle'),
  themeIcon:     document.getElementById('theme-icon'),
  themeLabel:    document.getElementById('theme-label'),
  sidebarToggle: document.getElementById('sidebar-toggle'),
  sidebar:       document.getElementById('sidebar'),
  sidebarOverlay:document.getElementById('sidebar-overlay'),
  breadcrumb:    document.getElementById('breadcrumb-title'),
  topbarCount:   document.getElementById('topbar-count'),
  toast:         document.getElementById('toast'),
  // Dashboard
  statTotal:     document.getElementById('stat-total'),
  statGenres:    document.getElementById('stat-genres'),
  statDuration:  document.getElementById('stat-duration'),
  statArtists:   document.getElementById('stat-artists'),
  genreList:     document.getElementById('genre-list'),
  recentSongs:   document.getElementById('recent-songs'),
  // Songs table
  adminSearch:   document.getElementById('admin-search'),
  filterGenre:   document.getElementById('filter-genre'),
  songsTbody:    document.getElementById('songs-tbody'),
  tableInfo:     document.getElementById('table-info'),
  bulkActions:   document.getElementById('bulk-actions'),
  selectedCount: document.getElementById('selected-count'),
  songsBadge:    document.getElementById('songs-badge'),
  // Form
  songForm:      document.getElementById('song-form'),
  editId:        document.getElementById('edit-id'),
  fTitle:        document.getElementById('f-title'),
  fArtist:       document.getElementById('f-artist'),
  fAlbum:        document.getElementById('f-album'),
  fGenre:        document.getElementById('f-genre'),
  fDuration:     document.getElementById('f-duration'),
  fDurationSec:  document.getElementById('f-duration-sec'),
  fSrc:          document.getElementById('f-src'),
  fImage:        document.getElementById('f-image'),
  fColor1:       document.getElementById('f-color1'),
  fColor2:       document.getElementById('f-color2'),
  formPageTitle: document.getElementById('form-page-title'),
  formSubmitBtn: document.getElementById('form-submit-btn'),
  previewCanvas: document.getElementById('preview-canvas'),
  previewTitle:  document.getElementById('preview-title'),
  previewArtist: document.getElementById('preview-artist'),
  previewGenre:  document.getElementById('preview-genre'),
  colorPresets:  document.getElementById('color-presets'),
  // Errors
  errTitle:      document.getElementById('err-title'),
  errArtist:     document.getElementById('err-artist'),
  errSrc:        document.getElementById('err-src'),
  // Settings
  importFile:    document.getElementById('import-file'),
  storageStats:  document.getElementById('storage-stats'),
  // Modal
  modalOverlay:  document.getElementById('modal-overlay'),
  modalTitle:    document.getElementById('modal-title'),
  modalBody:     document.getElementById('modal-body'),
  modalConfirm:  document.getElementById('modal-confirm'),
  modalCancel:   document.getElementById('modal-cancel'),
  // Logout
  btnLogout:     document.getElementById('btn-logout')
};

/* ============================================================
   5. INISIALISASI
============================================================ */
function init() {
  loadTheme();
  loadPlaylist();
  renderColorPresets();
  renderDashboard();
  renderSongsTable();
  renderFilterGenre();
  renderStorageStats();
  bindEvents();
  updateTopbar();
  console.log('✅ Admin Panel NeumorphPlayer siap!');
}

/* ============================================================
   6. NAVIGASI HALAMAN
============================================================ */
function navigateTo(page) {
  adminState.currentPage = page;

  // Sembunyikan semua halaman
  document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
  document.getElementById(`page-${page}`).classList.add('active');

  // Update nav aktif
  document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
  const nav = document.getElementById(`nav-${page}`);
  if (nav) nav.classList.add('active');

  // Update breadcrumb
  const labels = {
    'dashboard': 'Dashboard',
    'songs':     'Kelola Lagu',
    'add-song':  'Tambah Lagu',
    'settings':  'Pengaturan'
  };
  A.breadcrumb.textContent = labels[page] || page;

  // Tutup sidebar di mobile
  closeSidebar();

  // Update konten halaman
  if (page === 'dashboard') { renderDashboard(); }
  if (page === 'songs')     { renderSongsTable(); }
  if (page === 'settings')  { renderStorageStats(); }
  if (page === 'add-song' && !adminState.editingId) { resetForm(false); }
}

/* ============================================================
   7. TEMA
============================================================ */
function loadTheme() {
  const saved = localStorage.getItem('nm_theme') || 'light-mode';
  A.body.className = saved;
  updateThemeUI(saved);
}
function toggleTheme() {
  const isDark = A.body.classList.contains('dark-mode');
  const theme  = isDark ? 'light-mode' : 'dark-mode';
  A.body.className = theme;
  localStorage.setItem('nm_theme', theme);
  updateThemeUI(theme);
}
function updateThemeUI(theme) {
  const isDark = theme === 'dark-mode';
  A.themeIcon.className  = isDark ? 'fa-solid fa-sun' : 'fa-solid fa-moon';
  A.themeLabel.textContent = isDark ? 'Mode Terang' : 'Mode Gelap';
}

/* ============================================================
   8. SIDEBAR MOBILE
============================================================ */
function openSidebar() {
  A.sidebar.classList.add('open');
  A.sidebarOverlay.classList.add('show');
  document.body.style.overflow = 'hidden';
}
function closeSidebar() {
  A.sidebar.classList.remove('open');
  A.sidebarOverlay.classList.remove('show');
  document.body.style.overflow = '';
}

/* ============================================================
   9. PLAYLIST – LOAD & SIMPAN
============================================================ */
function loadPlaylist() {
  try {
    const saved = localStorage.getItem('nm_playlist');
    adminState.playlist = saved ? JSON.parse(saved) : JSON.parse(JSON.stringify(DEFAULT_PLAYLIST));
  } catch (e) {
    adminState.playlist = JSON.parse(JSON.stringify(DEFAULT_PLAYLIST));
  }
}

function savePlaylist() {
  localStorage.setItem('nm_playlist', JSON.stringify(adminState.playlist));
  updateTopbar();
  A.songsBadge.textContent = adminState.playlist.length;
}

function updateTopbar() {
  A.topbarCount.textContent = `${adminState.playlist.length} Lagu`;
  A.songsBadge.textContent  = adminState.playlist.length;
}

/* ============================================================
   10. GENERATE ID UNIK
============================================================ */
function generateId() {
  return Date.now() + Math.floor(Math.random() * 1000);
}

/* ============================================================
   11. DASHBOARD
============================================================ */
function renderDashboard() {
  const list = adminState.playlist;

  // Stat cards
  A.statTotal.textContent   = list.length;
  A.statGenres.textContent  = new Set(list.map(s => s.genre)).size;
  A.statArtists.textContent = new Set(list.map(s => s.artist)).size;

  // Total durasi
  const totalSec = list.reduce((sum, s) => sum + (s.durationSec || 0), 0);
  const m = Math.floor(totalSec / 60);
  const s = (totalSec % 60).toString().padStart(2, '0');
  A.statDuration.textContent = m > 60
    ? `${Math.floor(m/60)}j ${m%60}m`
    : `${m}:${s}`;

  // Genre breakdown
  const genreMap = {};
  list.forEach(s => { genreMap[s.genre] = (genreMap[s.genre] || 0) + 1; });
  const maxCount = Math.max(...Object.values(genreMap), 1);

  A.genreList.innerHTML = '';
  Object.entries(genreMap)
    .sort((a, b) => b[1] - a[1])
    .forEach(([genre, count]) => {
      const pct = Math.round((count / maxCount) * 100);
      const div = document.createElement('div');
      div.className = 'genre-item';
      div.innerHTML = `
        <div class="genre-row">
          <span class="genre-name">${escHtml(genre)}</span>
          <span class="genre-count">${count} lagu</span>
        </div>
        <div class="genre-bar-track">
          <div class="genre-bar-fill" style="width:${pct}%"></div>
        </div>
      `;
      A.genreList.appendChild(div);
    });

  if (!Object.keys(genreMap).length) {
    A.genreList.innerHTML = '<p style="color:var(--text-muted);font-size:.82rem">Belum ada lagu</p>';
  }

  // Recent songs (semua lagu)
  A.recentSongs.innerHTML = '';
  list.slice(0, 6).forEach(song => {
    const div = document.createElement('div');
    div.className = 'recent-item';
    div.innerHTML = `
      <div class="recent-cover" style="background:linear-gradient(135deg,${song.color1},${song.color2})">
        <i class="fa-solid fa-music"></i>
      </div>
      <div class="recent-info">
        <div class="recent-title">${escHtml(song.title)}</div>
        <div class="recent-artist">${escHtml(song.artist)}</div>
      </div>
      <div class="recent-dur">${song.duration}</div>
    `;
    A.recentSongs.appendChild(div);
  });

  if (!list.length) {
    A.recentSongs.innerHTML = '<p style="color:var(--text-muted);font-size:.82rem;padding:16px">Belum ada lagu. <a href="#" onclick="navigateTo(\'add-song\')" style="color:var(--accent)">Tambah sekarang →</a></p>';
  }
}

/* ============================================================
   12. RENDER TABEL LAGU
============================================================ */
function renderSongsTable() {
  let list = [...adminState.playlist];

  // Filter teks
  const q = adminState.filterText.toLowerCase();
  if (q) {
    list = list.filter(s =>
      s.title.toLowerCase().includes(q) ||
      s.artist.toLowerCase().includes(q) ||
      s.album.toLowerCase().includes(q) ||
      s.genre.toLowerCase().includes(q)
    );
  }

  // Filter genre
  if (adminState.filterGenre) {
    list = list.filter(s => s.genre === adminState.filterGenre);
  }

  // Sort
  list.sort((a, b) => {
    const va = String(a[adminState.sortField] || '').toLowerCase();
    const vb = String(b[adminState.sortField] || '').toLowerCase();
    return adminState.sortAsc ? va.localeCompare(vb) : vb.localeCompare(va);
  });

  A.songsTbody.innerHTML = '';
  A.tableInfo.textContent = `${list.length} lagu ditampilkan`;

  if (!list.length) {
    A.songsTbody.innerHTML = `
      <tr><td colspan="9">
        <div class="empty-table">
          <i class="fa-solid fa-music-slash"></i>
          <p>Tidak ada lagu ditemukan</p>
        </div>
      </td></tr>
    `;
    return;
  }

  list.forEach((song, idx) => {
    const realIndex = adminState.playlist.findIndex(s => s.id === song.id);
    const isChecked = adminState.selectedRows.has(song.id);
    const tr = document.createElement('tr');
    tr.dataset.id    = song.id;
    tr.dataset.index = realIndex;
    tr.className     = isChecked ? 'selected-row' : '';
    tr.draggable     = true;
    tr.style.animationDelay = `${idx * 0.03}s`;

    tr.innerHTML = `
      <td class="col-drag">
        <div class="drag-handle" title="Seret untuk urutan">
          <i class="fa-solid fa-grip-vertical"></i>
        </div>
      </td>
      <td class="col-num">
        <input type="checkbox" class="row-check" ${isChecked ? 'checked' : ''}
          aria-label="Pilih ${escHtml(song.title)}" />
      </td>
      <td class="col-cover">
        <div class="table-cover"
             style="background:linear-gradient(135deg,${song.color1},${song.color2})">
          <i class="fa-solid fa-music"></i>
        </div>
      </td>
      <td class="col-title">${escHtml(song.title)}</td>
      <td class="col-artist">${escHtml(song.artist)}</td>
      <td class="col-album">${escHtml(song.album || '–')}</td>
      <td class="col-genre">
        <span class="genre-badge">${escHtml(song.genre || '–')}</span>
      </td>
      <td class="col-dur">${song.duration}</td>
      <td class="col-actions">
        <div class="row-actions">
          <button class="row-btn edit" title="Edit lagu" onclick="editSong(${song.id})">
            <i class="fa-solid fa-pen-to-square"></i>
          </button>
          <button class="row-btn delete" title="Hapus lagu" onclick="deleteSong(${song.id})">
            <i class="fa-solid fa-trash"></i>
          </button>
        </div>
      </td>
    `;

    // Checkbox change
    tr.querySelector('.row-check').addEventListener('change', (e) => {
      if (e.target.checked) {
        adminState.selectedRows.add(song.id);
        tr.classList.add('selected-row');
      } else {
        adminState.selectedRows.delete(song.id);
        tr.classList.remove('selected-row');
      }
      updateBulkActions();
    });

    // Drag events
    tr.addEventListener('dragstart', (e) => {
      adminState.dragSrcIndex = realIndex;
      tr.classList.add('dragging');
      e.dataTransfer.effectAllowed = 'move';
    });
    tr.addEventListener('dragend', () => {
      tr.classList.remove('dragging');
      document.querySelectorAll('tr.drag-over').forEach(r => r.classList.remove('drag-over'));
    });
    tr.addEventListener('dragover', (e) => {
      e.preventDefault();
      e.dataTransfer.dropEffect = 'move';
      document.querySelectorAll('tr.drag-over').forEach(r => r.classList.remove('drag-over'));
      tr.classList.add('drag-over');
    });
    tr.addEventListener('drop', (e) => {
      e.preventDefault();
      const targetIndex = parseInt(tr.dataset.index);
      if (adminState.dragSrcIndex !== null && adminState.dragSrcIndex !== targetIndex) {
        reorderPlaylist(adminState.dragSrcIndex, targetIndex);
      }
    });

    A.songsTbody.appendChild(tr);
  });

  updateBulkActions();
}

/* ============================================================
   13. RENDER FILTER GENRE
============================================================ */
function renderFilterGenre() {
  const genres = [...new Set(adminState.playlist.map(s => s.genre).filter(Boolean))].sort();
  A.filterGenre.innerHTML = '<option value="">Semua Genre</option>';
  genres.forEach(g => {
    const opt = document.createElement('option');
    opt.value = g; opt.textContent = g;
    if (g === adminState.filterGenre) opt.selected = true;
    A.filterGenre.appendChild(opt);
  });
}

/* ============================================================
   14. BULK ACTIONS (hapus banyak)
============================================================ */
function updateBulkActions() {
  const count = adminState.selectedRows.size;
  if (count > 0) {
    A.bulkActions.style.display = 'flex';
    A.selectedCount.textContent = count;
  } else {
    A.bulkActions.style.display = 'none';
  }
}

function deleteSelected() {
  const count = adminState.selectedRows.size;
  if (!count) return;
  showModal(
    '⚠️ Hapus Lagu Terpilih',
    `Hapus ${count} lagu yang dipilih? Tindakan ini tidak dapat dibatalkan.`,
    () => {
      adminState.playlist = adminState.playlist.filter(s => !adminState.selectedRows.has(s.id));
      adminState.selectedRows.clear();
      savePlaylist();
      renderSongsTable();
      renderFilterGenre();
      showToast(`🗑️ ${count} lagu berhasil dihapus`);
    }
  );
}

/* ============================================================
   15. DRAG-AND-DROP URUTAN LAGU
============================================================ */
function reorderPlaylist(fromIdx, toIdx) {
  const item = adminState.playlist.splice(fromIdx, 1)[0];
  adminState.playlist.splice(toIdx, 0, item);
  savePlaylist();
  renderSongsTable();
  showToast('↕️ Urutan lagu diperbarui');
}

/* ============================================================
   16. FORM TAMBAH / EDIT LAGU
   (resetForm didefinisikan di bagian bawah – seksi 34 –
    agar sekaligus membersihkan UI upload audio & gambar)
============================================================ */

function editSong(id) {
  const song = adminState.playlist.find(s => s.id === id);
  if (!song) return;

  adminState.editingId = id;
  A.editId.value = id;

  // Isi form
  A.fTitle.value       = song.title;
  A.fArtist.value      = song.artist;
  A.fAlbum.value       = song.album || '';
  A.fGenre.value       = song.genre || '';
  A.fDuration.value    = song.duration || '';
  A.fDurationSec.value = song.durationSec || '';
  A.fColor1.value      = song.color1 || '#7c5cbf';
  A.fColor2.value      = song.color2 || '#e44d7b';

  // Pisahkan prefix dari path
  A.fSrc.value   = song.src   ? song.src.replace('assets/music/', '')   : '';
  A.fImage.value = song.image ? song.image.replace('assets/images/', '') : '';

  A.formPageTitle.textContent = '✏️ Edit Lagu';
  A.formSubmitBtn.innerHTML   = '<i class="fa-solid fa-floppy-disk"></i> Perbarui Lagu';
  clearErrors();
  updatePreview();
  navigateTo('add-song');
}

function deleteSong(id) {
  const song = adminState.playlist.find(s => s.id === id);
  if (!song) return;
  showModal(
    '⚠️ Hapus Lagu',
    `Hapus "${song.title}" oleh ${song.artist}? Tindakan ini tidak dapat dibatalkan.`,
    () => {
      adminState.playlist = adminState.playlist.filter(s => s.id !== id);
      savePlaylist();
      renderSongsTable();
      renderFilterGenre();
      renderDashboard();
      showToast(`🗑️ "${song.title}" dihapus`);
    }
  );
}

/* ============================================================
   17. VALIDASI FORM
============================================================ */
function validateForm() {
  let ok = true;
  clearErrors();

  if (!A.fTitle.value.trim()) {
    setError('err-title', 'Judul lagu wajib diisi');
    A.fTitle.classList.add('error');
    ok = false;
  }
  if (!A.fArtist.value.trim()) {
    setError('err-artist', 'Nama artis wajib diisi');
    A.fArtist.classList.add('error');
    ok = false;
  }
  if (!A.fSrc.value.trim()) {
    setError('err-src', 'Path file audio wajib diisi');
    ok = false;
  }

  // Validasi format durasi
  const dur = A.fDuration.value.trim();
  if (dur && !/^\d+:[0-5]\d$/.test(dur)) {
    setError('err-title', 'Format durasi salah. Contoh: 3:45');
    ok = false;
  }

  return ok;
}

function setError(id, msg) {
  document.getElementById(id).textContent = msg;
}

function clearErrors() {
  ['err-title','err-artist','err-src'].forEach(id => {
    document.getElementById(id).textContent = '';
  });
  document.querySelectorAll('.neu-input.error').forEach(el => el.classList.remove('error'));
}

/* ============================================================
   18. SUBMIT FORM (Tambah / Edit)
============================================================ */
async function handleFormSubmit(e) {
  e.preventDefault();
  if (!validateForm()) return;

  // Ubah status tombol menjadi loading
  const originalBtnContent = A.formSubmitBtn.innerHTML;
  A.formSubmitBtn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Mengupload...';
  A.formSubmitBtn.disabled = true;

  try {
    // 1. Siapkan FormData untuk mengirim file fisik ke upload.php
    const formData = new FormData();
    const audioInput = document.getElementById('file-audio-input');
    const imageInput = document.getElementById('file-image-input');
    
    if (audioInput.files[0]) {
      formData.append('audio', audioInput.files[0]);
    }
    if (imageInput.files[0]) {
      formData.append('image', imageInput.files[0]);
    }
    if (adminState.editingId) {
      formData.append('is_edit', 'true');
    }

    // 2. Kirim via AJAX ke upload.php (hanya jika ada file yang perlu diupload)
    if (audioInput.files[0] || imageInput.files[0]) {
      const response = await fetch('upload.php', {
        method: 'POST',
        body: formData
      });
      
      const result = await response.json();
      if (!result.success) {
        throw new Error(result.message || 'Gagal mengupload file ke server');
      }
      
      // Jika server mengembalikan path baru, kita gunakan path tersebut
      if (result.audio) A.fSrc.value = result.audio.replace('assets/music/', '');
      if (result.image) A.fImage.value = result.image.replace('assets/images/', '');
    }

    // 3. Hitung durationSec dari format menit:detik
    let durSec = parseInt(A.fDurationSec.value) || 0;
    const durStr = A.fDuration.value.trim();
    if (durStr && /^\d+:[0-5]\d$/.test(durStr)) {
      const [m, s] = durStr.split(':').map(Number);
      durSec = m * 60 + s;
    }

    // 4. Siapkan data lagu untuk disimpan di localStorage
    const songData = {
      title:       A.fTitle.value.trim(),
      artist:      A.fArtist.value.trim(),
      album:       A.fAlbum.value.trim(),
      genre:       A.fGenre.value.trim() || 'Lainnya',
      duration:    A.fDuration.value.trim() || formatSecToMin(durSec),
      durationSec: durSec,
      src:         'assets/music/' + A.fSrc.value.trim(),
      image:       A.fImage.value.trim() ? 'assets/images/' + A.fImage.value.trim() : '',
      color1:      A.fColor1.value,
      color2:      A.fColor2.value
    };

    if (adminState.editingId) {
      // MODE EDIT
      const idx = adminState.playlist.findIndex(s => s.id === adminState.editingId);
      if (idx !== -1) {
        adminState.playlist[idx] = { ...adminState.playlist[idx], ...songData };
        showToast(`✅ "${songData.title}" berhasil diperbarui`);
      }
      adminState.editingId = null;
      A.formPageTitle.textContent = 'Tambah Lagu Baru';
    } else {
      // MODE TAMBAH
      songData.id = generateId();
      adminState.playlist.push(songData);
      showToast(`✅ "${songData.title}" berhasil ditambahkan & diupload!`);
    }

    // 5. Simpan dan update UI
    savePlaylist();
    renderSongsTable();
    renderFilterGenre();
    renderDashboard();
    resetForm(false);
    navigateTo('songs');

  } catch (error) {
    console.error('Upload Error:', error);
    showModal('❌ Gagal Mengupload', error.message, () => {}, 'danger');
  } finally {
    // Kembalikan status tombol
    A.formSubmitBtn.innerHTML = originalBtnContent;
    A.formSubmitBtn.disabled = false;
  }
}

/* Konversi detik ke format m:ss */
function formatSecToMin(sec) {
  if (!sec) return '0:00';
  const m = Math.floor(sec / 60);
  const s = (sec % 60).toString().padStart(2, '0');
  return `${m}:${s}`;
}

/* ============================================================
   19. AUTO-FILL DURASI DETIK
============================================================ */
A.fDuration.addEventListener('input', () => {
  const val = A.fDuration.value.trim();
  if (/^\d+:[0-5]\d$/.test(val)) {
    const [m, s] = val.split(':').map(Number);
    A.fDurationSec.value = m * 60 + s;
  }
});

A.fDurationSec.addEventListener('input', () => {
  const sec = parseInt(A.fDurationSec.value);
  if (!isNaN(sec) && sec > 0 && !A.fDuration.value) {
    A.fDuration.value = formatSecToMin(sec);
  }
});

/* ============================================================
   20. CANVAS PREVIEW COVER
============================================================ */
function updatePreview() {
  const title  = A.fTitle.value.trim()  || 'Judul Lagu';
  const artist = A.fArtist.value.trim() || 'Nama Artis';
  const genre  = A.fGenre.value.trim()  || 'Genre';
  const c1     = A.fColor1.value;
  const c2     = A.fColor2.value;

  A.previewTitle.textContent  = title;
  A.previewArtist.textContent = artist;
  A.previewGenre.textContent  = genre;

  const canvas = A.previewCanvas;
  const ctx    = canvas.getContext('2d');
  const W = canvas.width, H = canvas.height;
  const cx = W/2, cy = H/2, r = W/2;

  ctx.clearRect(0, 0, W, H);
  ctx.save();
  ctx.beginPath();
  ctx.arc(cx, cy, r, 0, Math.PI*2);
  ctx.closePath();
  ctx.clip();

  // Gradient
  const grad = ctx.createRadialGradient(cx*0.6, cy*0.6, 0, cx, cy, r);
  grad.addColorStop(0, c1);
  grad.addColorStop(1, c2);
  ctx.fillStyle = grad;
  ctx.fillRect(0, 0, W, H);

  // Dekorasi lingkaran
  ctx.globalAlpha = 0.1;
  for (let i=0; i<4; i++) {
    ctx.beginPath();
    ctx.arc(cx + (i-2)*15, cy + (i-2)*8, r*(0.3+i*0.15), 0, Math.PI*2);
    ctx.strokeStyle = '#fff'; ctx.lineWidth = 2; ctx.stroke();
  }

  // Ikon musik
  ctx.globalAlpha = 0.9;
  ctx.fillStyle = 'rgba(255,255,255,0.85)';
  ctx.font = `bold ${W*0.3}px serif`;
  ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
  ctx.fillText('♪', cx, cy);

  ctx.restore();

  // Vinyl overlay
  ctx.save();
  ctx.beginPath(); ctx.arc(cx,cy,r-1,0,Math.PI*2);
  ctx.strokeStyle='rgba(0,0,0,0.2)'; ctx.lineWidth=3; ctx.stroke();
  ctx.beginPath(); ctx.arc(cx,cy,r*0.12,0,Math.PI*2);
  ctx.fillStyle='rgba(0,0,0,0.5)'; ctx.fill();
  ctx.beginPath(); ctx.arc(cx,cy,r*0.06,0,Math.PI*2);
  ctx.fillStyle='rgba(255,255,255,0.7)'; ctx.fill();
  ctx.restore();
}

/* ============================================================
   21. PRESET WARNA
============================================================ */
function renderColorPresets() {
  A.colorPresets.innerHTML = '';
  COLOR_PRESETS.forEach((preset, i) => {
    const btn = document.createElement('button');
    btn.type = 'button';
    btn.className = 'preset-swatch';
    btn.title = preset.label;
    btn.style.background = `linear-gradient(135deg,${preset.c1},${preset.c2})`;
    btn.addEventListener('click', () => {
      A.fColor1.value = preset.c1;
      A.fColor2.value = preset.c2;
      updatePreview();
      document.querySelectorAll('.preset-swatch').forEach(b => b.classList.remove('active'));
      btn.classList.add('active');
    });
    A.colorPresets.appendChild(btn);
  });
}

/* ============================================================
   22. EXPORT / IMPORT PLAYLIST
============================================================ */
function exportPlaylist() {
  const json   = JSON.stringify(adminState.playlist, null, 2);
  const blob   = new Blob([json], { type: 'application/json' });
  const url    = URL.createObjectURL(blob);
  const a      = document.createElement('a');
  a.href       = url;
  a.download   = `neumorphplayer-playlist-${Date.now()}.json`;
  a.click();
  URL.revokeObjectURL(url);
  showToast('📥 Playlist berhasil diexport!');
}

function triggerImport() {
  A.importFile.click();
}

function handleImport(e) {
  const file = e.target.files[0];
  if (!file) return;

  const reader = new FileReader();
  reader.onload = (evt) => {
    try {
      const data = JSON.parse(evt.target.result);
      if (!Array.isArray(data)) throw new Error('Format tidak valid');

      showModal(
        '📥 Import Playlist',
        `Ditemukan ${data.length} lagu. Ini akan MENGGANTIKAN playlist saat ini. Lanjutkan?`,
        () => {
          // Validasi minimal field
          adminState.playlist = data.map((s, i) => ({
            id:          s.id || generateId() + i,
            title:       s.title || 'Lagu Tanpa Judul',
            artist:      s.artist || 'Artis Unknown',
            album:       s.album || '',
            genre:       s.genre || 'Lainnya',
            duration:    s.duration || '0:00',
            durationSec: s.durationSec || 0,
            src:         s.src || '',
            image:       s.image || '',
            color1:      s.color1 || '#7c5cbf',
            color2:      s.color2 || '#e44d7b'
          }));
          savePlaylist();
          renderSongsTable();
          renderFilterGenre();
          renderDashboard();
          showToast(`✅ ${data.length} lagu berhasil diimport!`);
        }
      );
    } catch (err) {
      showToast('❌ File JSON tidak valid!');
    }
    e.target.value = '';
  };
  reader.readAsText(file);
}

/* ============================================================
   23. RESET KE DEFAULT
============================================================ */
function confirmResetPlaylist() {
  showModal(
    '⚠️ Reset Playlist',
    `Ini akan menghapus SEMUA lagu dan mengembalikan ke ${DEFAULT_PLAYLIST.length} lagu bawaan. Lanjutkan?`,
    () => {
      adminState.playlist = JSON.parse(JSON.stringify(DEFAULT_PLAYLIST));
      adminState.selectedRows.clear();
      savePlaylist();
      renderSongsTable();
      renderFilterGenre();
      renderDashboard();
      renderStorageStats();
      showToast('🔄 Playlist direset ke default');
    }
  );
}

/* ============================================================
   24. HAPUS CACHE / localStorage
============================================================ */
function clearCache() {
  showModal(
    '⚠️ Hapus Cache',
    'Semua data localStorage (playlist, tema, indeks) akan dihapus. Halaman akan dimuat ulang.',
    () => {
      ['nm_playlist','nm_theme','nm_index','nm_volume'].forEach(k => localStorage.removeItem(k));
      showToast('🗑️ Cache dihapus. Memuat ulang…');
      setTimeout(() => location.reload(), 1200);
    },
    'danger'
  );
}

/* ============================================================
   25. INFO STORAGE
============================================================ */
function renderStorageStats() {
  const keys = ['nm_playlist', 'nm_theme', 'nm_index', 'nm_volume'];
  let html = '';
  keys.forEach(k => {
    const val = localStorage.getItem(k);
    const size = val ? new Blob([val]).size : 0;
    html += `
      <div class="storage-item">
        <span class="storage-key">${k}
          <span style="color:var(--text-muted);font-weight:400"> (${size > 0 ? (size/1024).toFixed(2)+' KB' : 'kosong'})</span>
        </span>
        <span class="storage-val">${val ? (val.length > 80 ? val.slice(0,80)+'…' : val) : '–'}</span>
      </div>
    `;
  });
  A.storageStats.innerHTML = html || '<p style="color:var(--text-muted)">Tidak ada data</p>';
}

/* ============================================================
   26. MODAL KONFIRMASI
============================================================ */
let modalCallback = null;
function showModal(title, body, onConfirm, type = 'warning') {
  A.modalTitle.textContent = title;
  A.modalBody.textContent  = body;
  modalCallback = onConfirm;
  A.modalOverlay.classList.add('show');

  // Warna ikon sesuai tipe
  const icon = A.modalOverlay.querySelector('.modal-icon');
  const confirmBtn = A.modalConfirm;
  if (type === 'danger') {
    icon.style.color = 'var(--danger)';
    confirmBtn.className = 'btn-action danger';
  } else {
    icon.style.color = '#f59e0b';
    confirmBtn.className = 'btn-action danger';
  }
}
function closeModal() {
  A.modalOverlay.classList.remove('show');
  modalCallback = null;
}

/* ============================================================
   27. TOAST
============================================================ */
let toastTimer = null;
function showToast(msg, dur = 2800) {
  clearTimeout(toastTimer);
  A.toast.textContent = msg;
  A.toast.classList.add('show');
  toastTimer = setTimeout(() => A.toast.classList.remove('show'), dur);
}

/* ============================================================
   28. ESCAPE HTML
============================================================ */
function escHtml(str) {
  return String(str || '')
    .replace(/&/g,'&amp;').replace(/</g,'&lt;')
    .replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}

/* ============================================================
   29. BIND SEMUA EVENTS
============================================================ */
function bindEvents() {
  /* ── Tema ──────────────────────────────────────────── */
  A.themeToggle.addEventListener('click', toggleTheme);

  /* ── Sidebar Mobile ────────────────────────────────── */
  A.sidebarToggle.addEventListener('click', openSidebar);
  A.sidebarOverlay.addEventListener('click', closeSidebar);

  /* ── Logout ────────────────────────────────────────── */
  if (A.btnLogout) {
    A.btnLogout.addEventListener('click', () => {
      sessionStorage.removeItem('nm_admin_logged_in');
      window.location.href = 'login.html';
    });
  }

  /* ── Navigasi Sidebar ──────────────────────────────── */
  document.querySelectorAll('.nav-item').forEach(item => {
    item.addEventListener('click', (e) => {
      e.preventDefault();
      navigateTo(item.dataset.page);
    });
  });

  /* ── Form Lagu ─────────────────────────────────────── */
  A.songForm.addEventListener('submit', handleFormSubmit);

  /* ── Preview Realtime ──────────────────────────────── */
  [A.fTitle, A.fArtist, A.fGenre, A.fColor1, A.fColor2].forEach(el => {
    el.addEventListener('input', updatePreview);
  });

  /* ── Pencarian & Filter Tabel ──────────────────────── */
  A.adminSearch.addEventListener('input', (e) => {
    adminState.filterText = e.target.value;
    renderSongsTable();
  });
  A.filterGenre.addEventListener('change', (e) => {
    adminState.filterGenre = e.target.value;
    renderSongsTable();
  });

  /* ── Sort Kolom Tabel ──────────────────────────────── */
  document.querySelectorAll('.songs-table th[data-sort]').forEach(th => {
    th.addEventListener('click', () => {
      const field = th.dataset.sort;
      if (adminState.sortField === field) {
        adminState.sortAsc = !adminState.sortAsc;
      } else {
        adminState.sortField = field;
        adminState.sortAsc = true;
      }
      renderSongsTable();
    });
  });

  /* ── Import File ────────────────────────────────────── */
  A.importFile.addEventListener('change', handleImport);

  /* ── Modal ─────────────────────────────────────────── */
  A.modalConfirm.addEventListener('click', () => {
    if (modalCallback) modalCallback();
    closeModal();
  });
  A.modalCancel.addEventListener('click', closeModal);
  A.modalOverlay.addEventListener('click', (e) => {
    if (e.target === A.modalOverlay) closeModal();
  });

  /* ── Keyboard Escape ────────────────────────────────── */
  document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape') closeModal();
  });

  /* ── Upload File Audio ──────────────────────────────── */
  bindAudioUpload();

  /* ── Upload Gambar Cover ────────────────────────────── */
  bindImageUpload();

  /* ── Inisialisasi Preview ───────────────────────────── */
  updatePreview();
}

/* ============================================================
   30. UPLOAD FILE AUDIO – Event Binding & Handler
============================================================ */
function bindAudioUpload() {
  const fileInput  = document.getElementById('file-audio-input');
  const dropZone   = document.getElementById('audio-drop-zone');
  const pickBtn    = document.getElementById('btn-pick-audio');

  if (!fileInput || !dropZone) return;

  /* Klik drop zone → buka file picker */
  dropZone.addEventListener('click', () => fileInput.click());

  /* File dipilih via picker */
  fileInput.addEventListener('change', (e) => {
    if (e.target.files[0]) handleAudioFile(e.target.files[0]);
  });

  /* Drag events pada drop zone */
  dropZone.addEventListener('dragenter', (e) => {
    e.preventDefault();
    dropZone.classList.add('drag-active');
  });
  dropZone.addEventListener('dragover', (e) => {
    e.preventDefault();
    dropZone.classList.add('drag-active');
  });
  dropZone.addEventListener('dragleave', (e) => {
    if (!dropZone.contains(e.relatedTarget))
      dropZone.classList.remove('drag-active');
  });
  dropZone.addEventListener('drop', (e) => {
    e.preventDefault();
    dropZone.classList.remove('drag-active');
    const file = e.dataTransfer.files[0];
    if (file && file.type.startsWith('audio/')) {
      handleAudioFile(file);
    } else {
      showToast('❌ File bukan format audio yang valid!');
    }
  });
}

/* Proses file audio yang dipilih */
function handleAudioFile(file) {
  /* Isi input nama file */
  A.fSrc.value = file.name;

  /* Auto-isi durasi dari metadata audio */
  const tempAudio = new Audio();
  const objectUrl = URL.createObjectURL(file);
  tempAudio.src   = objectUrl;
  tempAudio.addEventListener('loadedmetadata', () => {
    const sec = Math.round(tempAudio.duration);
    if (sec && isFinite(sec)) {
      A.fDurationSec.value = sec;
      A.fDuration.value    = formatSecToMin(sec);
    }
    URL.revokeObjectURL(objectUrl);
  });

  /* Auto-isi metadata ID3 (Judul, Artis, Album, Genre) menggunakan jsmediatags */
  if (window.jsmediatags) {
    jsmediatags.read(file, {
      onSuccess: function(tag) {
        const tags = tag.tags;
        let changed = false;
        
        if (tags.title) {
          A.fTitle.value = tags.title;
          changed = true;
        } else {
          // Fallback: gunakan nama file tanpa ekstensi sebagai judul
          A.fTitle.value = file.name.replace(/\.[^/.]+$/, "");
          changed = true;
        }
        
        if (tags.artist) {
          A.fArtist.value = tags.artist;
          changed = true;
        }
        
        if (tags.album) {
          A.fAlbum.value = tags.album;
        }
        
        if (tags.genre) {
          A.fGenre.value = tags.genre;
        }

        if (changed) updatePreview();
        showToast(`🏷️ Metadata berhasil diambil dari ${file.name}`);
      },
      onError: function(error) {
        console.warn('Gagal membaca ID3 tags:', error.info);
        // Fallback: gunakan nama file jika gagal
        if (!A.fTitle.value) {
          A.fTitle.value = file.name.replace(/\.[^/.]+$/, "");
          updatePreview();
        }
      }
    });
  } else {
    // Jika jsmediatags gagal dimuat
    if (!A.fTitle.value) {
      A.fTitle.value = file.name.replace(/\.[^/.]+$/, "");
      updatePreview();
    }
  }

  /* Tampilkan preview box, sembunyikan drop zone */
  const previewBox  = document.getElementById('audio-preview-box');
  const dropZone    = document.getElementById('audio-drop-zone');
  const nameEl      = document.getElementById('audio-preview-name');
  const sizeEl      = document.getElementById('audio-preview-size');
  const playerEl    = document.getElementById('audio-preview-player');
  const pickBtn     = document.getElementById('btn-pick-audio');

  nameEl.textContent = file.name;
  sizeEl.textContent = formatFileSize(file.size);

  /* Set sumber audio preview ke blob URL */
  playerEl.src = URL.createObjectURL(file);

  previewBox.style.display  = 'block';
  dropZone.style.display    = 'none';
  pickBtn.classList.add('has-file');
  pickBtn.innerHTML = '<i class="fa-solid fa-check"></i><span>Terpilih</span>';
}

/* Hapus file audio yang dipilih */
function clearAudioFile() {
  const fileInput  = document.getElementById('file-audio-input');
  const previewBox = document.getElementById('audio-preview-box');
  const dropZone   = document.getElementById('audio-drop-zone');
  const playerEl   = document.getElementById('audio-preview-player');
  const pickBtn    = document.getElementById('btn-pick-audio');

  /* Hentikan & bersihkan audio preview */
  if (playerEl.src) {
    playerEl.pause();
    URL.revokeObjectURL(playerEl.src);
    playerEl.src = '';
  }

  fileInput.value           = '';
  previewBox.style.display  = 'none';
  dropZone.style.display    = 'flex';
  pickBtn.classList.remove('has-file');
  pickBtn.innerHTML = '<i class="fa-solid fa-folder-open"></i><span>Pilih File</span>';

  /* Hanya reset input jika nama file cocok */
  showToast('🗑️ File audio dihapus dari pilihan');
}

/* ============================================================
   31. UPLOAD GAMBAR COVER – Event Binding & Handler
============================================================ */
function bindImageUpload() {
  const fileInput = document.getElementById('file-image-input');
  const dropZone  = document.getElementById('image-drop-zone');
  const pickBtn   = document.getElementById('btn-pick-image');

  if (!fileInput || !dropZone) return;

  /* Klik drop zone → buka file picker */
  dropZone.addEventListener('click', () => fileInput.click());

  /* File dipilih via picker */
  fileInput.addEventListener('change', (e) => {
    if (e.target.files[0]) handleImageFile(e.target.files[0]);
  });

  /* Drag events pada drop zone */
  dropZone.addEventListener('dragenter', (e) => {
    e.preventDefault();
    dropZone.classList.add('drag-active');
  });
  dropZone.addEventListener('dragover', (e) => {
    e.preventDefault();
    dropZone.classList.add('drag-active');
  });
  dropZone.addEventListener('dragleave', (e) => {
    if (!dropZone.contains(e.relatedTarget))
      dropZone.classList.remove('drag-active');
  });
  dropZone.addEventListener('drop', (e) => {
    e.preventDefault();
    dropZone.classList.remove('drag-active');
    const file = e.dataTransfer.files[0];
    if (file && file.type.startsWith('image/')) {
      handleImageFile(file);
    } else {
      showToast('❌ File bukan format gambar yang valid!');
    }
  });
}

/* Proses file gambar yang dipilih */
function handleImageFile(file) {
  const reader = new FileReader();
  reader.onload = (e) => {
    const previewBox  = document.getElementById('image-preview-box');
    const dropZone    = document.getElementById('image-drop-zone');
    const thumb       = document.getElementById('image-preview-thumb');
    const nameEl      = document.getElementById('image-preview-name');
    const sizeEl      = document.getElementById('image-preview-size');
    const pickBtn     = document.getElementById('btn-pick-image');

    /* Isi input nama file */
    A.fImage.value = file.name;

    /* Tampilkan thumbnail */
    thumb.src = e.target.result;
    nameEl.textContent = file.name;
    sizeEl.textContent = formatFileSize(file.size);

    previewBox.style.display = 'block';
    dropZone.style.display   = 'none';
    pickBtn.classList.add('has-file');
    pickBtn.innerHTML = '<i class="fa-solid fa-check"></i><span>Terpilih</span>';

    /* Update preview canvas menggunakan gambar yang dipilih */
    updatePreviewWithImage(e.target.result);

    showToast(`🖼️ "${file.name}" dipilih sebagai cover`);
  };
  reader.readAsDataURL(file);
}

/* Hapus gambar yang dipilih */
function clearImageFile() {
  const fileInput  = document.getElementById('file-image-input');
  const previewBox = document.getElementById('image-preview-box');
  const dropZone   = document.getElementById('image-drop-zone');
  const thumb      = document.getElementById('image-preview-thumb');
  const pickBtn    = document.getElementById('btn-pick-image');

  fileInput.value           = '';
  thumb.src                 = '';
  A.fImage.value            = '';
  previewBox.style.display  = 'none';
  dropZone.style.display    = 'flex';
  pickBtn.classList.remove('has-file');
  pickBtn.innerHTML = '<i class="fa-solid fa-folder-open"></i><span>Pilih Gambar</span>';

  /* Kembalikan preview canvas ke mode gradient */
  updatePreview();
  showToast('🗑️ Gambar cover dihapus dari pilihan');
}

/* ============================================================
   32. UPDATE PREVIEW CANVAS DENGAN GAMBAR UPLOAD
============================================================ */
function updatePreviewWithImage(dataUrl) {
  const canvas = A.previewCanvas;
  const ctx    = canvas.getContext('2d');
  const W = canvas.width, H = canvas.height;
  const cx = W/2, cy = H/2, r = W/2;

  const img = new Image();
  img.onload = () => {
    ctx.clearRect(0, 0, W, H);
    ctx.save();
    ctx.beginPath();
    ctx.arc(cx, cy, r, 0, Math.PI*2);
    ctx.closePath();
    ctx.clip();
    ctx.drawImage(img, 0, 0, W, H);
    ctx.restore();

    /* Vinyl overlay */
    ctx.save();
    ctx.beginPath(); ctx.arc(cx,cy,r-1,0,Math.PI*2);
    ctx.strokeStyle='rgba(0,0,0,0.25)'; ctx.lineWidth=3; ctx.stroke();
    ctx.beginPath(); ctx.arc(cx,cy,r*0.12,0,Math.PI*2);
    ctx.fillStyle='rgba(0,0,0,0.5)'; ctx.fill();
    ctx.beginPath(); ctx.arc(cx,cy,r*0.06,0,Math.PI*2);
    ctx.fillStyle='rgba(255,255,255,0.7)'; ctx.fill();
    ctx.restore();
  };
  img.src = dataUrl;
}

/* ============================================================
   33. FORMAT UKURAN FILE
============================================================ */
function formatFileSize(bytes) {
  if (bytes === 0) return '0 B';
  const k     = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB'];
  const i     = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

/* ============================================================
   34. RESET FORM – Termasuk Reset UI Upload Audio & Gambar
============================================================ */
function resetForm(showToastMsg = true) {
  adminState.editingId = null;
  A.editId.value = '';
  A.songForm.reset();
  A.fColor1.value = '#7c5cbf';
  A.fColor2.value = '#e44d7b';
  A.formPageTitle.textContent = 'Tambah Lagu Baru';
  A.formSubmitBtn.innerHTML   = '<i class="fa-solid fa-floppy-disk"></i> Simpan Lagu';
  clearErrors();
  updatePreview();

  /* Reset upload audio UI */
  const audioPreview = document.getElementById('audio-preview-box');
  const audioDrop    = document.getElementById('audio-drop-zone');
  const audioPlayer  = document.getElementById('audio-preview-player');
  const audioPickBtn = document.getElementById('btn-pick-audio');
  const audioInput   = document.getElementById('file-audio-input');
  if (audioPlayer && audioPlayer.src) {
    audioPlayer.pause();
    URL.revokeObjectURL(audioPlayer.src);
    audioPlayer.src = '';
  }
  if (audioInput)   audioInput.value = '';
  if (audioPreview) audioPreview.style.display = 'none';
  if (audioDrop)    audioDrop.style.display    = 'flex';
  if (audioPickBtn) {
    audioPickBtn.classList.remove('has-file');
    audioPickBtn.innerHTML = '<i class="fa-solid fa-folder-open"></i><span>Pilih File</span>';
  }

  /* Reset upload gambar UI */
  const imagePreview = document.getElementById('image-preview-box');
  const imageDrop    = document.getElementById('image-drop-zone');
  const imagePickBtn = document.getElementById('btn-pick-image');
  const imageInput   = document.getElementById('file-image-input');
  const imageThumb   = document.getElementById('image-preview-thumb');
  if (imageThumb)   imageThumb.src = '';
  if (imageInput)   imageInput.value = '';
  if (imagePreview) imagePreview.style.display = 'none';
  if (imageDrop)    imageDrop.style.display    = 'flex';
  if (imagePickBtn) {
    imagePickBtn.classList.remove('has-file');
    imagePickBtn.innerHTML = '<i class="fa-solid fa-folder-open"></i><span>Pilih Gambar</span>';
  }

  if (showToastMsg) showToast('📝 Form direset');
}

/* ============================================================
   35. JALANKAN APLIKASI
============================================================ */
document.addEventListener('DOMContentLoaded', init);

