<template>
  <div
    class="o-video"
    :class="{ offline: !online, mask: !isPlaying, controls, floating, fullscreen: isFullscreen }"
    @mousemove="onMouseMove"
  >
    <template v-if="online">
      <video
        ref="video"
        class="o-video__player o-simple-video"
        :poster="poster"
        autoplay
        muted
        @play="onVideoPlay"
        @pause="onVideoPause"
        @waiting="onVideoWaiting"
        @playing="onVideoPlaying"
        @error="onVideoError"
        @ended="onVideoEnded"
      />
      <div class="o-video__mask">
        <div
          class="l-flex--row center o-video__btn u-pointer"
          @click.stop="onPlayOrPause"
        >
          <i :class="statusIconClass" />
        </div>
      </div>
    </template>
    <div
      v-if="controls"
      class="l-flex--row c-footer"
    >
      <div class="l-flex__fill c-sibling-item u-ellipsis">{{ device.name }}</div>
      <slot
        name="controls"
        :can-play="canPlay"
        :on-full-screen="onFullScreen"
      >
        <template v-if="canPlay">
          <i
            v-if="loadingQuality"
            class="c-sibling-item el-icon-loading"
          />
          <div
            v-else
            class="l-flex__none c-sibling-item o-quality-menu u-pointer"
            @click.stop="toggleQualityMenu"
          >
            <div
              v-if="showQualityMenu"
              class="o-quality-menu__list u-font-size--sm u-text--center"
            >
              <div
                v-for="item in qualities"
                :key="item.value"
                class="o-quality-menu__item has-active"
                :class="{ 'u-color--success': quality.value === item.value }"
                @click="changeQuality(item)"
              >
                {{ item.label }}
              </div>
            </div>
            <span class="has-active">{{ quality.label }}</span>
          </div>
          <i
            class="c-sibling-item el-icon-full-screen has-active"
            @click="onFullScreen"
          />
        </template>
      </slot>
    </div>
  </div>
</template>

<script>
import {
  authCode,
  getRecordConfig,
  addRecordConfig,
  updateRecordConfig
} from '@/api/device'
import { GATEWAY } from '@/constant'
import playerMixin from '../player'

const Quality = {
  fff: {
    videoWidth: 640,
    videoHeight: 360,
    videoBitRate: 36 * 1024,
    frameRate: 1
  },
  ff: {
    videoWidth: 1280,
    videoHeight: 720,
    videoBitRate: 100 * 1024,
    frameRate: 10
  },
  f: {
    videoWidth: 1920,
    videoHeight: 1080,
    videoBitRate: 1024 * 1024,
    frameRate: 20
  }
}

export default {
  name: 'DevicePlayer',
  mixins: [playerMixin],
  props: {
    device: {
      type: Object,
      required: true
    }
  },
  data () {
    return {
      qualities: [
        { value: 'fff', label: '标清' },
        { value: 'ff', label: '高清' },
        { value: 'f', label: '超清' }
      ],
      loadingQuality: false,
      showQualityMenu: false,
      quality: null,
      recordConfig: null,
      floating: true
    }
  },
  computed: {
    online () {
      return this.device.onlineStatus === 1
    },
    canPlay () {
      return !this.loading && !this.needReset
    }
  },
  watch: {
    online (val) {
      if (val) {
        this.$nextTick(this.createPlayer)
      } else {
        this.hideQualityMenu()
        this.onVideoReset()
        this.destroyPlayer()
      }
    },
    isFullscreen () {
      this.onMouseMove()
    }
  },
  created () {
    this.$delayMoveTimer = -1
    this.$timer = -1
    if (this.online) {
      this.createPlayer()
    }
  },
  beforeDestroy () {
    clearTimeout(this.$delayMoveTimer)
    this.hideQualityMenu()
  },
  methods: {
    onMouseMove () {
      clearTimeout(this.$delayMoveTimer)
      this.floating = false
      if (this.isFullscreen) {
        this.$delayMoveTimer = setTimeout(() => {
          this.floating = true
        }, 3000)
      }
    },
    onVideoReset () {
      this.recordConfig = null
      this.$playerInfo = null
    },
    getRecordConfig () {
      this.loadingQuality = true
      getRecordConfig(this.device.id, { custom: true }).finally(() => {
        this.loadingQuality = false
      }).then(
        ({ data }) => {
          if (data) {
            const { frameRate } = data
            const key = Object.keys(Quality).find(key => Quality[key].frameRate === frameRate) || 'fff'
            this.quality = this.qualities.find(({ value }) => value === key) || this.qualities[0]
            this.recordConfig = data
            this.createPlayer()
          } else {
            this.setRecordConfig(this.qualities[0])
          }
        },
        () => {
          this.onVideoDestroyByError()
        }
      )
    },
    setRecordConfig (quality) {
      this.loadingQuality = true
      ;(this.recordConfig ? updateRecordConfig : addRecordConfig)({
        deviceId: this.device.id,
        ...Quality[quality.value]
      }, { custom: true }).then(
        ({ data }) => {
          this.quality = quality
          this.recordConfig = data
          this.createPlayer()
        },
        () => {
          this.onVideoDestroyByError()
        }
      ).finally(() => {
        this.loadingQuality = false
      })
    },
    hideQualityMenu () {
      if (this.showQualityMenu) {
        this.showQualityMenu = false
        document.removeEventListener('click', this.hideQualityMenu)
      }
    },
    toggleQualityMenu () {
      if (this.showQualityMenu) {
        this.hideQualityMenu()
      } else {
        document.addEventListener('click', this.hideQualityMenu)
        this.showQualityMenu = true
      }
    },
    changeQuality (quality) {
      if (this.quality.value !== quality.value) {
        this.$playerInfo = null
        this.setRecordConfig(quality)
      } else if (this.needReset) {
        this.createPlayer()
      }
    },
    getAuthCode () {
      this.$playerInfo = null
      authCode(this.recordConfig.stream).then(
        ({ data }) => {
          if (this.$timer !== null) {
            this.$playerInfo = data
            this.createPlayer()
          }
        },
        () => {
          this.onVideoDestroyByError()
        }
      )
    },
    createPlayer () {
      if (this.$timer === null) {
        return
      }
      this.loading = true
      clearTimeout(this.$timer)
      if (!this.recordConfig) {
        this.getRecordConfig()
        return
      }
      if (!this.$playerInfo) {
        this.getAuthCode()
        return
      }
      const { vhost = '__defaultVhost__', token, timestamp, expire } = this.$playerInfo
      if (Number(timestamp) + Number(expire) * 1000 <= Date.now()) {
        this.getAuthCode()
        return
      }
      this.destroyPlayer()
      this.playUrl(`${GATEWAY}/live/${this.recordConfig.stream}.flv?vhost=${vhost}&authorization=${token}&timestamp=${timestamp}&expire=${expire}`)
    }
  }
}
</script>

<style lang="scss" scoped>
.o-quality-menu {
  display: inline-block;
  position: relative;
  padding: 0 $padding--xs;
  z-index: 1;

  &__list {
    position: absolute;
    right: 0;
    bottom: 100%;
    width: 100%;
    margin-bottom: $spacing--2xs;
    border-radius: $radius;
    background-color: rgba(#000, 0.85);
    z-index: -1;
  }

  &__item {
    padding: $padding--2xs 0;
  }
}
</style>
