<template>
  <div class="frames-wrap">
    <img v-if="needMask && isShowMask" class="mask-image" :src="imageSrcFunc(1)" alt="" draggable="false">
    <!-- {{ frameTotalNum }} -->
    <img
      v-for="index of frameTotalNum"
      v-show="
        frameCurNum === index - 1 ||
        (frameCurNum - 1 === index - 1) ||
        (frameCurNum === 0 && index === frameTotalNum)
      "
      :key="index"
      :style="{
        zIndex: (frameCurNum === 0 && index === frameTotalNum) ? -1 : 0,
        opacity: needMask && isShowMask ? 0 : 1
      }"
      :src="imageSrcFunc(index)"
      alt=""
      draggable="false"
      @load="onFrameLoad(index - 1)"
      @error="onFrameError(index - 1)"
    >
    <audio v-if="audioUrl" ref="audio" loop :src="audioUrl" controls @timeupdate="onAudioCurTimeChange" />
  </div>
</template>
<script>
import appStore from "@/store/index";

export default {
  props: {
    isDebug: {
      type: Boolean,
      default: false,
    },
    frameTotalNum: {
      type: Number,
      required: true,
    },
    frameInterval: {
      type: Number,
      default: 41.667
    },
    imageSrcFunc: {
      type: Function,
      required: true,
    },
    autoPlay: {
      type: Boolean,
      default: false,
    },
    repeat: {
      type: Boolean,
      default: false,
    },
    audioUrl: {
      type: String,
      default: '',
    },
    audioVolumeRatio: {
      type: Number,
      default: 1,
    },
  },
  emits: ['over'],
  setup() {
    const store = appStore();
    return { store }
  },
  data() {
    return {
      isShowMask: true,
      repeatCount: 0,
      frameCurNum: 0,
      frameStateList: new Array(this.frameTotalNum),
      frameIntervalId: null,
      isPlaying: false,
      isPaused: false, // paused时也算playing

      intersectionObserverForFrame: null,

      intersectionObserverForAudio: null,
      intersectionRatio: 0,
      audioFadeoutRate: 1,

      firstIn: true,

      // frameTotalNum: 24
    }
  },
  computed: {

    // 在移动端火狐浏览器中，有透明度的序列帧的头几轮播放会有闪烁的现象，所以需要临时用第一帧盖住。
    needMask() {
      if (this.repeat && /FireFox/i.test(navigator.userAgent)) {
        return true
      } else {
        return false
      }
    },
    audioVolume() {
      if (this.store.canPlayLongImageBgAudio) {
        if (this.firstIn) {
          this.firstIn = false
          this.$refs.audio && (this.$refs.audio.currentTime = 0)
        }
        return this.intersectionRatio * this.audioFadeoutRate * this.audioVolumeRatio
      } else {
        return 0
      }
    }
  },
  watch: {
    frameCurNum: {
      handler(vNew) {
        if (this.isDebug) {
          console.log('SerialFrames frameCurNum: ', vNew)
        }
      },
      immediate: true,
    },
    intersectionRatio: {
      handler(vNew, vOld) {
        console.log('result:', vNew, vOld);
        if (this.isDebug) {
          console.log('intersectionRation change: ', vNew)
        }
        const audioNode = this.$refs.audio
        if (!this.$refs.audio) {
          return
        }
        if (vNew > 0) {
          if (audioNode.paused && vOld <= 0 && !this.$isSafari) { // safari里只能在用户操作回调函数中成功调用play。
            console.log('result:bofang');
            audioNode.currentTime = 0
            audioNode.play()
          }
        } else {
          if (!audioNode.paused && vOld > 0 && !this.$isSafari) {
            audioNode.pause()
          }
        }
      },
      immediate: false,
    },
    audioVolume: {
      handler(vNew) {
        setTimeout(() => {
          const audioNode = this.$refs.audio
          if (!this.$refs.audio) {
            return
          }
          if (this.isDebug) {
            console.log('audio volume: ', vNew)
          }

          audioNode.volume = vNew
        }, 0)
      },
      immediate: true,
    }
  },
  mounted() {

    if (this.autoPlay) {
      this.intersectionObserverForFrame = new IntersectionObserver((entries) => {
        let entry = entries[entries.length - 1]
        if (entry.intersectionRatio > 0) {
          if (this.isDebug) {
            console.log('play!')
          }
          this.play()
        } else {
          if (this.isDebug) {
            console.log('stop!')
          }
          this.stop()
        }
      }, {
        root: document.getElementsByClassName('long-image')[0],
        threshold: [
          0.0,
        ]
      })
      this.intersectionObserverForFrame.observe(this.$el)
    }

    if (this.audioUrl) {
      this.intersectionObserverForAudio = new IntersectionObserver((entries) => {
        let entry = entries[entries.length - 1]
        this.intersectionRatio = entry.intersectionRatio
      }, {
        root: document.getElementsByClassName('long-image')[0],
        threshold: [
          0.0,
          0.1,
          0.2,
          0.3,
          0.4,
          0.5,
          0.6,
          0.7,
          0.8,
          0.9,
          1.0
        ]
      })
      this.intersectionObserverForAudio.observe(this.$el)
    }
  },
  unmounted() {
    clearInterval(this.frameIntervalId)
    if (this.intersectionObserverForFrame) {
      this.intersectionObserverForFrame.disconnect()
    }
    if (this.intersectionObserverForAudio) {
      this.intersectionObserverForAudio.disconnect()
    }
    if (this.$refs.audio && !this.$refs.audio.paused) {
      this.$refs.audio.pause()
    }
    this.firstIn = true
  },
  methods: {
    onFrameLoad(idx) {
      this.frameStateList[idx] = true
    },
    onFrameError(idx) {
      this.frameStateList[idx] = false
    },
    play() {
      if (this.isPlaying) {
        return
      }
      this.isPlaying = true
      this.frameCurNum = 0
      this.frameIntervalId = setInterval(() => {
        if (this.isPaused) {
          return
        }

        const frameNumBackup = this.frameCurNum
        this.frameCurNum++
        if (this.frameCurNum === this.frameTotalNum) {
          if (this.repeat) {
            this.frameCurNum = 0
            this.repeatCount++
          } else {
            clearInterval(this.frameIntervalId)
            this.isPlaying = false
            this.isPaused = false
            this.$emit('over')
            return
          }
        }

        while (this.frameStateList[this.frameCurNum] === false) {
          this.frameCurNum++
          if (this.frameCurNum === this.frameTotalNum) {
            this.frameCurNum = 0
          }
        }
        if (this.frameStateList[this.frameCurNum] === undefined) {
          if (this.frameCurNum < frameNumBackup) {
            this.repeatCount--
          }
          this.frameCurNum = frameNumBackup
        }
        if (this.repeatCount === 1 && this.needMask) {
          this.isShowMask = false
        }
      }, this.frameInterval)
    },
    pause() {
      if (!this.isPlaying) {
        return
      }
      this.isPaused = true
    },
    resume() {
      if (!this.isPlaying) {
        return
      }
      this.isPaused = false
    },
    stop() {
      if (!this.isPlaying) {
        return
      }
      clearInterval(this.frameIntervalId)
      this.isPlaying = false
      this.isPaused = false
      this.frameCurNum = 0
      this.repeatCount = 0
      if (this.needMask) {
        this.isShowMask = true
      }
    },
    onAudioCurTimeChange() {
      const audioNode = this.$refs.audio
      if (!this.$refs.audio) {
        return
      }
      if (audioNode.currentTime <= 2) {
        this.audioFadeoutRate = audioNode.currentTime / 2
      }
      if (audioNode.duration - audioNode.currentTime <= 2) {
        this.audioFadeoutRate = (audioNode.duration - audioNode.currentTime) / 2
      } else {
        this.audioFadeoutRate = 1
      }
    }
  },
}
</script>

<style lang="scss" scoped>
.frames-wrap {
  text-align: left;
  flex-basis: auto;

  >img {
    height: 100%;
  }
}
</style>
