document.addEventListener('DOMContentLoaded', () => {
  // initialize audio player
  var player = new Player();
  player.initialize();

  // set up episode links on content swap
  document.getElementsByTagName('main').item(0)
      .addEventListener('htmx:afterSwap', (e) => {
    const episodes = e.detail.elt.getElementsByClassName('episode');
    for (var episode of episodes) {
      const title = episode.getAttribute('title');
      const series = episode.dataset.series;
      const cover = episode.dataset.cover;
      const file = episode.dataset.file;
      episode.addEventListener('click', () => {
        player.playEpisode(cover, series, title, file);
      });
    }
  });

  // load page
  const pname = location.pathname == '/'
    ? '/home.html'
    : location.pathname + '.html';
  const path = '/partial' + pname;
  htmx.ajax('GET', path, 'main');
});

class Player {
  constructor() {
    this.playSvg = 'M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM6.79 5.093A.5.5 0 0 0 6 5.5v5a.5.5 0 0 0 .79.407l3.5-2.5a.5.5 0 0 0 0-.814l-3.5-2.5z';
    this.pauseSvg = 'M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM6.25 5C5.56 5 5 5.56 5 6.25v3.5a1.25 1.25 0 1 0 2.5 0v-3.5C7.5 5.56 6.94 5 6.25 5zm3.5 0c-.69 0-1.25.56-1.25 1.25v3.5a1.25 1.25 0 1 0 2.5 0v-3.5C11 5.56 10.44 5 9.75 5z';
    const controls = document.getElementById('controls');
    const timeVolume = document.getElementById('timeVolume');
    this.nowPlaying = document.getElementById('nowPlaying');
    this.rewButton = controls.getElementsByTagName('button').item(0);
    this.playButton = controls.getElementsByTagName('button').item(1);
    this.playButtonPath = this.playButton.getElementsByTagName('path').item(0);
    this.ffwButton = controls.getElementsByTagName('button').item(2);
    this.cover = this.nowPlaying.getElementsByTagName('img').item(0);
    this.seriesName = this.nowPlaying.getElementsByTagName('span').item(0);
    this.episodeName = this.nowPlaying.getElementsByTagName('span').item(1);
    this.timeDisplay = timeVolume.getElementsByTagName('span').item(0);
    this.volumeSlider = timeVolume.getElementsByTagName('input').item(0);
    this.howl = null;
    this.ticker = null;
  }

  initialize() {
    this.reset();
    const player = this;
    this.playButton.addEventListener('click', () => {
      player.playPause();
    });
    this.rewButton.addEventListener('click', () => {
      player.rewind();
    });
    this.ffwButton.addEventListener('click', () => {
      player.fastForward();
    });
    this.volumeSlider.addEventListener('change', () => {
      this.setVolume();
    });

    // set up mediasession in browsers that support it
    if ('mediaSession' in navigator) {
      const player = this;
      navigator.mediaSession.setActionHandler('pause',
        () => player.playPause());
      navigator.mediaSession.setActionHandler('play',
        () => player.playPause());
      navigator.mediaSession.setActionHandler('stop',
        () => player.playPause());
      navigator.mediaSession.setActionHandler('seekforward',
        () => player.fastForward());
      navigator.mediaSession.setActionHandler('seekbackward',
        () => player.rewind());
      navigator.mediaSession.setActionHandler('nexttrack',
        () => player.fastForward());
      navigator.mediaSession.setActionHandler('previoustrack',
        () => player.rewind());
    }
  }

  startTicker() {
    if (!this.ticker) {
      const player = this;
      this.ticker = setInterval(() => {
        player.setTime();
      }, 500);
    }
  }

  stopTicker() {
    if (this.ticker) {
      clearInterval(this.ticker);
      this.ticker = null;
    }
  }

  disableControls(disabled) {
    this.playButton.disabled = disabled === true;
    this.rewButton.disabled = disabled === true;
    this.ffwButton.disabled = disabled === true;
  }

  setPlay() {
    this.playButtonPath.setAttribute('d', this.playSvg);
  }

  setPause() {
    this.playButtonPath.setAttribute('d', this.pauseSvg);
  }

  setSeries(series, cover) {
    this.seriesName.innerHTML = series ?? 'No episode playing';
    this.seriesName.setAttribute('title', series ?? 'No episode playing');
    this.cover.setAttribute('src', cover ?? '/transparent.png');
  }

  setEpisode(episode) {
    this.episodeName.innerHTML = episode ?? '';
    this.episodeName.setAttribute('title', episode ?? '');
  }

  setMetadata(series, episode, cover) {
    if ('mediaSession' in navigator) {
      this.metadata = new MediaMetadata({
        title: episode,
        album: series,
        artist: 'Radiostasis',
        artwork: [{
          src: cover,
          sizes: '256x256',
          type: 'image/jpeg',
        }],
      });
    }
  }

  sendMetadata() {
    if ('mediaSession' in navigator) {
      navigator.mediaSession.metadata = this.metadata;
    }
  }

  clearMetadata() {
    if ('mediaSession' in navigator) {
      navigator.mediaSession.metadata = null;
    }
  }

  _getDisplayTime(time) {
    const minutes = Math.floor(time / 60);
    const seconds = Math.round(time - (minutes * 60));
    const secStr = seconds < 10 ? '0' + seconds : seconds;
    return minutes + ':' + secStr;
  }

  setTime() {
    if (this.howl && this.howl.state() === 'loaded') {
      const total = this.howl.duration();
      const current = this.howl.seek();
      this.timeDisplay.innerHTML =
        this._getDisplayTime(current) + ' / ' + this._getDisplayTime(total);
    } else {
      this.timeDisplay.innerHTML = '--:-- / --:--';
    }
  }

  getVolume() {
    return parseFloat(this.volumeSlider.value) / 100;
  }

  setVolume() {
    if (this.howl) {
      this.howl.volume(this.getVolume());
    }
  }

  reset() {
    this.howl = null;
    this.setPlay();
    this.setSeries();
    this.setEpisode();
    this.clearMetadata();
    this.setTime();
    this.nowPlaying.classList.remove('error');
    this.disableControls(true);
    this.stopTicker();
    this.metadata = null;
  }

  error(message) {
    this.reset();
    this.setSeries('Error playing episode');
    this.setEpisode(message);
    this.nowPlaying.classList.add('error');
  }

  playPause() {
    if (this.howl && this.howl.playing()) {
      this.howl.pause();
    } else if (this.howl && !this.howl.playing()) {
      this.howl.play();
    }
  }

  rewind() {
    if (this.howl && this.howl.state() === 'loaded') {
      let newPos = this.howl.seek() - 10;
      if (newPos < 0) newPos = 0;
      this.howl.seek(newPos);
    }
  }

  fastForward() {
    if (this.howl && this.howl.state() === 'loaded') {
      let newPos = this.howl.seek() + 30;
      if (newPos > this.howl.duration()) newPos = this.howl.duration();
      this.howl.seek(newPos);
    }
  }

  playEpisode(cover, series, episode, file) {
    if (this.howl) {
      this.howl.stop();
    }

    this.reset();
    this.setPause();
    this.disableControls(true);
    this.setSeries('Loading episode', '/loading.gif');
    this.setEpisode(episode);

    fetch('/api/r/' + file).then(async (res) => {
      if (!res.ok) {
        this.error('API returned ' + res.status);
        return;
      }
      const link = await res.json();
      const player = this;
      this.howl = new Howl({
        src: link.url + '?Authorization=' + link.token,
        html5: true,
        autoplay: true,
        volume: this.getVolume(),
        onload: () => {
          player.setTime();
          player.setMetadata(series, episode, cover);
        },
        onplay: () => {
          player.sendMetadata();
          player.setSeries(series, cover);
          player.setPause();
          player.disableControls(false);
          player.startTicker();
        },
        onpause: () => {
          player.setPlay();
          player.stopTicker();
        },
        onend: () => {
          player.reset();
        },
        onloaderror: () => {
          player.reset();
          player.error('Playback error');
        },
      });
    }).catch(err => {
      console.log(err);
      this.error('API request error');
    });
  }
}
