<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) {
        if (!this.lastSnapTime || Date.now() - this.lastSnapTime > 60 * 1000) {
          this.lastSnapTime = Date.now();
          this.snapTimer();
        } else {
          this.serverLog(
            "debug/S-002001",
            "上次的抓拍未超过1分钟，本次抓拍指令取消"
          );
          this.decreaseSnapCount();
        }
        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
            }
          });
          if (stream) {
            video.srcObject = stream;
            try {
              await video.play();
            } catch (error) {
              this.$Message.error({
                content: "摄像头没有正常启用",
                duration: 5
              });
            }
          } else {
            this.$Message.error("没有可用的视频流");
          }
        } catch (error) {
          console.log(error);
          this.$Message.error("无法启用摄像头");
        }
      } else {
        this.$Message.error("没有找到可用的摄像头");
      }
    },
    async snapTimer() {
      try {
        const examRecordDataId = this.$route.params.examRecordDataId;
        const captureBlob = await this.getSnapShot();
        // console.log(captureBlob.size);
        this.serverLog("debug/S-004001", "抓拍照片的大小：" + captureBlob.size);
        const captureFilePath = await this.uploadToServer(captureBlob);
        await this.faceCompare(captureFilePath, examRecordDataId);
      } catch (error) {
        // FIXME: more processing
        console.log("定时抓拍流程失败");
      } finally {
        const video = this.$refs.video;
        video && video.play();
        this.decreaseSnapCount();
      }
    },
    async snap() {
      // TODO: chrome 70. FaceDetector检测人脸
      // var canvas = document.createElement("canvas");
      // canvas.width = 220;
      // canvas.height = 165;

      // var context = canvas.getContext("2d");
      // context.drawImage(this.$refs.video, 0, 0, 220, 165);
      // var f = new FaceDetector();
      // const v = await f.detect(canvas);
      // console.log(v);
      // return;

      this.$Message.destroy();
      try {
        this.disableSnap = true;
        // console.log("disableSnap: " + this.disableSnap);
        // await new Promise(resolve =>
        //   setTimeout(() => {
        //     console.log(new Date());
        //     resolve();
        //   }, 3000)
        // );
        // return;
        // if(this.disableSnap) return; // 避免界面没有更新。
        this.msg = "拍照中...";
        const captureBlob = await this.getSnapShot();
        this.msg = "上传照片中...";
        const captureFilePath = await this.uploadToServer(captureBlob);
        this.msg = "人脸比对中...";
        await this.faceCompareSync(captureFilePath);
      } catch (error) {
        // FIXME: more processing
        console.log("同步照片比对流程失败");
        throw error;
      } finally {
        const video = this.$refs.video;
        video && video.play();
        this.msg = "开始识别";
        this.disableSnap = false;
      }
    },
    async getSnapShot() {
      return new Promise((resolve, reject) => {
        const video = this.$refs.video;
        if (video.readyState !== 4 || !video.srcObject.active) {
          this.$Message.error({ content: "摄像头没有正常启用", duration: 5 });
          reject("摄像头没有正常启用");
          this.logout();
          return;
        }
        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, "image/jpeg", 0.95);
      });
    },
    async uploadToServer(captureBlob) {
      //保存抓拍照片到服务器
      // var fileName = new Date().getTime() + ".png";
      // var fileUrl = "/api/exchange/inner/upyun/put/capturePhoto/" + fileName;
      var fileUrl = "/api/exchange/inner/upyun/put/capturePhoto/jpg";
      let resultUrl;
      try {
        const res = await this.$http.put(fileUrl, captureBlob, {
          headers: {
            "Content-Type": "image/jpg"
          }
        });
        resultUrl = res.data;
      } catch (e) {
        console.log(e);
        this.$Message.error("保存抓拍照片到服务器失败！");
        throw "保存抓拍照片到服务器失败！";
      }

      // let UPYUN_URL;
      // try {
      //   UPYUN_URL = (await this.$http.get("/api/ecs_oe_student_face/upyun"))
      //     .data.downloadPrefix;
      // } catch (error) {
      //   this.$Message.error("获取照片下载前缀失败！");
      //   throw "获取照片下载前缀失败！";
      // }
      return resultUrl;
    },
    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);
        throw "同步照片比较失败！";
      }
    },
    async faceCompare(captureFilePath, examRecordDataId) {
      try {
        const res = await this.$http.post(
          "/api/ecs_oe_student_face/examCaptureQueue/uploadExamCapture?fileUrl=" +
            captureFilePath +
            "&examRecordDataId=" +
            examRecordDataId
        );
        const fileName = res.data;
        try {
          await this.showSnapResult(fileName, examRecordDataId);
        } catch (error) {
          this.$Message.error("设置获取抓拍结果失败！");
        }
      } catch (e) {
        console.log(e);
        this.$Message.error(e.message);
        throw "异步比较抓拍照片失败";
      }
    },
    async showSnapResult(fileName, examRecordDataId) {
      if (!fileName) return; // 交卷后提交照片会得不到照片名称

      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({
              content: "请独立完成考试",
              duration: 5,
              closable: true
            });
          } else if (!snapRes.isPass) {
            this.$Message.error({
              content: "请调整坐姿，诚信考试",
              duration: 5,
              closable: true
            });
          }
        } else {
          setTimeout(
            this.showSnapResult.bind(this, fileName, examRecordDataId),
            30 * 1000
          );
        }
      } catch (e) {
        console.log(e);
        if (this.$route.name !== "OnlineExamingHome") {
          // 非考试页，不显示结果，也不继续查询
          return;
        }
        this.$Message.error(e.message);
        throw 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>
