<template>
  <div
    class="c-media"
    :style="styles"
  >
    <svg-icon icon-class="w-material" />
    <template v-if="source">
      <template v-if="canPlay">
        <video
          ref="player"
          class="c-media__inst"
          :src="src"
          autoplay
          :muted.prop="muted"
          @ended="onEnded"
          @error="onError"
        />
        <canvas
          v-show="isSnapping"
          ref="canvas"
          class="c-media__canvas"
        />
      </template>
      <div
        v-if="isImage"
        class="c-media__inst has-bg"
        :style="imageStyles"
      />
    </template>
  </div>
</template>

<script>
import {
  getAssetUrl,
  getThumbnailUrl
} from '@/api/asset'
import { AssetType } from '@/constant'
import { WidgetType } from '../constant'
import { switchToNext } from '../utils'

export default {
  name: WidgetType.MEDIA,
  inject: ['control'],
  props: {
    node: {
      type: Object,
      default: null
    }
  },
  data () {
    return {
      ignore: false,
      source: null
    }
  },
  computed: {
    isSnapping () {
      return this.control.snapping
    },
    styles () {
      const {
        width,
        height,
        radius
      } = this.node
      return {
        width: `${width}px`,
        height: `${height}px`,
        'font-size': `${Math.min(width, height) / 3 | 0}px`,
        'border-radius': `${radius}px`
      }
    },
    isImage () {
      return this.source?.type === AssetType.IMAGE
    },
    imageStyles () {
      return this.isImage ? { 'background-image': `url(${getThumbnailUrl(this.source.keyName)})` } : null
    },
    isVideo () {
      return this.source?.type === AssetType.VIDEO
    },
    src () {
      return this.isVideo ? getAssetUrl(this.source.keyName) : null
    },
    muted () {
      return this.node.mute || this.control.muted
    },
    canPlay () {
      return this.isVideo && !this.ignore
    }
  },
  watch: {
    'node.sources' () {
      this.reset()
    },
    isSnapping (val) {
      let ignore = false
      const player = this.$refs.player
      if (player) {
        if (val) {
          // 尽量保障出画面
          if (player.currentTime && player.currentTime >= 0.5) {
            player.pause()
            this.getSnap()
          } else {
            ignore = true
          }
        } else {
          player.play()
          const canvas = this.$refs.canvas
          if (canvas) {
            canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height)
          }
        }
      }
      this.ignore = ignore
    }
  },
  created () {
    this.$timer = -1
    this.reset()
  },
  beforeDestroy () {
    clearTimeout(this.$timer)
  },
  methods: {
    reset () {
      this.$index = -1
      this.choose()
    },
    choose () {
      const { sources, toggleType } = this.node
      clearTimeout(this.$timer)

      this.$index = switchToNext(toggleType, sources, this.$index)
      this.source = sources[this.$index]

      if (this.isImage && sources.length > 1) {
        this.$timer = setTimeout(this.choose, this.source.duration * 1000)
      }
    },
    onEnded () {
      this.$refs.player.currentTime = 0
      if (this.node.sources.length > 1) {
        this.choose()
      }
      this.$refs.player.play()
    },
    onError (e) {
      console.warn('video error', e)
      if (this.node.sources.length > 1) {
        this.choose()
      }
    },
    getSnap () {
      const video = this.$refs.player
      const canvas = this.$refs.canvas
      if (video && canvas) {
        const cxt = canvas.getContext('2d')
        canvas.width = this.node.width
        canvas.height = this.node.height
        cxt.drawImage(video, 0, 0, this.node.width, this.node.height)
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.c-media {
  position: relative;
  display: inline-flex;
  justify-content: center;
  align-items: center;
  background-color: rgba(255, 255, 255, 0.8);
  overflow: hidden;

  &__inst,
  &__canvas {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }

  &__inst {
    object-fit: fill;
  }
}
</style>
