const AUDIO_PLAYER_STATE_KEY = 'globalAudioPlayerState';

class SimpleAudioPlayer {
  constructor({
    audioSelector = '#globalAudio',
    playBtnSelector = '.player-button',
    timelineSelector = '.timeline',
    infoSelector = '#timeInfo',
    nowPlayingSelector = '#nowPlayingInfo',
    containerSelector = '#audioPlayerContainer',
    footerSelector = 'footer',
    minimizeBtnSelector = '.minimize-button'
  } = {}) {
    // Elements
    this.audio     = document.querySelector(audioSelector);
    this.playBtn   = document.querySelector(playBtnSelector);
    this.timeline  = document.querySelector(timelineSelector);
    this.timeInfo  = document.querySelector(infoSelector);
    this.nowInfo   = document.querySelector(nowPlayingSelector);
    this.container = document.querySelector(containerSelector);
    this.footer    = document.querySelector(footerSelector);
    this.minBtn    = document.querySelector(minimizeBtnSelector);

    // State
    this.isSeeking    = false;
    this.rafId        = null;
    this.abortCtrl    = null;
    this._hasMetadata = false;
    this._posInterval = null;
    this._posIntervalMs = 1000;

    // Pre-compute icons once
    const fill = getComputedStyle(document.documentElement)
                    .getPropertyValue('--dark-background').trim();
    this.icons = {
      play : this.svg(
        'M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z',
        fill
      ),
      pause: this.svg(
        'M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z',
        fill
      ),
      sound: this.svg(
        'M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM14.657 2.929a1 1 0 011.414 0A9.972 9.972 0 0119 10a9.972 9.972 0 01-2.929 7.071 1 1 0 01-1.414-1.414A7.971 7.971 0 0017 10c0-2.21-.894-4.208-2.343-5.657a1 1 0 010-1.414zm-2.829 2.828a1 1 0 011.415 0A5.983 5.983 0 0115 10a5.984 5.984 0 01-1.757 4.243 1 1 0 01-1.415-1.415A3.984 3.984 0 0013 10a3.983 3.983 0 00-1.172-2.828 1 1 0 010-1.415z',
        fill
      )
    };

    // Seeked => refresh timeline if external seek (e.g. Android controls)
    this.audio.addEventListener('seeked', () => this.updateTimeline());

    // Bind UI events
    this._bindEvents();

    // Setup MediaSession handlers + heartbeat
    this._initMediaSession();

    // Restore previous playback state (if any) and persist on navigation
    this._restoreState();
    window.addEventListener('pagehide', () => this._saveState());
    window.addEventListener('beforeunload', () => this._saveState());
  }

  /**
   * Push the current position to MediaSession so lockscreen / BT UIs stay in sync.
   * Keeps values strict but avoids over-clamping that can confuse some platforms.
   */
  _pushPositionState(force = false) {
    if (!navigator.mediaSession?.setPositionState) return;
    if (!this._hasMetadata) return;

    const duration = this.audio.duration;
    const position = this.audio.currentTime;
    if (!Number.isFinite(duration) || duration <= 0) return;
    if (!Number.isFinite(position) || position < 0) return;

    let playbackRate = Number.isFinite(this.audio.playbackRate) ? this.audio.playbackRate : 1;
    if (!playbackRate) playbackRate = 1;

    try {
      if ('playbackState' in navigator.mediaSession) {
        navigator.mediaSession.playbackState = this.audio.paused ? 'paused' : 'playing';
      }
      navigator.mediaSession.setPositionState({ duration, playbackRate, position });
    } catch (err) {
      if (force) console.warn('setPositionState failed:', err);
    }
  }

  // Minimal SVG helper
  svg(pathD, fill) {
    return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="${fill}">
      <path fill-rule="evenodd" d="${pathD}" clip-rule="evenodd"/>
    </svg>`;
  }

  _startPositionSync() {
    if (this._posInterval) return;
    this._posInterval = setInterval(() => {
      if (!this.audio.paused) {
        this._pushPositionState();
      }
    }, this._posIntervalMs);
  }

  _stopPositionSync() {
    if (!this._posInterval) return;
    clearInterval(this._posInterval);
    this._posInterval = null;
  }

  _bindEvents() {
    this.playBtn.addEventListener('click', () => this.togglePlay());
    if (this.minBtn) {
      this.minBtn.addEventListener('click', () => this.toggleCollapse());
    }

    this.audio.addEventListener('loadstart', () => {
      this._hasMetadata = false;
      this._stopPositionSync();
      this.timeline.min = 0;
      this.timeline.max = 0;
      this.timeline.value = 0;
      this.timeline.style.backgroundSize = '0% 100%';
      this.timeInfo.textContent = '00:00 / --:--';
    });

    this.audio.addEventListener('loadedmetadata', () => {
      this._hasMetadata = true;
      this.timeline.min   = 0;
      this.timeline.max   = this.audio.duration;
      this.timeline.value = 0;
      this.timeline.style.backgroundSize = '0% 100%';
      this._pushPositionState(true);
    });

    this.audio.addEventListener('play', () => {
      this._updatePlayState();
      this._pushPositionState(true);
      this._startPositionSync();
    });

    this.audio.addEventListener('playing',  () => this._pushPositionState(true));

    this.audio.addEventListener('pause', () => {
      this._updatePlayState();
      this._pushPositionState(true);
      this._stopPositionSync();
    });

    this.audio.addEventListener('ratechange', () => this._pushPositionState(true));
    this.audio.addEventListener('ended', () => {
      this.playBtn.innerHTML = this.icons.play;
      this._pushPositionState(true);
      this._stopPositionSync();
      if ('mediaSession' in navigator) navigator.mediaSession.playbackState = 'paused';
    });

    // Native timeupdate => update timeline
    this.audio.addEventListener('timeupdate', () => this.updateTimeline());

    // Keep position in sync when page visibility changes
    document.addEventListener('visibilitychange', () => {
      this._pushPositionState(true);
      if (document.visibilityState === 'visible' && !this.audio.paused) {
        this._startPositionSync();
      }
    });

    window.addEventListener('pageshow', () => this._pushPositionState(true));
    window.addEventListener('focus', () => this._pushPositionState(true));

    // Unified seek input
    this.timeline.addEventListener('input', () => {
      this.isSeeking = true;
      this.audio.currentTime = this.timeline.value;

      this._pushPositionState(true); // immediate Android sync
      this.updateTimeline();
      this.isSeeking = false;
    });
  }

  togglePlay() {
    this.audio.paused ? this.audio.play() : this.audio.pause();
  }

  _updatePlayState() {
    this.playBtn.innerHTML = this.audio.paused ? this.icons.play : this.icons.pause;
    this._pushPositionState(true); // lock‑screen refresh on play/pause toggle
  }

  _formatTime(sec) {
    const m = Math.floor(sec / 60), s = Math.floor(sec % 60);
    return `${m < 10 ? '0' : ''}${m}:${s < 10 ? '0' : ''}${s}`;
  }

  updateTimeline() {
    if (!this._hasMetadata || !this.audio.duration || this.isSeeking) return;

    // 1) Move the thumb
    this.timeline.value = this.audio.currentTime;
    // 2) Resize fill
    const pct = (this.audio.currentTime / this.audio.duration) * 100;
    this.timeline.style.backgroundSize = `${pct}% 100%`;
    // 3) Update text
    this.timeInfo.textContent =
      `${this._formatTime(this.audio.currentTime)} / ${this._formatTime(this.audio.duration)}`;
    // 4) Push to Android widget
    this._pushPositionState();
  }

  toggleCollapse() {
    const collapsed = !this.container.classList.contains('collapsed');
    this._setCollapsed(collapsed);
    this._saveState();
  }

  _setCollapsed(collapsed) {
    if (!this.container) return;
    this.container.classList.toggle('collapsed', collapsed);
    if (this.minBtn) {
      this.minBtn.setAttribute('aria-expanded', (!collapsed).toString());
      this.minBtn.setAttribute('aria-label', collapsed ? 'Player ausklappen' : 'Player einklappen');
    }
  }

  _saveState() {
    try {
      if (!this.currentRelUrl) {
        sessionStorage.removeItem(AUDIO_PLAYER_STATE_KEY);
        return;
      }
      const state = {
        relUrl: this.currentRelUrl,
        currentTime: Number.isFinite(this.audio.currentTime) ? this.audio.currentTime : 0,
        paused: this.audio.paused,
        collapsed: this.container?.classList.contains('collapsed') || false
      };
      sessionStorage.setItem(AUDIO_PLAYER_STATE_KEY, JSON.stringify(state));
    } catch {
      // Best-effort persistence only.
    }
  }

  _restoreState() {
    let stateRaw;
    try {
      stateRaw = sessionStorage.getItem(AUDIO_PLAYER_STATE_KEY);
    } catch {
      return;
    }
    if (!stateRaw) return;

    let state;
    try {
      state = JSON.parse(stateRaw);
    } catch {
      return;
    }
    if (!state || !state.relUrl) return;

    this._setCollapsed(Boolean(state.collapsed));
    const resumeTime = Number.isFinite(state.currentTime) ? state.currentTime : 0;
    const autoplay = !state.paused;
    this.loadTrack(state.relUrl, { autoplay, resumeTime });
  }

  async fileDownload() {
    let relUrl = this.currentRelUrl || '';
    const src = this.audio.currentSrc || this.audio.src;

    if (!relUrl && src) {
      try {
        const urlObj = new URL(src, window.location.href);
        if (urlObj.pathname.startsWith('/media/')) {
          relUrl = urlObj.pathname.slice('/media/'.length);
        }
      } catch {
        // ignore parsing errors
      }
    }

    if (!relUrl) return;

    const encodedSubpath = relUrl
      .replace(/^\/+/, '')
      .split('/')
      .map(segment => encodeURIComponent(decodeURIComponent(segment)))
      .join('/');

    // Fetch the tokenized URL from your backend
    let tokenizedUrl;
    try {
      const resp = await fetch(`/create_dltoken/${encodedSubpath}`);
      if (!resp.ok) return;
      tokenizedUrl = (await resp.text()).trim();
    } catch {
      return;
    }

    if (!tokenizedUrl) return;

    // Build the URL with cache-buster
    const downloadUrl = new URL(tokenizedUrl, window.location.href);

    // Create a link and click it
    const a = document.createElement('a');
    a.href = downloadUrl.toString();
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  }

  async loadTrack(relUrl, reqId, options = {}) {
    if (reqId && typeof reqId === 'object') {
      options = reqId;
      reqId = null;
    }
    const { autoplay = true, resumeTime = 0 } = options;

    this.currentRelUrl = relUrl;
    const requestId = reqId || (crypto.randomUUID ? crypto.randomUUID() : (Date.now().toString(36) + Math.random().toString(36).slice(2)));
    const urlWithReq = `/media/${relUrl}${relUrl.includes('?') ? '&' : '?'}req=${encodeURIComponent(requestId)}`;

    // Reset any residual state from the previous track before we fetch the new one
    this._hasMetadata = false;
    this.audio.pause();
    this.audio.removeAttribute('src');
    this.audio.load();
    this.timeline.min = 0;
    this.timeline.max = 0;
    this.timeline.value = 0;
    this.timeline.style.backgroundSize = '0% 100%';
    this.timeInfo.textContent = '00:00 / --:--';
    if ('mediaSession' in navigator) {
      navigator.mediaSession.playbackState = 'paused';
    }

    this.container.style.display = 'block';
    this.nowInfo.textContent = 'Loading…';

    this.abortCtrl?.abort();
    this.abortCtrl = new AbortController();

    try {
      const head = await fetch(urlWithReq, {
        method: 'HEAD',
        signal: this.abortCtrl.signal
      });
      if (!head.ok) throw new Error(`Status ${head.status}`);

      this.audio.src = urlWithReq;
      this.audio.load();

      const wantsResume = Number.isFinite(resumeTime) && resumeTime > 0;
      if (wantsResume) {
        this.audio.addEventListener('loadedmetadata', () => {
          const safeTime = Number.isFinite(this.audio.duration)
            ? Math.min(resumeTime, this.audio.duration)
            : resumeTime;
          this.audio.currentTime = safeTime;
          this.updateTimeline();

          if (autoplay) {
            this.audio.play().catch(() => this._updatePlayState());
          } else {
            this._updatePlayState();
          }
        }, { once: true });
      }

      if (!wantsResume) {
        if (autoplay) {
          try {
            await this.audio.play();
          } catch {
            this._updatePlayState();
          }
        } else {
          this._updatePlayState();
        }
      }

      // Full breadcrumb
      const parts      = relUrl.split('/');
      const file       = parts.pop();
      const folderPath = parts.join(' › ').replace('Gottesdienste S','S'); // Special case
      this.nowInfo.innerHTML =
        `${folderPath}<br><strong>${file.replace(/\.[^/.]+$/, '')}</strong>`;

      if ('mediaSession' in navigator) {
        navigator.mediaSession.metadata = new MediaMetadata({
          title : file.replace(/\.[^/.]+$/, ''),
          artist: parts.pop(),
          artwork: [{ src:'/icon/logo-192x192.png', sizes:'192x192', type:'image/png' }]
        });
      }
      this._saveState();
    } catch (err) {
      if (err.name !== 'AbortError') {
        this.nowInfo.textContent = 'Error loading track';
        console.error(err);
      }
    }
  }

  _initMediaSession() {
    if (!('mediaSession' in navigator)) return;

    const wrap = fn => details => {
      fn(details);
      this.updateTimeline();
    };

    // Core controls
    navigator.mediaSession.setActionHandler('play',        wrap(() => this.audio.play()));
    navigator.mediaSession.setActionHandler('pause',       wrap(() => this.audio.pause()));
    navigator.mediaSession.setActionHandler('seekbackward', wrap(({seekOffset=10}) => {
      this.audio.currentTime = Math.max(0, this.audio.currentTime - seekOffset);
    }));
    navigator.mediaSession.setActionHandler('seekforward',  wrap(({seekOffset=10}) => {
      this.audio.currentTime = Math.min(this.audio.duration, this.audio.currentTime + seekOffset);
    }));
    navigator.mediaSession.setActionHandler('seekto',       wrap(({seekTime, fastSeek}) => {
      if (fastSeek && this.audio.fastSeek) this.audio.fastSeek(seekTime);
      else this.audio.currentTime = seekTime;
    }));

    // Prev & Next
    navigator.mediaSession.setActionHandler('previoustrack', wrap(() => {
      if (typeof currentMusicIndex !== 'number' || !Array.isArray(currentMusicFiles)) return;
      if (currentMusicIndex > 0) {
        const prevFile = currentMusicFiles[currentMusicIndex - 1];
        const prevLink = document.querySelector(`.play-file[data-url="${prevFile.path}"]`);
        if (prevLink) {
          prevLink.click();
        }
      }
    }));
    navigator.mediaSession.setActionHandler('nexttrack',     wrap(() => {
      if (typeof currentMusicIndex !== 'number' || !Array.isArray(currentMusicFiles)) return;
      if (currentMusicIndex < currentMusicFiles.length - 1) {
        const nextFile = currentMusicFiles[currentMusicIndex + 1];
        const nextLink = document.querySelector(`.play-file[data-url="${nextFile.path}"]`);
        if (nextLink) {
          nextLink.click();
        }
      }
    }));

  }
}

// Initialize instance
const player = new SimpleAudioPlayer();
