/* ============================================================
   Radio Ultra – app.js
   ============================================================ */
(() => {
  'use strict';

  const audio      = document.getElementById('audioPlayer');
  const btnPlay    = document.getElementById('btnPlay');
  const btnStop    = document.getElementById('btnStop');
  const playerName = document.getElementById('playerName');
  const playerMeta = document.getElementById('playerMeta');
  const playerLogo = document.getElementById('playerLogo');
  const playerFb   = document.getElementById('playerLogoFallback');
  const stickyPl   = document.getElementById('stickyPlayer');
  const volSlider  = document.getElementById('volume');
  const cards      = [...document.querySelectorAll('.station-card')];
  const searchEl   = document.getElementById('search');
  const noResults  = document.getElementById('noResults');
  const genreFilter= document.getElementById('genreFilter');
  const btnWake    = document.getElementById('btnWake');
  const btnCast    = document.getElementById('btnCast');
  const castButtons = [...document.querySelectorAll('[data-cast-button]')];
  if (btnCast) btnCast.style.display = 'inline-flex';

  let currentId    = null;
  let metaTimer    = null;
  let filterGenre  = '';
  let filterSearch = '';
  let isPlaying    = false;
  let wakeLock     = null;
  let wakeWanted   = false;
  let currentStation = null;
  let isCasting      = false;

  function showPlayerMessage(message) {
    playerMeta.textContent = message;
    stickyPl.style.display = 'flex';
  }

  // ── Device-aware app download ───────────────────────────────
  function setupAppDownload() {
    const menus = [...document.querySelectorAll('[data-app-download-menu]')];

    if (menus.length) {
      const ua = navigator.userAgent || navigator.vendor || '';
      const platform = (navigator.userAgentData && navigator.userAgentData.platform) || navigator.platform || '';
      const isAndroid = /android/i.test(ua) || /android/i.test(platform);
      const isIOS = /iPad|iPhone|iPod/i.test(ua) || (platform === 'MacIntel' && navigator.maxTouchPoints > 1);
      const isWindows = /win/i.test(platform) || /windows/i.test(ua);
      const isMac = !isIOS && (/mac/i.test(platform) || /macintosh/i.test(ua));
      const isLinux = !isAndroid && /linux/i.test(platform);

      const preferredPlatform = isAndroid ? 'android' : isIOS ? 'ios' : isWindows ? 'windows' : isMac ? 'mac' : isLinux ? 'linux' : 'web';

      menus.forEach(menu => {
        const toggle = menu.querySelector('.app-download-toggle');
        const label = menu.querySelector('[data-app-download-label]');
        const options = [...menu.querySelectorAll('.app-download-option')];
        const preferred = options.find(option => option.dataset.platform === preferredPlatform) ||
          options.find(option => option.dataset.platform === 'web') ||
          options[0];

        if (preferred) {
          preferred.classList.add('preferred');
          if (toggle) {
            const preferredName = preferred.querySelector('strong')?.textContent?.trim();
            if (preferredName) {
              toggle.title = `Rekommenderat för denna enhet: ${preferredName}`;
            }
          }
        }

        if (!toggle) return;

        toggle.addEventListener('click', event => {
          event.preventDefault();
          const isOpen = menu.classList.toggle('open');
          toggle.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
        });

        document.addEventListener('click', event => {
          if (menu.contains(event.target)) return;
          menu.classList.remove('open');
          toggle.setAttribute('aria-expanded', 'false');
        });

        document.addEventListener('keydown', event => {
          if (event.key !== 'Escape') return;
          menu.classList.remove('open');
          toggle.setAttribute('aria-expanded', 'false');
        });
      });

      return;
    }

    const links = [...document.querySelectorAll('[data-apk-download]')];
    if (!links.length) return;

    const ua = navigator.userAgent || navigator.vendor || '';
    const platform = (navigator.userAgentData && navigator.userAgentData.platform) || navigator.platform || '';
    const isAndroid = /android/i.test(ua) || /android/i.test(platform);
    const isIOS = /iPad|iPhone|iPod/i.test(ua) || (platform === 'MacIntel' && navigator.maxTouchPoints > 1);

    links.forEach(link => {
      const apkUrl = link.dataset.apkUrl || link.href;
      link.href = apkUrl;
      link.setAttribute('type', 'application/vnd.android.package-archive');

      if (isAndroid) {
        link.textContent = '📱 Installera Android-app';
        link.classList.add('android-detected');
        link.classList.remove('ios-device');
        link.setAttribute('download', 'stellan-radio.apk');
        link.title = 'Ladda ner Stellan Radio som Android APK';
        return;
      }

      if (isIOS) {
        link.textContent = '📱 Android-app (APK)';
        link.classList.add('ios-device');
        link.classList.remove('android-detected');
        link.removeAttribute('download');
        link.title = 'APK-filen kan installeras på Android-enheter';
        return;
      }

      link.textContent = '📱 Ladda ner Android-app';
      link.classList.remove('android-detected', 'ios-device');
      link.setAttribute('download', 'stellan-radio.apk');
      link.title = 'Ladda ner Stellan Radio som Android APK';
    });
  }

  setupAppDownload();


  // ── Stellan Radio Cast integration ──────────────────────────
  window.__onGCastApiAvailable = function(isAvailable) {
    if (isAvailable) initCast();
  };

  function castReady() {
    return !!(window.cast && window.chrome && chrome.cast && cast.framework);
  }

  function getCastSession() {
    if (!castReady()) return null;
    return cast.framework.CastContext.getInstance().getCurrentSession();
  }

  function updateCastButtons() {
    castButtons.forEach(button => {
      button.classList.toggle('casting', isCasting);
      button.dataset.casting = isCasting ? '1' : '0';
      button.setAttribute('aria-pressed', isCasting ? 'true' : 'false');
      button.title = isCasting ? 'Cast är igång - tryck för att avsluta' : 'Casta vald kanal';
      button.textContent = '📺';
    });
  }

  function getCastContentType(url) {
    const cleanUrl = (url || '').split('?')[0].toLowerCase();

    if (cleanUrl.endsWith('.m3u8')) return 'application/vnd.apple.mpegurl';
    if (cleanUrl.endsWith('.aac'))  return 'audio/aac';
    if (cleanUrl.endsWith('.ogg'))  return 'audio/ogg';
    if (cleanUrl.endsWith('.opus')) return 'audio/ogg';
    if (cleanUrl.endsWith('.wav'))  return 'audio/wav';

    return 'audio/mpeg';
  }

  function initCast() {
    if (!castReady()) return;

    try {
      const context = cast.framework.CastContext.getInstance();

      context.setOptions({
        receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
        autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
      });

      context.addEventListener(
        cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
        event => {
          if (
            event.sessionState === cast.framework.SessionState.SESSION_STARTED ||
            event.sessionState === cast.framework.SessionState.SESSION_RESUMED
          ) {
            isCasting = true;
            updateCastButtons();
            castCurrentStation();
          }

          if (event.sessionState === cast.framework.SessionState.SESSION_ENDED) {
            isCasting = false;
            updateCastButtons();
          }
        }
      );

      if (btnCast) btnCast.style.display = 'inline-flex';
    } catch (err) {
      console.warn('Google Cast kunde inte initieras:', err);
    }
  }

  function castCurrentStation() {
    const session = getCastSession();

    if (!session || !currentStation || !currentStation.url) return;

    const absoluteLogo = currentStation.logo
      ? new URL(currentStation.logo, window.location.href).href
      : '';

    const contentType = getCastContentType(currentStation.url);
    const mediaInfo = new chrome.cast.media.MediaInfo(currentStation.url, contentType);

    mediaInfo.streamType = chrome.cast.media.StreamType.LIVE;
    mediaInfo.contentType = contentType;

    const metadata = new chrome.cast.media.MusicTrackMediaMetadata();
    metadata.title = currentStation.name || document.title.replace(/^🎙️\s*/, '') || 'Live radio';
    metadata.artist = currentStation.meta || 'Live radio';

    if (absoluteLogo) {
      metadata.images = [new chrome.cast.Image(absoluteLogo)];
    }

    mediaInfo.metadata = metadata;

    const request = new chrome.cast.media.LoadRequest(mediaInfo);
    request.autoplay = true;

    session.loadMedia(request).then(() => {
      isCasting = true;
      updateCastButtons();

      audio.pause();

      isPlaying = true;
      updatePlayBtn();

      playerMeta.textContent = currentStation.meta || 'Castar till Google Home / Chromecast…';
    }).catch(err => {
      isCasting = false;
      updateCastButtons();
      console.warn('Kunde inte starta Cast-uppspelning:', err);
      playerMeta.textContent = 'Kunde inte casta denna kanal.';
    });
  }

  if (castReady()) initCast();

  function stopCasting() {
    const session = getCastSession();
    isCasting = false;
    updateCastButtons();

    if (session && typeof session.endSession === 'function') {
      session.endSession(true);
    }

    if (currentStation) {
      playerMeta.textContent = 'Cast avslutad.';
    }
  }

  function toggleCast() {
      if (isCasting || getCastSession()) {
        stopCasting();
        return;
      }

      if (!currentStation || !currentStation.url) {
        showPlayerMessage('Starta en radiokanal först. Tryck sedan på Casta igen.');
        return;
      }

      if (!window.chrome) {
        showPlayerMessage('Cast kräver Google Chrome.');
        return;
      }

      if (!window.cast || !chrome.cast || !window.cast.framework) {
        showPlayerMessage('Google Cast är inte redo ännu.');
        console.warn('Cast debug:', {
          protocol: window.location.protocol,
          host: window.location.host,
          hasChrome: !!window.chrome,
          hasCast: !!window.cast,
          hasChromeCast: !!(window.chrome && chrome.cast),
          hasFramework: !!(window.cast && cast.framework)
        });
        return;
      }

      try {
        initCast();

        const context = cast.framework.CastContext.getInstance();

        context.requestSession()
          .then(() => {
            castCurrentStation();
          })
          .catch(err => {
            console.warn('Cast requestSession error:', err);
          });

      } catch (err) {
        showPlayerMessage('Kunde inte starta Cast.');
        console.error('Cast start error:', err);
      }
  }

  castButtons.forEach(button => button.addEventListener('click', toggleCast));
  updateCastButtons();

  let castInitAttempts = 0;
  function retryCastInit() {
    castInitAttempts++;
    if (castReady()) {
      initCast();
      return;
    }
    if (castInitAttempts < 20) {
      setTimeout(retryCastInit, 500);
    }
  }
  retryCastInit();

  // ── Wake Lock (håller skärmen vaken under uppspelning) ───────
  async function requestWakeLock() {
    if (!('wakeLock' in navigator)) return;
    try {
      wakeLock = await navigator.wakeLock.request('screen');
      wakeLock.addEventListener('release', () => updateWakeBtn());
      updateWakeBtn();
    } catch (err) {
      console.warn('Wake Lock kunde inte aktiveras:', err);
    }
  }

  function releaseWakeLock() {
    if (wakeLock) { wakeLock.release(); wakeLock = null; }
    updateWakeBtn();
  }

  function updateWakeBtn() {
    if (!btnWake) return;
    const active = !!wakeLock;
    btnWake.classList.toggle('active', active);
    btnWake.title = active ? 'Skärmen hålls vaken (klicka för att stänga av)' : 'Håll skärmen vaken';
    const moonIcon = btnWake.querySelector('.icon-moon');
    const sunIcon  = btnWake.querySelector('.icon-sun');
    if (moonIcon && sunIcon) {
      moonIcon.style.display = active ? 'none' : '';
      sunIcon.style.display  = active ? '' : 'none';
    }
  }

  if (btnWake) {
    if (!('wakeLock' in navigator)) {
      btnWake.style.display = 'none';
    } else {
      btnWake.addEventListener('click', () => {
        wakeWanted = !wakeWanted;
        if (wakeWanted) requestWakeLock(); else releaseWakeLock();
      });
    }
  }

  // Återaktivera wake lock om fliken döljs och visas igen (t.ex. surfplattan väcks)
  document.addEventListener('visibilitychange', () => {
    if (wakeWanted && document.visibilityState === 'visible' && !wakeLock) {
      requestWakeLock();
    }
  });

  // ── Volume ──────────────────────────────────────────────────
  audio.volume = parseFloat(volSlider.value);
  volSlider.addEventListener('input', () => { audio.volume = parseFloat(volSlider.value); });

  // ── Play card ───────────────────────────────────────────────
  function syncSelectedStream(card) {
    const select = card.querySelector('.station-stream-select');
    if (!select) {
      card.dataset.currentMeta = card.dataset.meta || '';
      return;
    }

    const option = select.selectedOptions[0];
    const selectedName = option?.dataset.name || option?.textContent.trim() || card.dataset.baseName || card.dataset.name;

    card.dataset.url = select.value || card.dataset.url;
    card.dataset.name = selectedName;
    card.dataset.selectedStreamName = selectedName;
    card.dataset.streamId = option?.dataset.streamId || card.dataset.streamId || '';
    card.dataset.currentMeta = option?.dataset.meta || '';
    setCardMeta(card, card.dataset.currentMeta);
  }

  cards.forEach(syncSelectedStream);

  function playCard(card) {
    syncSelectedStream(card);

    const id   = card.dataset.id;
    const url  = card.dataset.url;
    const name = card.dataset.name;
    const logo = card.dataset.logo;
    const init = card.dataset.initial;
    const streamId = card.dataset.streamId || '';
    const meta = card.dataset.currentMeta || card.dataset.meta || '';

    if (!url) return;

    currentStation = { id, streamId, url, name, logo, init, meta };

    // Avbryt ev. pågående återanslutningsförsök för föregående kanal
    clearTimeout(reconnectTimer); reconnectTimer = null;
    clearTimeout(stallTimer);
    reconnectAttempts = 0;

    // Highlight
    cards.forEach(c => c.classList.remove('playing'));
    card.classList.add('playing');

    // Audio
    audio.pause();
    audio.src = url;
    audio.load();
    audio.play().catch(() => {});

    if (getCastSession()) {
      castCurrentStation();
    }

    currentId = id;
    isPlaying = true;
    updatePlayBtn();

    // Player strip
    playerName.textContent = name;
    playerMeta.textContent = meta;
    stickyPl.style.display = 'flex';

    if (logo) {
      playerLogo.src = logo;
      playerLogo.style.display = 'block';
      playerFb.style.display = 'none';
    } else {
      playerLogo.style.display = 'none';
      playerFb.textContent = init;
      playerFb.style.display = 'flex';
    }

    // Log play (fire & forget)
    fetch('api/live.php', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({station_id: id})
    }).catch(() => {});

    // Aktivera wake lock automatiskt när uppspelning startar (om inte redan satt)
    if (!wakeWanted) { wakeWanted = true; requestWakeLock(); }

    // Start metadata polling
    clearInterval(metaTimer);
    fetchMeta(id, streamId);
    metaTimer = setInterval(() => {
      if (!currentStation) return;
      fetchMeta(currentStation.id, currentStation.streamId);
    }, 30000);
  }

  function updatePlayBtn() {
    btnPlay.textContent = isPlaying ? '⏸' : '▶';
  }

  // ── Metadata fetch ──────────────────────────────────────────
  function metaTextFrom(data) {
    return [data.artist, data.title].filter(Boolean).join(' – ');
  }

  function setCardMeta(card, text) {
    if (!card) return;
    let el = document.getElementById('meta-' + card.dataset.id);
    if (!el) {
      el = document.createElement('p');
      el.className = 'meta-text';
      el.id = 'meta-' + card.dataset.id;
      const info = card.querySelector('.card-info');
      if (info) info.appendChild(el);
    }
    el.textContent = text || '';
    el.hidden = !text;
  }

  function fetchMeta(stationId, streamId = '') {
    const endpoint = streamId
      ? 'api/stream.php?id=' + encodeURIComponent(streamId)
      : 'api/station.php?id=' + encodeURIComponent(stationId);

    fetch(endpoint)
      .then(r => r.json())
      .then(data => {
        if (!data.ok) return;
        const text = metaTextFrom(data);
        const matchesCurrent = currentStation &&
          String(currentStation.id) === String(stationId) &&
          (!streamId || String(currentStation.streamId || '') === String(streamId));

        if (matchesCurrent) {
          playerMeta.textContent = text;
          currentStation.meta = text;
        }

        const card = cards.find(c => String(c.dataset.id) === String(stationId));
        if (card && (!streamId || String(card.dataset.streamId || '') === String(streamId))) {
          card.dataset.currentMeta = text;
          if (!card.querySelector('.station-stream-select')) card.dataset.meta = text;
          setCardMeta(card, text);
        }
      })
      .catch(() => {});
  }

  function refreshStationMetadata() {
    fetch('api/stations.php')
      .then(r => r.json())
      .then(data => {
        if (!data.ok || !Array.isArray(data.stations)) return;

        data.stations.forEach(station => {
          const card = cards.find(c => String(c.dataset.id) === String(station.id));
          if (!card) return;

          const text = metaTextFrom({
            artist: station.meta_artist,
            title: station.meta_title
          });

          card.dataset.meta = text;
          if (!card.querySelector('.station-stream-select')) {
            card.dataset.currentMeta = text;
            setCardMeta(card, text);
          }

          if (currentStation && String(currentStation.id) === String(station.id) && !currentStation.streamId) {
            currentStation.meta = text;
            playerMeta.textContent = text;
          }
        });
      })
      .catch(() => {});
  }

  setTimeout(refreshStationMetadata, 5000);
  setInterval(refreshStationMetadata, 60000);

  // ── Controls ────────────────────────────────────────────────
  btnPlay.addEventListener('click', () => {
    if (!audio.src) return;
    if (isPlaying) { audio.pause(); isPlaying = false; }
    else           { audio.play().catch(() => {}); isPlaying = true; }
    updatePlayBtn();
  });

  btnStop.addEventListener('click', () => {
    currentId = null; // sätt först, så ev. pågående reconnect avbryts
    clearTimeout(reconnectTimer); reconnectTimer = null;
    clearTimeout(stallTimer);
    reconnectAttempts = 0;
    const castSession = getCastSession();
    if (castSession && typeof castSession.endSession === 'function') {
      castSession.endSession(true);
    }
    audio.pause();
    audio.src = '';
    isCasting = false;
    updateCastButtons();
    isPlaying = false;
    updatePlayBtn();
    stickyPl.style.display = 'none';
    cards.forEach(c => c.classList.remove('playing'));
    clearInterval(metaTimer);
    wakeWanted = false;
    releaseWakeLock();
  });

  audio.addEventListener('play',  () => { isPlaying = true;  updatePlayBtn(); });
  audio.addEventListener('pause', () => { isPlaying = false; updatePlayBtn(); });

  // ── Auto-reconnect vid buffring/avbrott ──────────────────────
  let reconnectAttempts = 0;
  let reconnectTimer    = null;
  let stallTimer        = null;
  let lastPlaybackSignal = Date.now();
  const MAX_RECONNECT_DELAY = 15000; // 15s tak mellan försök
  const STALL_RECONNECT_AFTER = 18000;

  function markPlaybackSignal() {
    lastPlaybackSignal = Date.now();
  }

  function scheduleReconnect(reason) {
    if (!currentId || reconnectTimer) return; // redan på väg, eller inget aktivt val

    const card = cards.find(c => c.dataset.id === currentId);
    if (!card) return;

    const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), MAX_RECONNECT_DELAY);
    reconnectAttempts++;

    console.warn(`Radio Ultra: återansluter om ${delay}ms (${reason}, försök ${reconnectAttempts})`);
    playerMeta.textContent = 'Återansluter…';

    reconnectTimer = setTimeout(() => {
      reconnectTimer = null;
      if (!currentId) return; // stoppad under tiden
      const wasVolume = audio.volume;
      audio.src = '';
      syncSelectedStream(card);
      audio.src = card.dataset.url;
      audio.volume = wasVolume;
      audio.load();
      audio.play().catch(() => {});
    }, delay);
  }

  audio.addEventListener('playing', () => {
    // Lyckad uppspelning – återställ backoff-räknaren
    markPlaybackSignal();
    reconnectAttempts = 0;
    if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
  });
  audio.addEventListener('timeupdate', markPlaybackSignal);
  audio.addEventListener('progress', markPlaybackSignal);
  audio.addEventListener('canplay', markPlaybackSignal);

  audio.addEventListener('error', () => {
    if (currentId) scheduleReconnect('error');
  });

  // 'stalled' = bytes slutade komma in (vanligt vid nätverksglapp)
  audio.addEventListener('stalled', () => {
    if (!currentId) return;
    clearTimeout(stallTimer);
    stallTimer = setTimeout(() => {
      const noRecentPlayback = Date.now() - lastPlaybackSignal > STALL_RECONNECT_AFTER;
      if (!audio.paused && audio.readyState < 2 && noRecentPlayback) scheduleReconnect('stalled');
    }, STALL_RECONNECT_AFTER);
  });

  // 'waiting' = bufferunderskott, normalt kortvarigt men kan fastna
  audio.addEventListener('waiting', () => {
    if (!currentId) return;
    clearTimeout(stallTimer);
    stallTimer = setTimeout(() => {
      const noRecentPlayback = Date.now() - lastPlaybackSignal > STALL_RECONNECT_AFTER;
      if (!audio.paused && audio.readyState < 2 && noRecentPlayback) scheduleReconnect('waiting too long');
    }, STALL_RECONNECT_AFTER);
  });

  audio.addEventListener('canplay', () => clearTimeout(stallTimer));

  // ── Card click ──────────────────────────────────────────────
  cards.forEach(card => {
    const streamSelect = card.querySelector('.station-stream-select');
    if (streamSelect) {
      streamSelect.addEventListener('click', e => e.stopPropagation());
      streamSelect.addEventListener('change', e => {
        e.stopPropagation();
        syncSelectedStream(card);
        if (String(card.dataset.id) === String(currentId)) {
          playCard(card);
        }
      });
    }

    card.addEventListener('click', e => {
      if (e.target.closest('.station-stream-select')) return;
      if (e.target.closest('.btn-card-play') || e.currentTarget === card) {
        if (card.dataset.id === currentId && isPlaying) {
          audio.pause(); isPlaying = false; updatePlayBtn();
          card.classList.remove('playing');
          return;
        }
        playCard(card);
      }
    });
  });

  // ── Search & Filter ─────────────────────────────────────────
  function applyFilter() {
    let visible = 0;
    cards.forEach(card => {
      const matchGenre  = !filterGenre  || card.dataset.genre === filterGenre;
      const searchableName = (card.dataset.baseName || card.dataset.name || '').toLowerCase();
      const selectedName = (card.dataset.selectedStreamName || '').toLowerCase();
      const matchSearch = !filterSearch || searchableName.includes(filterSearch) || selectedName.includes(filterSearch);
      const show = matchGenre && matchSearch;
      card.style.display = show ? '' : 'none';
      if (show) visible++;
    });
    noResults.style.display = visible === 0 ? 'block' : 'none';
  }

  searchEl.addEventListener('input', () => {
    filterSearch = searchEl.value.toLowerCase().trim();
    applyFilter();
  });

  genreFilter.addEventListener('click', e => {
    const chip = e.target.closest('.chip');
    if (!chip) return;
    document.querySelectorAll('.chip').forEach(c => c.classList.remove('active'));
    chip.classList.add('active');
    filterGenre = chip.dataset.genre;
    applyFilter();
  });

  // ── Keyboard ────────────────────────────────────────────────
  document.addEventListener('keydown', e => {
    if (e.target.tagName === 'INPUT') return;
    if (e.code === 'Space')     { e.preventDefault(); btnPlay.click(); }
    if (e.code === 'KeyS')      { btnStop.click(); }
  });

})();
