<template>
  <div
    class="o-video"
    :class="{ offline: !online, mask: showMask }"
  >
    <template v-if="online">
      <video
        ref="video"
        class="o-video__player o-simple-video"
        :poster="poster"
        autoplay
        muted
        @pause="onPause"
        @play="onPlay"
      />
      <div class="o-video__mask">
        <div
          class="l-flex--row center o-video__btn u-pointer"
          @click="onClick"
        >
          <i :class="iconClass" />
        </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>
      <div
        v-if="online"
        class="l-flex__none c-sibling-item o-quality-menu"
        @click.stop="toggleQualityMenu"
      >
        <div
          v-if="showQualityMenu"
          class="o-quality-menu__list"
        >
          <div
            class="o-quality-menu__item u-pointer"
            @click="changeQuality('fff')"
          >
            标清
          </div>
          <div
            class="o-quality-menu__item u-pointer"
            @click="changeQuality('ff')"
          >
            高清
          </div>
          <div
            class="o-quality-menu__item u-pointer"
            @click="changeQuality('')"
          >
            原画
          </div>
        </div>
        <div class="u-pointer">
          {{ qualityValue }}
        </div>
      </div>
    </div>
    <slot />
  </div>
</template>

<script>
import flvjs from 'flv.js'
import { authCode } from '@/api/camera'
import { GATEWAY } from '@/constant'
import videoPoster from '@/assets/video-poster.png'

export default {
  name: 'DevicePlayer',
  props: {
    device: {
      type: Object,
      required: true
    },
    autoplay: {
      type: [Boolean, String],
      default: false
    },
    controls: {
      type: [Boolean, String],
      default: false
    }
  },
  data () {
    return {
      needPause: !this.autoplay,
      poster: videoPoster,
      loading: false,
      refreshShow: false,
      paused: false,
      showQualityMenu: false,
      quality: ''
    }
  },
  computed: {
    showMask () {
      return this.loading || this.refreshShow || this.paused
    },
    iconClass () {
      if (this.loading) {
        return 'el-icon-loading'
      }
      if (this.refreshShow) {
        return 'el-icon-refresh'
      }
      return this.paused ? 'el-icon-video-play' : 'el-icon-video-pause'
    },
    online () {
      return this.device.activate === 2 && this.device.onlineStatus === 1
    },
    qualityValue () {
      switch (this.quality) {
        case 'fff':
          return '标清'
        case 'ff':
          return '高清'
        default:
          return '原画'
      }
    }
  },
  created () {
    this.$timer = -1
    if (this.online) {
      this.getAuthCode()
      if (this.controls) {
        document.addEventListener('click', this.hideQualityMenu)
      }
    }
  },
  beforeDestroy () {
    if (this.online && this.controls) {
      document.removeEventListener('click', this.hideQualityMenu)
    }
    this.destroyPlayer()
    this.$timer = null
  },
  methods: {
    hideQualityMenu () {
      this.showQualityMenu = false
    },
    toggleQualityMenu () {
      this.showQualityMenu = !this.showQualityMenu
    },
    changeQuality (quality) {
      if (this.quality !== quality) {
        this.quality = quality
        this.destroyPlayer()
        if (this.$playerInfo) {
          this.createPlayer(this.$playerInfo)
        } else {
          this.getAuthCode()
        }
      }
    },
    onPause () {
      this.paused = true
    },
    onPlay () {
      this.paused = false
      if (this.loading) {
        this.loading = false
        if (this.needPause) {
          this.$player.pause()
        }
      }
    },
    onClick () {
      if (this.loading) {
        return
      }
      if (this.refreshShow) {
        this.getAuthCode()
      } else if (this.paused) {
        this.needPause = true
        this.$player.play()
      } else {
        this.needPause = false
        this.$player.pause()
      }
    },
    getAuthCode () {
      if (this.loading) {
        return
      }
      this.loading = true
      this.$playerInfo = null
      authCode({ deviceId: this.device.id }).then(
        ({ data }) => {
          if (this.$timer !== null) {
            this.$playerInfo = data
            this.createPlayer(this.$playerInfo)
          }
        },
        () => {
          this.destroyPlayer()
        }
      )
    },
    createPlayer ({ timestamp, expire, token }) {
      if (Number(timestamp) + Number(expire) * 1000 <= Date.now()) {
        this.getAuthCode()
        return
      }
      this.loading = true
      if (flvjs.isSupported()) {
        const quality = this.quality ? `_${this.quality}` : ''
        const player = flvjs.createPlayer({
          type: 'flv',
          isLive: true,
          hasAudio: false,
          url: `${GATEWAY}/live/${this.device.id}${quality}.flv?authorization=${token}&timestamp=${timestamp}&expire=${expire}`
        })
        player.on(flvjs.Events.ERROR, e => {
          console.log('flvjs', this.device.name, flvjs.Events.ERROR, e)
          this.destroyPlayer()
          this.$message({
            type: 'warning',
            message: `${this.device.name} 视频流出错`
          })
        })
        player.on(flvjs.Events.METADATA_ARRIVED, () => {
          console.log('flvjs', this.device.name, flvjs.Events.METADATA_ARRIVED)
          clearTimeout(this.$timer)
        })

        try {
          this.refreshShow = false
          this.$player = player
          this.$timer = setTimeout(() => {
            if (this.loading) {
              this.destroyPlayer()
              this.$message({
                type: 'warning',
                message: `暂未获取到 ${this.device.name} 的视频流`
              })
            }
          }, 10000)
          player.attachMediaElement(this.$refs.video)
          player.load()
        } catch (error) {
          console.log('连接异常', error)
          this.destroyPlayer()
        }
      }
    },
    destroyPlayer () {
      clearTimeout(this.$timer)
      this.loading = false
      this.refreshShow = true
      const player = this.$player
      if (player) {
        player.pause()
        player.unload()
        player.detachMediaElement()
        player.destroy()
        this.$player = null
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.o-video:hover {
  .o-video__mask {
    display: inline-block;
  }
}

.o-quality-menu {
  display: inline-block;
  position: relative;
  padding: 0 6px;
  z-index: 1;

  &:hover {
    .o-quality-menu__list {
      display: inline-block;
    }
  }

  &__list {
    display: none;
    position: absolute;
    right: 0;
    bottom: 0;
    width: 100%;
    padding-bottom: 24px;
    font-size: 14px;
    text-align: center;
    border-radius: $radius $radius 0 0;
    background-color: rgba(#000, 0.3);
    z-index: -1;
  }

  &__item {
    padding: 4px 0;

    &:hover {
      color: $primary;
    }
  }
}
</style>
