/* functional/audio/player.js
   Відповідає за:
   - чергу відтворення (playlist або весь список)
   - play/pause, prev/next
   - auto-next по ended
   - збереження стану (volume, queue, index) в localStorage
*/

(function () {
  const LS_QUEUE = 'vm_audio_queue_v1';
  const LS_INDEX = 'vm_audio_index_v1';
  const LS_VOL   = 'vm_audio_vol_v1';

  const elAudio  = document.getElementById('vmAudio');
  const elTitle  = document.getElementById('vmNowTitle');
  const elArtist = document.getElementById('vmNowArtist');
  const elPlay   = document.getElementById('vmPlay');
  const elPrev   = document.getElementById('vmPrev');
  const elNext   = document.getElementById('vmNext');
  const elSeek   = document.getElementById('vmSeek');
  const elCur    = document.getElementById('vmCur');
  const elDur    = document.getElementById('vmDur');
  const elVol    = document.getElementById('vmVol');

  const elTracks         = document.getElementById('vmTracks');
  const elPlaylists      = document.getElementById('vmPlaylists');
  const elPlaylistTracks = document.getElementById('vmPlaylistTracks');

  // Guard: якщо частина DOM не підключена — не ламаємо сторінку
  if (!elAudio || !elTitle || !elArtist || !elPlay || !elPrev || !elNext || !elSeek || !elCur || !elDur || !elVol) return;
  if (!elTracks || !elPlaylists || !elPlaylistTracks) return;

  const LANG = String((document.documentElement && document.documentElement.lang) ? document.documentElement.lang : 'uk').toLowerCase();
  const I18N = {
    uk: { tracksWord: 'треків', play: 'Відтворити', playlist: 'Плейлист' },
    ru: { tracksWord: 'треков', play: 'Играть',      playlist: 'Плейлист' },
    en: { tracksWord: 'tracks', play: 'Play',        playlist: 'Playlist' },
  };
  const T = I18N[LANG] || I18N.uk;

  function fmtTime(sec) {
    sec = Math.max(0, Math.floor(sec || 0));
    const m = Math.floor(sec / 60);
    const s = sec % 60;
    return m + ':' + String(s).padStart(2, '0');
  }

  async function apiJSON(url, opts) {
    const o = opts || {};
    const r = await fetch(url, {
      credentials: 'same-origin',
      headers: Object.assign({ 'Accept': 'application/json' }, o.headers || {}),
      signal: o.signal
    });
    if (!r.ok) throw new Error('HTTP ' + r.status);
    const ct = (r.headers.get('content-type') || '').toLowerCase();
    if (!ct.includes('application/json')) throw new Error('not_json');
    return await r.json();
  }

  function escapeHTML(s) {
    return String(s || '').replace(/[&<>"']/g, (c) => ({
      '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'
    }[c]));
  }

  function makeAudioItem(iconText, titleText, subText) {
    const div = document.createElement('div');
    div.className = 'audio-item';

    const icon = document.createElement('div');
    icon.style.display = 'flex';
    icon.style.alignItems = 'center';
    icon.style.justifyContent = 'center';
    icon.textContent = iconText;

    const body = document.createElement('div');

    const n1 = document.createElement('div');
    n1.className = 'n1';
    n1.textContent = titleText || '—';

    const n2 = document.createElement('div');
    n2.className = 'n2';
    n2.textContent = subText || '';

    body.appendChild(n1);
    body.appendChild(n2);

    div.appendChild(icon);
    div.appendChild(body);

    return div;
  }

  function setActiveInList(container, trackId) {
    try {
      const items = container.querySelectorAll('.audio-item[data-id]');
      items.forEach(it => it.classList.remove('is-active'));
      const active = container.querySelector('.audio-item[data-id="' + CSS.escape(String(trackId)) + '"]');
      if (active) active.classList.add('is-active');
    } catch (e) {}
  }

  let playlistFetchController = null;

  const VMPlayer = {
    queue: [],
    index: 0,

    saveState() {
      try {
        localStorage.setItem(LS_QUEUE, JSON.stringify(this.queue || []));
        localStorage.setItem(LS_INDEX, String(this.index || 0));
        localStorage.setItem(LS_VOL, String(Math.round((elAudio.volume || 0) * 100)));
      } catch (e) {}
    },

    loadState() {
      try {
        const q = JSON.parse(localStorage.getItem(LS_QUEUE) || '[]');
        const i = parseInt(localStorage.getItem(LS_INDEX) || '0', 10);
        const v = parseInt(localStorage.getItem(LS_VOL) || '80', 10);

        if (Array.isArray(q)) this.queue = q;
        const max = Math.max(0, (this.queue && this.queue.length ? this.queue.length - 1 : 0));
        if (!Number.isNaN(i)) this.index = Math.max(0, Math.min(max, i));
        else this.index = 0;

        const vv = Math.max(0, Math.min(100, Number.isNaN(v) ? 80 : v));
        elAudio.volume = vv / 100;
        elVol.value = String(vv);
      } catch (e) {}
    },

    setQueue(queue, index, autoplay = true) {
      this.queue = Array.isArray(queue) ? queue : [];
      const max = Math.max(0, this.queue.length - 1);
      this.index = Math.max(0, Math.min(max, index || 0));
      this.saveState();
      this.loadCurrent(autoplay);
    },

    current() {
      return this.queue[this.index] || null;
    },

    loadCurrent(autoplay) {
      const t = this.current();
      if (!t) {
        elTitle.textContent = '—';
        elArtist.textContent = '';
        elAudio.removeAttribute('src');
        try { elAudio.load(); } catch (e) {}
        return;
      }

      elTitle.textContent = t.title || '—';
      elArtist.textContent = t.artist || '';
      elAudio.src = t.url;
      try { elAudio.load(); } catch (e) {}

      // активний у списках (якщо відображені)
      setActiveInList(elTracks, t.id);
      setActiveInList(elPlaylistTracks, t.id);

      if (autoplay) elAudio.play().catch(() => {});
      this.saveState();
    },

    toggle() {
      if (!this.current()) return;
      if (elAudio.paused) elAudio.play().catch(() => {});
      else elAudio.pause();
    },

    next() {
      if (!this.queue.length) return;
      if (this.index < this.queue.length - 1) {
        this.index += 1;
        this.loadCurrent(true);
      } else {
        // кінець черги — стоп
        try { elAudio.pause(); } catch (e) {}
        elAudio.currentTime = 0;
      }
      this.saveState();
    },

    prev() {
      if (!this.queue.length) return;
      if (elAudio.currentTime > 3) {
        elAudio.currentTime = 0;
        return;
      }
      if (this.index > 0) {
        this.index -= 1;
        this.loadCurrent(true);
      } else {
        elAudio.currentTime = 0;
      }
      this.saveState();
    },

    async playAll() {
      const data = await apiJSON('/functional/audio/api_tracks.php');
      this.setQueue(data.tracks || [], 0, true);
    },

    async playTrackById(id) {
      const data = await apiJSON('/functional/audio/api_tracks.php');
      const q = data.tracks || [];
      const idx = q.findIndex(x => String(x.id) === String(id));
      this.setQueue(q, Math.max(0, idx), true);
    },

    async playPlaylist(id) {
      const data = await apiJSON('/functional/audio/api_playlist.php?id=' + encodeURIComponent(id));
      const q = data.tracks || [];
      this.setQueue(q, 0, true);
    }
  };

  window.VMPlayer = VMPlayer;

  function renderTracks(list) {
    elTracks.innerHTML = '';
    const frag = document.createDocumentFragment();

    (list || []).forEach((t, idx) => {
      const item = makeAudioItem('▶', t.title || '—', t.artist || '');
      item.dataset.id = String(t.id || '');
      item.addEventListener('click', () => {
        VMPlayer.setQueue(list, idx, true);
      });
      frag.appendChild(item);
    });

    elTracks.appendChild(frag);

    // підсвітити активний (якщо вже є queue)
    const cur = VMPlayer.current();
    if (cur) setActiveInList(elTracks, cur.id);
  }

  function renderPlaylists(list) {
    elPlaylists.innerHTML = '';
    const frag = document.createDocumentFragment();

    (list || []).forEach((p) => {
      const cnt = String(p.tracks_cnt || 0) + ' ' + T.tracksWord;
      const item = makeAudioItem('🎵', p.title || '—', cnt);
      item.dataset.pid = String(p.id || '');

      item.addEventListener('click', async () => {
        const pid = p.id;

        // Abort previous playlist fetch
        try { if (playlistFetchController) playlistFetchController.abort(); } catch (e) {}
        playlistFetchController = new AbortController();

        try {
          const data = await apiJSON(
            '/functional/audio/api_playlist.php?id=' + encodeURIComponent(pid),
            { signal: playlistFetchController.signal }
          );
          renderPlaylistTracks(p, data.tracks || []);
        } catch (e) {
          // якщо Abort — ігноруємо
          if (e && (e.name === 'AbortError' || String(e).includes('AbortError'))) return;
        }
      });

      frag.appendChild(item);
    });

    elPlaylists.appendChild(frag);
  }

  function renderPlaylistTracks(pl, tracks) {
    elPlaylistTracks.innerHTML = '';
    if (!tracks || !tracks.length) return;

    const header = document.createElement('div');
    header.style.margin = '6px 0 8px';

    const row = document.createElement('div');
    row.style.display = 'flex';
    row.style.alignItems = 'center';
    row.style.justifyContent = 'space-between';
    row.style.gap = '10px';
    row.style.flexWrap = 'wrap';

    const title = document.createElement('div');
    title.style.fontWeight = '900';
    title.textContent = pl && pl.title ? pl.title : T.playlist;

    const btn = document.createElement('button');
    btn.className = 'audio-btn';
    btn.type = 'button';
    btn.textContent = '▶ ' + T.play;
    btn.addEventListener('click', () => {
      VMPlayer.setQueue(tracks, 0, true);
    });

    row.appendChild(title);
    row.appendChild(btn);
    header.appendChild(row);
    elPlaylistTracks.appendChild(header);

    const frag = document.createDocumentFragment();
    tracks.forEach((t, idx) => {
      const item = makeAudioItem('▶', t.title || '—', t.artist || '');
      item.dataset.id = String(t.id || '');
      item.addEventListener('click', () => {
        VMPlayer.setQueue(tracks, idx, true);
      });
      frag.appendChild(item);
    });
    elPlaylistTracks.appendChild(frag);

    const cur = VMPlayer.current();
    if (cur) setActiveInList(elPlaylistTracks, cur.id);
  }

  // Controls
  elPlay.addEventListener('click', () => VMPlayer.toggle());
  elPrev.addEventListener('click', () => VMPlayer.prev());
  elNext.addEventListener('click', () => VMPlayer.next());

  elAudio.addEventListener('play',  () => { elPlay.textContent = '⏸'; });
  elAudio.addEventListener('pause', () => { elPlay.textContent = '▶'; });
  elAudio.addEventListener('ended', () => VMPlayer.next());

  elAudio.addEventListener('loadedmetadata', () => {
    elDur.textContent = fmtTime(elAudio.duration);
  });

  // throttle timeupdate UI
  let lastUiTick = 0;
  elAudio.addEventListener('timeupdate', () => {
    const now = Date.now();
    if (now - lastUiTick < 200) return; // ~5 разів/сек
    lastUiTick = now;

    const d = elAudio.duration || 0;
    const c = elAudio.currentTime || 0;

    elCur.textContent = fmtTime(c);

    if (d > 0) {
      const v = Math.round((c / d) * 1000);
      elSeek.value = String(Math.max(0, Math.min(1000, v)));
    } else {
      elSeek.value = '0';
    }
  });

  elSeek.addEventListener('input', () => {
    const d = elAudio.duration || 0;
    if (d <= 0) return;
    const v = parseInt(elSeek.value || '0', 10);
    const t = (v / 1000) * d;
    elAudio.currentTime = Math.max(0, Math.min(d, t));
  });

  elVol.addEventListener('input', () => {
    const v = Math.max(0, Math.min(100, parseInt(elVol.value || '80', 10)));
    elAudio.volume = v / 100;
    VMPlayer.saveState();
  });

  // Initial load: tracks + playlists
  (async function init() {
    VMPlayer.loadState();

    try {
      const data = await apiJSON('/functional/audio/api_tracks.php');
      renderTracks(data.tracks || []);
      renderPlaylists(data.playlists || []);
    } catch (e) {}

    // hash commands:
    // #play=all
    // #play=track&id=123
    // #play=playlist&id=5
    try {
      const h = (location.hash || '').replace(/^#/, '');
      const p = new URLSearchParams(h);
      const play = p.get('play');

      if (play === 'all') await VMPlayer.playAll();
      if (play === 'track') {
        const id = p.get('id');
        if (id) await VMPlayer.playTrackById(id);
      }
      if (play === 'playlist') {
        const id = p.get('id');
        if (id) await VMPlayer.playPlaylist(id);
      }
    } catch (e) {}

    // Restore queue if exists (no autoplay)
    if (VMPlayer.queue && VMPlayer.queue.length && VMPlayer.current()) {
      VMPlayer.loadCurrent(false);
    }
  })();

})();