<template>
  <div
    ref="player"
    :is="video.source === 'self-hosted' ? 'video' : 'div'"
    :src="video.source !== 'self-hosted' ? iframeSrc : null"
  >
    <iframe
      v-if="video.source === 'vimeo' || video.source === 'youtube'"
      :src="iframeSrc"
      allowfullscreen
      allowtransparency
      allow="autoplay"
    />
    <source
      v-if="video.source === 'self-hosted'"
      :src="iframeSrc"
      :type="type"
    >
  </div>
</template>

<script>
import Plyr from 'plyr/dist/plyr.min';
import dynamicComponent from '@/js/mixins/dynamic-component';

export default {
  mixins: [dynamicComponent],
  props: {
    videoUrl: {
      type: String,
      required: true,
    },
    background: {
      type: Boolean,
      default: false,
    },
    poster: {
      type: String,
      default: undefined,
    },
    type: {
      type: String,
      default: undefined,
    },
    controls: {
      type: Array,
      default: () => [
        'play-large',
        'play',
        'progress',
        'current-time',
        'mute',
        'volume',
        'captions',
        'settings',
        'pip',
        'airplay',
        'fullscreen',
      ],
    },
    settings: {
      type: Array,
      default: () => [
        'captions',
        'quality',
        'speed',
        'loop',
      ],
    },
    i18n: {
      type: Object,
      default: () => ({
        restart: 'Restart',
        rewind: 'Rewind {seektime}s',
        play: 'Play',
        pause: 'Pause',
        fastForward: 'Forward {seektime}s',
        seek: 'Seek',
        seekLabel: '{currentTime} of {duration}',
        played: 'Played',
        buffered: 'Buffered',
        currentTime: 'Current time',
        duration: 'Duration',
        volume: 'Volume',
        mute: 'Mute',
        unmute: 'Unmute',
        enableCaptions: 'Enable captions',
        disableCaptions: 'Disable captions',
        enterFullscreen: 'Enter fullscreen',
        exitFullscreen: 'Exit fullscreen',
        frameTitle: 'Player for {title}',
        captions: 'Captions',
        settings: 'Settings',
        menuBack: 'Go back to previous menu',
        speed: 'Speed',
        normal: 'Normal',
        quality: 'Quality',
        loop: 'Loop',
        start: 'Start',
        end: 'End',
        all: 'All',
        reset: 'Reset',
        disabled: 'Disabled',
        enabled: 'Enabled',
        advertisement: 'Ad',
        qualityBadge: {
          2160: '4K',
          1440: 'HD',
          1080: 'HD',
          720: 'HD',
          576: 'SD',
          480: 'SD',
        },
      }),
    },
    loadSprite: {
      type: Boolean,
      default: true,
    },
    iconUrl: {
      type: String,
      default: '',
    },
    iconPrefix: {
      type: String,
      default: 'plyr',
    },
    blankvideo: {
      type: String,
      default: 'https://cdn.plyr.io/static/blank.mp4',
    },
    autoplay: {
      type: Boolean,
      default: false,
    },
    autopause: {
      type: Boolean,
      default: true,
    },
    seekTime: {
      type: Number,
      default: 10,
    },
    volume: {
      type: Number,
      default: 1,
    },
    muted: {
      type: Boolean,
      default: false,
    },
    clickToPlay: {
      type: Boolean,
      default: true,
    },
    disableContextMenu: {
      type: Boolean,
      default: true,
    },
    hideControls: {
      type: Boolean,
      default: true,
    },
    resetOnEnd: {
      type: Boolean,
      default: false,
    },
    keyboard: {
      type: Object,
      default: () => ({
        focused: true,
        global: false,
      }),
    },
    tooltips: {
      type: Object,
      default: () => ({
        controls: false,
        seek: true,
      }),
    },
    duration: {
      type: Number,
      default: undefined,
    },
    displayDuration: {
      type: Boolean,
      default: true,
    },
    invertTime: {
      type: Boolean,
      default: true,
    },
    toggleInvert: {
      type: Boolean,
      default: true,
    },
    listeners: {
      type: Object,
      default: null,
    },
    captions: {
      type: Object,
      default: () => ({
        enabled: true,
        fallback: true,
        iosNative: false,
      }),
    },
    fullscreen: {
      type: Object,
      default: () => ({
        enabled: true,
        fallback: true,
        iosNative: false,
      }),
    },
    ratio: {
      type: String,
      default: '16:9',
    },
    storage: {
      type: Object,
      default: () => ({
        enabled: true,
        key: 'plyr',
      }),
    },
    speed: {
      type: Object,
      default: () => ({
        selected: 1,
        options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2],
      }),
    },
    quality: {
      type: Object,
      default: () => ({
        default: 'default',
        options: [
          'hd2160',
          'hd1440',
          'hd1080',
          'hd720',
          'large',
          'medium',
          'small',
          'tiny',
          'default',
        ],
      }),
    },
    loop: {
      type: Object,
      default: () => ({
        active: false,
      }),
    },
    ads: {
      type: Object,
      default: () => ({
        enabled: false,
        publisherId: '',
      }),
    },
  },
  computed: {
    video() {
      return this.parseVideo(this.videoUrl);
    },
    iframeSrc() {
      if (this.video.source === 'vimeo') {
        return `https://player.vimeo.com/video/${this.video.id}?loop=false&amp;byline=false&amp;portrait=false&amp;title=false&amp;speed=true&amp;transparent=0&amp;gesture=media`;
      }

      if (this.video.source === 'youtube') {
        return `https://www.youtube.com/embed/${this.video.id}?iv_load_policy=3&amp;modestbranding=1&amp;playsinline=1&amp;showinfo=0&amp;rel=0&amp;enablejsapi=1`;
      }

      if (this.video.source === 'self-hosted') {
        return this.videoUrl;
      }

      return null;
    },
  },
  data() {
    return {
      player: undefined,
    };
  },
  mounted() {
    // Settings up Plyr instance
    const plyrOptions = {};

    if (this.background) {
      plyrOptions.controls = [];
      plyrOptions.clickToPlay = false;
      plyrOptions.fullscreen = {
        enabled: false,
        fallback: false,
        iosNative: false,
      };
      plyrOptions.loop = { active: true };
    } else {
      plyrOptions.controls = this.controls;
      plyrOptions.settings = this.settings;
      plyrOptions.loadSprite = this.loadSprite;
      plyrOptions.iconPrefix = this.iconPrefix;
      plyrOptions.autopause = this.autopause;
      plyrOptions.seekTime = this.seekTime;
      plyrOptions.clickToPlay = this.clickToPlay;
      plyrOptions.hideControls = this.hideControls;
      plyrOptions.resetOnEnd = this.resetOnEnd;
      plyrOptions.keyboard = this.keyboard;
      plyrOptions.tooltips = this.tooltips;
      plyrOptions.duration = this.duration;
      plyrOptions.displayDuration = this.displayDuration;
      plyrOptions.invertTime = this.invertTime;
      plyrOptions.toggleInvert = this.toggleInvert;
      plyrOptions.captions = this.captions;
      plyrOptions.fullscreen = this.fullscreen;
      plyrOptions.loop = this.loop;
      plyrOptions.ads = this.ads;
    }

    plyrOptions.i18n = this.i18n;
    plyrOptions.blankvideo = this.blankvideo;
    plyrOptions.disableContextMenu = this.disableContextMenu;
    plyrOptions.ratio = this.ratio;
    plyrOptions.storage = this.storage;
    plyrOptions.speed = this.speed;
    plyrOptions.quality = this.quality;

    if (this.listeners) {
      plyrOptions.listeners = this.listeners;
    }

    if (this.iconUrl) {
      plyrOptions.iconUrl = this.iconUrl;
    }

    this.player = new Plyr(this.$refs.player, plyrOptions);

    if (this.poster !== undefined) {
      this.player.poster = this.poster;
    }

    // Plyr Events //

    // Standard Media Events
    this.player.on('progress', (event) => {
      this.$emit('progress', event);
    });

    this.player.on('playing', (event) => {
      this.$emit('playing', event);
    });

    this.player.on('play', (event) => {
      this.$emit('play', event);
    });

    this.player.on('pause', (event) => {
      this.$emit('pause', event);
    });

    this.player.on('timeUpdate', (event) => {
      this.$emit('timeUpdate', event);
    });

    this.player.on('volumeChange', (event) => {
      this.$emit('volumeChange', event);
    });

    this.player.on('seeking', (event) => {
      this.$emit('seeking', event);
    });

    this.player.on('seeked', (event) => {
      this.$emit('seeked', event);
    });

    this.player.on('rateChange', (event) => {
      this.$emit('rateChange', event);
    });

    this.player.on('ended', (event) => {
      this.$emit('ended', event);
    });

    this.player.on('enterFullscreen', (event) => {
      this.$emit('enterFullscreen', event);
    });

    this.player.on('exitFullscreen', (event) => {
      this.$emit('exitFullscreen', event);
    });

    this.player.on('captionsenabled', (event) => {
      this.$emit('captionsenabled', event);
    });

    this.player.on('captionsdisabled', (event) => {
      this.$emit('captionsdisabled', event);
    });

    this.player.on('languagechange', (event) => {
      this.$emit('languagechange', event);
    });

    this.player.on('controlshidden', (event) => {
      this.$emit('controlshidden', event);
    });

    this.player.on('controlsshown', (event) => {
      this.$emit('controlsshown', event);
    });

    this.player.on('ready', (event) => {
      this.$emit('ready', event);

      this.onReady();
    });

    // HTML5 Only Events
    this.player.on('loadstart', (event) => {
      this.$emit('loadstart', event);
    });

    this.player.on('loadeddata', (event) => {
      this.$emit('loadeddata', event);
    });

    this.player.on('loadedmetadata', (event) => {
      this.$emit('loadedmetadata', event);
    });

    this.player.on('qualitychange', (event) => {
      this.$emit('qualitychange', event);
    });

    this.player.on('canplay', (event) => {
      this.$emit('canplay', event);
    });

    this.player.on('canplaythrough', (event) => {
      this.$emit('canplaythrough', event);
    });

    this.player.on('stalled', (event) => {
      this.$emit('stalled', event);
    });

    this.player.on('waiting', (event) => {
      this.$emit('waiting', event);
    });

    this.player.on('emptied', (event) => {
      this.$emit('emptied', event);
    });

    this.player.on('cuechange', (event) => {
      this.$emit('cuechange', event);
    });

    this.player.on('error', (event) => {
      this.$emit('error', event);
    });

    // YouTube Only Events
    this.player.on('statechange', (event) => {
      this.$emit('statechange', event);
    });
  },
  methods: {
    parseVideo(url) {
      // eslint-disable-next-line
      url.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
      let type = '';

      if (RegExp.$3.indexOf('youtu') > -1) {
        type = 'youtube';
      } else if (RegExp.$3.indexOf('vimeo') > -1) {
        type = 'vimeo';
      } else {
        return {
          source: 'self-hosted',
          id: null,
        };
      }

      return {
        source: type,
        id: RegExp.$6,
      };
    },
    onReady() {
      if (!this.muted) {
        this.player.volume = this.volume;
      }

      if (this.background || this.muted) {
        this.player.muted = true;
      }

      if (this.background || this.autoplay) {
        this.player.play();
      }
    },

    // Plyr Methods //

    play() {
      this.player.play();
    },
    pause() {
      this.player.pause();
    },
    togglePlay(toggle) {
      this.player.togglePlay(toggle);
    },
    stop() {
      this.player.stop();
    },
    restart() {
      this.player.restart();
    },
    rewind(seekTime) {
      this.player.rewind(seekTime);
    },
    forward(seekTime) {
      this.player.forward(seekTime);
    },
    increaseVolume(step) {
      this.player.increaseVolume(step);
    },
    decreaseVolume(step) {
      this.player.decreaseVolume(step);
    },
    toggleCaptions(toggle) {
      this.player.toggleCaptions(toggle);
    },
    enterFullscreen() {
      this.player.fullscreen.enter();
    },
    exitFullscreen() {
      this.player.fullscreen.exit();
    },
    toggleFullscreen() {
      this.player.fullscreen.toggle();
    },
    airplay() {
      this.player.airplay();
    },
    toggleControls(toggle) {
      this.player.toggleControls(toggle);
    },
    supports(type) {
      this.player.supports(type);
    },
    destroy() {
      this.player.destroy();
    },
  },
};
</script>

<style lang="scss">
  @import "~plyr/src/sass/plyr";
</style>
