<template>
  <m-dialog title="拍照识别" :visible.sync="show" widthType="2" :footer="false">
    <div class="box" ref="box">
      <video
        ref="video"
        autoplay
        playsinline
      ></video>
      <canvas ref="canvas"></canvas>
    </div>
  </m-dialog>
</template>

<script>
import MDialog from '@/components/Dialog'
export default {
  name: 'm-camera',
  components: {
    MDialog
  },
  data () {
    return {
      show: false,
      videoStream: null,
      animationId: null
    }
  },
  methods: {
    open () {
      this.startCamera()
    },
    oGetUserMedia (constraints) {
      const getUserMedia = navigator.mediaDevices?.getUserMedia ||
                          navigator.getUserMedia ||
                          navigator.webkitGetUserMedia ||
                          navigator.mozGetUserMedia ||
                          navigator.msGetUserMedia ||
                          navigator.oGetUserMedia

      return new Promise((resolve, reject) => {
        if (!getUserMedia) {
          return reject(new Error('当前浏览器不支持，请更换浏览器再尝试'))
        }
        getUserMedia.call(navigator.mediaDevices || navigator, constraints)
          .then(resolve)
          .catch(_ => {
            const str = '相机打开失败'
            reject(str)
          })
      })
    },
    async startCamera () {
      try {
        this.videoStream = await this.oGetUserMedia({
          video: { facingMode: 'user' }
        })
        this.show = true
        this.$emit('rendered')
        this.$nextTick(() => {
          // 设置容器大小
          const video = this.$refs.video
          video.srcObject = this.videoStream
          video.onloadedmetadata = () => {
            video.play()
            setTimeout(() => {
              this.resizeCanvas()
              this.drawToCanvas()
            }, 500)
          }
        })
      } catch (error) {
        this.$snackbar.error(error)
      }
    },
    resizeCanvas () {
      const { width: boxWidth } = this.$refs.box.getBoundingClientRect()
      const { width, height } = this.$refs.video.getBoundingClientRect()
      const rate = width / height
      const canvas = this.$refs.canvas
      canvas.width = boxWidth
      canvas.height = boxWidth / rate
    },
    drawToCanvas () {
      const canvas = this.$refs.canvas
      const context = canvas.getContext('2d')
      const video = this.$refs.video
      // 将视频画面绘制到canvas上
      const drawFrame = () => {
        context.clearRect(0, 0, canvas.width, canvas.height)
        context.save()
        // 水平翻转画布
        context.scale(-1, 1)
        // 在翻转的画布上绘制视频，调整绘制位置
        context.drawImage(video, -canvas.width, 0, canvas.width, canvas.height)
        // 恢复画布状态
        context.restore()
        this.animationId = requestAnimationFrame(drawFrame)
      }

      // 开始动画循环
      drawFrame()
    },
    async handleTake () {
      const canvas = this.$refs.canvas
      // 使用 toDataURL 方法获取 Base64 图像数据
      const img = canvas.toDataURL('image/png') // 可以选择其他格式如 'image/jpeg'
      try {
        const response = await fetch(img)
        const blob = await response.blob()
        const file = new File([blob], 'canvasImage.png', { type: 'image/png' })
        const query = new FormData()
        query.append('file', file)
      } catch (error) {
        this.$snackbar.error(error)
      }
    }
  },
  beforeDestroy () {
    // 停止视频流和动画
    if (this.videoStream) {
      this.videoStream.getTracks().forEach(track => track.stop())
    }
    if (this.animationId) {
      cancelAnimationFrame(this.animationId)
    }
  }
}
</script>

<style lang="scss" scoped>
.box {
  position: relative;
  width: 100%;
  video {
    z-index: -1;
    width: 100%;
    position: absolute;
  }
  canvas {
    display: block;
  }
}
</style>
