<template>
  <div
    class="treasure-display"
  >
    <img
      v-if="['idle', 'fade-in'].includes(displayState)"
      ref="treasure"
      class="treasure"
      :style="{
        height: treasureInitialHeightPercent + '%',
        opacity: treasureOpacity,
      }"
      src="@/assets/treasure.png"
      alt=""
      @dragstart.prevent
    >
    <button
      v-if="displayState !== 'idle'"
      class="btn-stop-treasure-display"
      @click="stopDisplay"
    >
      <img
        src="@/assets/button-stop.png"
        alt=""
      >
    </button>
    <SerialFrames
      v-show="displayState === 'display'"
      ref="treasure-serial-frames"
      class="treasure-serial-frames"
      :frame-total-num="treasureFrameTotalNum"
      :frame-interval="40"
      :image-src-func="(index) => require(`@/assets/treasure-frames/3_${(index - 1).toString().padStart(5, '0')}.jpg`)"
      @over="onSerialFramesOver"
    />
    <div
      v-if="displayState !== 'idle'"
      class="fade-mask"
      :style="{
        opacity: maskOpacity,
      }"
    >
      <img
        v-show="displayState === 'fade-out'"
        src="@/assets/treasure-last-frame.jpg"
        alt=""
      >
    </div>
  </div>
</template>

<script>
import TWEEN from '@tweenjs/tween.js'

export default {
  props: {
    treasureFadeInDuration: {
      type: Number,
      default: 3000,
    },
    treasureFadeOutDuration: {
      type: Number,
      default: 2000,
    },
    treasureFrameTotalNum: {
      type: Number,
      required: true,
    },
    treasureInitialHeightPercent: {
      type: Number,
      required: true, // 0~100
    },
    treasureFrameWidth: {
      type: Number,
      required: true, // 单位：px
    },
    treasureFrameHeight: {
      type: Number,
      required: true, // 单位：px
    },
  },
  emits: ['display-started', 'display-stopped'],
  data() {
    return {
      // 动画帧相关
      animationFrameId: null,

      displayState: 'idle', // idle, fade-in, display, fade-out

      // 文物淡入相关
      treasureFadeInProgress: {
        value: 0, // 0~100
      },
      treasureFadeInInitialLeft: 0,
      treasureFadeInInitialTop: 0,
      treasureFadeInFinalLeft: 0,
      treasureFadeInFinalTop: 0,
      treasureFinalHeightPercent: 0, // 0~100
      treasureFadeInTween: null,

      // 文物淡出相关
      treasureFadeOutProgress: {
        value: 0, // 0~100
      },
      treasureFadeOutTween: null,
    }
  },
  computed: {
    treasureOpacity() {
      if (this.displayState === 'fade-in') {
        if (this.treasureFadeInProgress.value > 50) {
          return 1
        } else {
          return this.treasureFadeInProgress.value / 50
        }
      } else if (this.displayState === 'fade-out') {
        if (this.treasureFadeOutProgress.value < 50) {
          return 1
        } else {
          return 1 - (this.treasureFadeOutProgress.value - 50) / 50
        }
      } else {
        return 0
      }
    },
    maskOpacity() {
      if (this.displayState === 'fade-in') {
        if (this.treasureFadeInProgress.value > 50) {
          return 1
        } else {
          return this.treasureFadeInProgress.value / 50
        }
      } else if (this.displayState === 'display') {
        return 1
      } else if (this.displayState === 'fade-out') {
        return (100 - this.treasureFadeOutProgress.value) / 100
      } else {
        return 0
      }
    },
  },
  watch: {
    'treasureFadeInProgress.value': {
      handler(vNew, vOld) {
        if (this.treasureFadeInProgress.value > 50) {
          this.$refs.treasure.style.left = this.treasureFadeInInitialLeft + (this.treasureFadeInProgress.value - 50) / 50 * (this.treasureFadeInFinalLeft - this.treasureFadeInInitialLeft) + 'px'
          this.$refs.treasure.style.top = this.treasureFadeInInitialTop + (this.treasureFadeInProgress.value - 50) / 50 * (this.treasureFadeInFinalTop - this.treasureFadeInInitialTop) + 'px'
          this.$refs.treasure.style.transform = `translate(-50%, -50%) scale(${1 + (this.treasureFadeInProgress.value - 50) / 50 * (this.treasureFinalHeightPercent / this.treasureInitialHeightPercent - 1)})`
        } else {
          this.$refs.treasure.style.left = this.treasureFadeInInitialLeft + 'px'
          this.$refs.treasure.style.top = this.treasureFadeInInitialTop + 'px'
          this.$refs.treasure.style.transform = `translate(-50%, -50%) scale(1)`
        }
      }
    },
  },
  mounted() {
    const that = this
    this.animationFrameId = requestAnimationFrame(this.animationFrameTask)

    this.treasureFadeInTween = new TWEEN.Tween(that.treasureFadeInProgress)
    this.treasureFadeInTween.to({
      value: 100,
    }, this.treasureFadeInDuration)
    this.treasureFadeInTween.onComplete(() => {
      this.displayState = 'display'
      this.$refs['treasure-serial-frames'].play()
    })
    this.treasureFadeInTween.easing(TWEEN.Easing.Linear.None)

    this.treasureFadeOutTween = new TWEEN.Tween(that.treasureFadeOutProgress)
    this.treasureFadeOutTween.to({
      value: 100,
    }, this.treasureFadeOutDuration)
    this.treasureFadeOutTween.onComplete(() => {
      this.displayState = 'idle'
      this.$emit('display-stopped')
    })
    this.treasureFadeOutTween.easing(TWEEN.Easing.Linear.None)
  },
  unmounted() {
    cancelAnimationFrame(this.animationFrameId)
    this.treasureFadeInTween.stop()
    this.treasureFadeOutTween.stop()
    clearInterval(this.treasureFrameIntervalId)
  },
  methods: {
    animationFrameTask() {
      TWEEN.update()
      this.animationFrameId = requestAnimationFrame(this.animationFrameTask)
    },

    startDisplay() {
      if (this.displayState !== 'idle') {
        return
      }

      // 计算淡入过渡的起始终止位置
      this.treasureFadeInInitialLeft = this.$refs.treasure.offsetLeft
      this.treasureFadeInInitialTop = this.$refs.treasure.offsetTop
      this.treasureFadeInFinalLeft = window.innerWidth / 2 - this.$refs.treasure.offsetParent.offsetLeft
      this.treasureFadeInFinalTop = window.innerHeight / 2 - this.$refs.treasure.offsetParent.offsetTop

      // 计算淡入过渡终止时文物需要放大的倍数
      const viewportRatio = window.innerWidth / window.innerHeight
      const frameRatio = this.treasureFrameWidth / this.treasureFrameHeight
      if (viewportRatio >= frameRatio) { // 视口比序列帧扁，序列帧高度会缩放到和视口相同，所以序列帧的第一帧作为淡入时的文物图片，也缩放到和视口等高即可。
        this.treasureFinalHeightPercent = 100
      } else { // 视口比序列帧窄，序列帧宽度会缩放到和视口相同，所以序列帧的第一帧作为淡入时的文物图片，也缩放到和视口等宽即可。
        const treasureFinalHeight = this.treasureFrameHeight / this.treasureFrameWidth * window.innerWidth
        this.treasureFinalHeightPercent = treasureFinalHeight / window.innerHeight * 100
      }

      this.displayState = 'fade-in'
      this.treasureFadeInTween.start()
      this.$emit('display-started')
    },
    stopDisplay() {
      this.displayState = 'idle'
      this.treasureFadeInTween.stop()
      this.treasureFadeOutTween.stop()
      this.$refs['treasure-serial-frames'].stop()
      if (this.$refs.treasure) {
        this.$refs.treasure.style.left = this.treasureFadeInInitialLeft + 'px'
        this.$refs.treasure.style.top = this.treasureFadeInInitialTop + 'px'
        this.$refs.treasure.style.transform = `translate(-50%, -50%) scale(1)`
      }
      this.$emit('display-stopped')
    },
    onSerialFramesOver() {
      this.displayState = 'fade-out'
      this.treasureFadeOutTween.start()
    },
  },

}
</script>

<style lang="less" scoped>
.treasure-display {
  .treasure {
    position: absolute;
    left: 49%;
    top: 32.5%;
    z-index: 2;
    transform: translate(-50%, -50%);
  }
  .fade-mask {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: #bfbfa7;
    z-index: 1;
    img {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }
  }
  .btn-stop-treasure-display {
    position: fixed;
    top: 20px;
    right: 20px;
    z-index: 4;
    border: none;
  }
  .treasure-serial-frames {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 3;
  }
}
</style>