<template>
  <div>
    <video id="video" ref="video" :width="width" :height="height" autoplay>
    </video>
    <div v-if="showRecognizeButton" style="position: absolute; width: 400px; text-align: center; margin-top: -50px; color: #232323;">
      <button class="verify-button" @click="snap" :disabled="disableSnap">{{msg}}</button>
    </div>
  </div>
</template>

<script>
import { mapState as globalMapState } from "vuex";
import { createNamespacedHelpers } from "vuex";
const { mapState, mapMutations } = createNamespacedHelpers("examingHomeModule");

export default {
  name: "FaceRecognition",
  data() {
    return { disableSnap: false, msg: "开始识别" };
  },
  props: {
    width: String,
    height: String,
    showRecognizeButton: Boolean,
    closeCamera: Boolean // optional
  },
  async mounted() {
    this.openCamera();
  },
  watch: {
    snapNow(val) {
      if (val) {
        this.snapTimer();
        this.toggleSnapNow();
      }
    },
    closeCamera: function(newValue) {
      if (newValue) {
        console.log("关闭摄像头");
        this.$refs.video.srcObject.getTracks().forEach(function(track) {
          track.stop();
        });
      } else {
        this.openCamera();
      }
    }
  },
  beforeDestroy() {
    this.$refs.video.srcObject.getTracks().forEach(function(track) {
      track.stop();
    });
  },
  methods: {
    ...mapMutations(["toggleSnapNow", "decreaseSnapCount"]),
    async openCamera() {
      const video = this.$refs.video;
      if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
        try {
          console.log("启动摄像头");
          const stream = await navigator.mediaDevices.getUserMedia({
            video: {
              facingMode: "user"
              // width: 400,
              // height: this.showRecognizeButton ? 300 : 250
            }
          });

          video.srcObject = stream;
          video.play();
        } catch (error) {
          console.log(error);
          this.$Message.error("无法启用摄像头");
        }
      } else {
        this.$Message.error("没有找到可用的摄像头");
      }
    },
    async snapTimer() {
      const captureBlob = await this.getSnapShot();
      const [fileName, captureFilePath] = await this.uploadToServer(
        captureBlob
      );
      this.decreaseSnapCount();
      await this.faceCompare(fileName, captureFilePath);
      const video = this.$refs.video;
      video && video.play();
    },
    async snap() {
      this.disableSnap = true;
      this.msg = "拍照中...";
      const captureBlob = await this.getSnapShot();
      this.msg = "上传照片中...";
      const [, captureFilePath] = await this.uploadToServer(captureBlob);
      this.msg = "人脸比对中...";
      await this.faceCompareSync(captureFilePath);
      const video = this.$refs.video;
      video && video.play();
      this.msg = "开始识别";
      this.disableSnap = false;
    },
    async getSnapShot() {
      return new Promise(resolve => {
        const video = this.$refs.video;
        video.pause();
        var canvas = document.createElement("canvas");
        canvas.width = 220;
        canvas.height = 165;

        var context = canvas.getContext("2d");
        context.drawImage(video, 0, 0, 220, 165);

        canvas.toBlob(resolve);
      });
    },
    async uploadToServer(captureBlob) {
      //保存抓拍照片到又拍云
      var fileName = new Date().getTime() + ".jpg";
      var fileUrl = "/capture_photo/" + this.user.userId + "/" + fileName;
      try {
        await this.$upyunhttp.put(fileUrl, captureBlob, {
          headers: {
            "Content-Type": "image/jpeg"
          }
        });
      } catch (e) {
        console.log(e);
        this.$Message.error(e.message);
        return;
      }

      const UPYUN_URL = (await this.$http.get("/api/ecs_oe_student_face/upyun"))
        .data.downloadPrefix;

      return [
        fileName,
        UPYUN_URL + "/capture_photo/" + this.user.userId + "/" + fileName
      ];
    },
    async faceCompareSync(captureFilePath) {
      try {
        const res = await this.$http.post(
          "/api/ecs_oe_student_face/examCaptureQueue/compareFaceSync?fileUrl=" +
            captureFilePath
        );

        // TODO: 识别成功、失败的通知或跳转
        this.$emit("on-recognize-result", {
          error: null,
          pass: res.data.isPass,
          stranger: res.data.isStranger
        });
      } catch (e) {
        console.log(e);
        this.$Message.error(e.message);
        return;
      }
    },
    async faceCompare(fileName, captureFilePath) {
      try {
        await this.$http.post(
          "/api/ecs_oe_student_face/examCaptureQueue/uploadExamCapture?fileUrl=" +
            captureFilePath +
            "&fileName=" +
            fileName +
            "&examRecordDataId=" +
            this.$route.params.examRecordDataId
        );
        const examRecordDataId = this.$route.params.examRecordDataId;
        await this.showSnapResult(fileName, examRecordDataId);
      } catch (e) {
        console.log(e);
        this.$Message.error(e.message);
        return;
      }
    },
    async showSnapResult(fileName, examRecordDataId) {
      try {
        // 获取抓拍结果
        const snapRes =
          (await this.$http.get(
            "/api/ecs_oe_student_face/examCaptureQueue/getExamCaptureResult?fileName=" +
              fileName +
              "&examRecordDataId=" +
              examRecordDataId
          )).data || {};
        if (this.$route.name !== "OnlineExamingHome") {
          // 非考试页，不显示结果，也不继续查询
          return;
        }
        if (snapRes.isCompleted) {
          if (snapRes.isStranger) {
            this.$Message.error("请独立考试");
          } else if (!snapRes.isPass) {
            this.$Message.error("请保持正确坐姿");
          }
        } else {
          setTimeout(
            this.showSnapResult.bind(this, fileName, examRecordDataId),
            30 * 1000
          );
        }
      } catch (e) {
        console.log(e);
        this.$Message.error(e.message);
      }
    }
  },
  computed: {
    ...globalMapState(["user"]),
    ...mapState(["snapNow"])
  }
};
</script>

<style scoped>
.verify-button {
  font-size: 16px;
  background-color: #ffcc00;
  display: inline-block;
  padding: 6px 16px;
  border-radius: 6px;
}

.verify-button:hover {
  color: #444444;
  cursor: pointer;
}
</style>
