<template>
  <div v-if="exam && examQuestion()" class="container" :key="exam.id">
    <div class="header">
      <RemainTime></RemainTime>
      <OverallProgress :exam-question-list="examQuestionList"></OverallProgress>
      <QuestionFilters :exam-question-list="examQuestionList"></QuestionFilters>
      <i-button class="qm-primary-button" @click="submitPaper">交卷</i-button>
    </div>
    <div class="main" id="examing-home-question">
      <QuestionView :exam-question="examQuestion()"></QuestionView>
      <ArrowNavView
        :previousQuestionOrder="previousQuestionOrder"
        :nextQuestionOrder="nextQuestionOrder"
      ></ArrowNavView>
    </div>
    <div :class="['side', 'side-row-size']">
      <div :class="['question-nav', !faceEnable && 'question-nav-long']">
        <QuestionNavView :paperStruct="paperStruct" />
      </div>
      <div v-if="faceEnable" class="camera">
        <FaceRecognition
          v-if="faceEnable"
          width="100%"
          height="100%"
          :showRecognizeButton="false"
        />
      </div>
    </div>
    <Modal
      v-model="showFaceId"
      :mask-closable="false"
      :closable="false"
      width="800"
      :styles="{ top: '10px' }"
    >
      <FaceId v-if="showFaceId" @closeFaceId="closeFaceId" />
      <p slot="footer"></p>
    </Modal>
    <FaceTracking v-if="faceEnable && PRODUCTION" />
  </div>
  <div v-else>
    正在等待数据返回...
    <i-button class="qm-primary-button" v-if="timeouted" @click="reloadPage">
      重试
    </i-button>
  </div>
</template>

<script>
import RemainTime from "./RemainTime.vue";
import OverallProgress from "./OverallProgress.vue";
import QuestionFilters from "./QuestionFilters.vue";
import QuestionView from "./QuestionView.vue";
import ArrowNavView from "./ArrowNavView.vue";
import QuestionNavView from "./QuestionNavView.vue";
import FaceTracking from "./FaceTracking.vue";
import FaceId from "./FaceId.vue";
import FaceRecognition from "../../../components/FaceRecognition/FaceRecognition";
import { openWS, closeWsWithoutReconnect } from "./ws.js";
import { createNamespacedHelpers } from "vuex";
const { mapState, mapMutations } = createNamespacedHelpers("examingHomeModule");

export default {
  name: "ExamingHome",
  data() {
    return {
      showFaceId: false,
      faceEnable: false,
      timeouted: false,
      PRODUCTION: process.env.NODE_ENV === "production"
    };
  },
  async created() {
    this.timeoutTimeout = setTimeout(() => (this.timeouted = true), 30 * 1000);

    // 仅在线上使用活体检测
    if (
      process.env.NODE_ENV === "production" &&
      /^\d+$/.test(this.$route.query.faceVerifyMinute)
    ) {
      const enoughTimeForFaceId = this.remainTime // 如果remainTime取到了的话
        ? this.remainTime / (60 * 1000) - 1 > this.$route.query.faceVerifyMinute
        : true;
      if (!enoughTimeForFaceId) return;

      this.faceIdMsgTimeout = setTimeout(() => {
        this.serverLog("debug/S-002001", "活体检测前抓拍");
        this.toggleSnapNow();
        this.$Message.info("30秒后开始活体检测");
      }, this.$route.query.faceVerifyMinute * 60 * 1000 - 30 * 1000); // 活体检测提醒
      this.faceIdDivTimeout = setTimeout(() => {
        this.serverLog("debug/S-003001", "准备弹出活体检测框");
        this.showFaceId = true;
      }, this.$route.query.faceVerifyMinute * 60 * 1000); // 定时做活体检测
      // }, 1 * 1000); // 定时做活体检测
    }
    // for test
    // setTimeout(() => {
    //   this.showFaceId = true;
    //   // this.$Modal.remove();
    //   // }, this.$route.query.faceVerifyMinute * 60 * 1000); // 定时做活体检测
    // }, 5 * 1000); // 定时做活体检测

    let faceEnable;
    try {
      faceEnable = await this.$http.get(
        "/api/ecs_exam_work/exam/examOrgProperty/" +
          this.$route.params.examId +
          `/IS_FACE_ENABLE`
      );
    } catch (error) {
      this.$Message.error("获取人脸检测设置失败");
      this.logout("?LogoutReason=获取人脸检测设置失败");
      return;
    }

    if (faceEnable.data) {
      this.faceEnable = true;

      // setTimeout(() => {
      //   this.serverLog("debug/S-002001", "进入考试后60秒内抓拍");
      //   this.toggleSnapNow(); // 开启抓拍才在进入考试时抓拍一张
      // }, 60 * 1000); // 60内秒钟后抓拍

      let initSnapshotTrialTimes = 0;
      this.initSnapInterval = setInterval(() => {
        if (this.exam || initSnapshotTrialTimes > 12) {
          clearInterval(this.initSnapInterval);
          this.serverLog(
            "debug/S-002001",
            "进入考试后60秒内抓拍" + `(${(initSnapshotTrialTimes + 1) * 5}秒)`
          );
          this.toggleSnapNow(); // 开启抓拍才在进入考试时抓拍一张
        } else {
          initSnapshotTrialTimes++;
        }
      }, 5 * 1000);

      //       let initSnapshotTrialTimes = 0;
      // const initSnapshot = setTimeout(() => {
      //   if (this.exam || initSnapshotTrialTimes < 6) {
      //     this.serverLog("debug/S-002001", "进入考试后60秒内抓拍");
      //     this.toggleSnapNow(); // 开启抓拍才在进入考试时抓拍一张
      //   } else {
      //     setTimeout(() => initSnapshot(), 5 * 1000);
      //   }
      // }, 5 * 1000); // 60内秒钟后抓拍

      try {
        const snapshotInterval = await this.$http.get(
          "/api/ecs_exam_work/exam/examOrgProperty/" +
            this.$route.params.examId +
            `/SNAPSHOT_INTERVAL`
        );
        if (snapshotInterval.data) {
          // 考务设置抓拍间隔
          this.snapInterval = setInterval(() => {
            this.serverLog(
              "debug/S-002001",
              "根据抓拍间隔抓拍：抓拍间隔=" + snapshotInterval.data + "分钟"
            );
            this.toggleSnapNow();
          }, snapshotInterval.data * 60 * 1000);
        }
      } catch (error) {
        this.$Message.error("获取人脸抓拍间隔设置失败");
        this.logout("?LogoutReason=获取人脸抓拍间隔设置失败");
        return;
      }
    }

    try {
      await this.initData();
    } catch (error) {
      this.$Message.error("获取试卷信息失败，退出登录");
      this.logout("?LogoutReason=获取试卷信息失败");
      return;
    }

    this.submitInterval = setInterval(
      () => this.answerAllQuestions(),
      5 * 1000 // 10秒检查是否有更改需要提交答案
    );
  },
  async mounted() {
    // iview bug: https://github.com/iview/iview/issues/4061
    // document.body.style = "";

    window._hmt.push(["_trackEvent", "正在考试页面", "进入页面"]);

    if (typeof nodeRequire != "undefined") {
      try {
        var fs = window.nodeRequire("fs");
        if (fs.existsSync("multiCamera.exe")) {
          await new Promise((resolve, reject) => {
            window.nodeRequire("node-cmd").get("multiCamera.exe", () => {
              try {
                let cameraInfos = fs.readFileSync("CameraInfo.txt", "utf-8");
                if (cameraInfos && cameraInfos.trim()) {
                  cameraInfos = cameraInfos.trim();
                  cameraInfos = cameraInfos.replace(/\r\n/g, "");
                  cameraInfos = cameraInfos.replace(/\n/g, "");
                  console.log(cameraInfos);
                  this.serverLog("debug/S-001001", cameraInfos);
                }
                resolve();
              } catch (error) {
                reject("读取摄像头列表失败");
              }
            });
          });
        }
      } catch (error) {
        console.log(error);
      }
    }
  },
  beforeRouteUpdate(from, to, next) {
    window._hmt.push(["_trackEvent", "正在考试页面", "题目切换"]);
    if (process.env.NODE_ENV === "development") {
      console.log("beforeRouteUpdate from: " + this.$route.fullPath);
    }
    this.answerAllQuestions();
    next();
  },
  beforeDestroy() {
    clearTimeout(this.timeoutTimeout);
    clearInterval(this.submitInterval);
    clearInterval(this.initSnapInterval);
    clearInterval(this.snapInterval);
    clearTimeout(this.faceIdMsgTimeout);
    clearTimeout(this.faceIdDivTimeout);
    closeWsWithoutReconnect();
    this.updateExamState({
      exam: null,
      paperStruct: null,
      examQuestionList: null,
      questionAudioFileUrl: []
    });
    this.$Modal.remove();
  },
  // beforeRouteUpdate(to, from, next) {
  //   this.updateQuestion(next);
  // },
  methods: {
    ...mapMutations([
      "updateExamState",
      "updateExamQuestion",
      "toggleSnapNow",
      "updateExamResult",
      "resetExamQuestionDirty"
    ]),
    async initData() {
      const [
        examData,
        paperStructData,
        examQuestionListData
      ] = await Promise.all([
        this.$http.get("/api/ecs_exam_work/exam/" + this.$route.params.examId),
        this.$http.get(
          "/api/ecs_oe_student/examRecordPaperStruct/getExamRecordPaperStruct?examRecordDataId=" +
            this.$route.params.examRecordDataId
        ),
        this.$http.get("/api/ecs_oe_student/examQuestion/findExamQuestionList")
      ]);
      const [exam, paperStruct] = [examData.data, paperStructData.data];

      let examQuestionList = examQuestionListData.data;

      if (
        exam === undefined ||
        paperStruct === undefined ||
        examQuestionListData === undefined
      ) {
        this.$Message.error("获取试卷信息失败");
        this.logout("?LogoutReason=获取试卷信息失败");
        return;
      }

      if (exam.examType === "PRACTICE") {
        const practiceType = (await this.$http.get(
          "/api/ecs_exam_work/exam/examOrgProperty/" +
            this.$route.params.examId +
            `/PRACTICE_TYPE`
        )).data;
        this.practiceType = practiceType; // IN_PRACTICE NO_ANSWER
        exam.practiceType = practiceType;
      }

      try {
        let freezeTimeData = await this.$http.get(
          "/api/ecs_exam_work/exam/examOrgProperty/" +
            this.$route.params.examId +
            `/FREEZE_TIME`
        );
        exam.freezeTime = freezeTimeData.data;
      } catch (error) {
        console.log("获取考试冻结时间失败--忽略");
      }

      // init subNumber
      let questionId = null;
      let i = 1;

      examQuestionList = examQuestionList.map(eq => {
        if (questionId == eq.questionId) {
          eq.subNumber = i++;
        } else {
          i = 1;
          questionId = eq.questionId;
          eq.subNumber = i++;
        }
        return eq;
      });

      let groupOrder = 1;
      let mainNumber = 0;
      examQuestionList = examQuestionList.map(eq => {
        if (mainNumber == eq.mainNumber) {
          eq.groupOrder = groupOrder++;
        } else {
          mainNumber = eq.mainNumber;
          groupOrder = 1;
          eq.groupOrder = groupOrder++;
        }

        const questionWrapperList =
          paperStruct.defaultPaper.questionGroupList[eq.mainNumber - 1]
            .questionWrapperList;
        const groupName =
          paperStruct.defaultPaper.questionGroupList[eq.mainNumber - 1]
            .groupName;
        const groupTotal = questionWrapperList.reduce(
          (accumulator, questionWrapper) =>
            accumulator + questionWrapper.questionUnitWrapperList.length,
          0
        );

        eq.groupName = groupName;
        eq.groupTotal = groupTotal;
        return eq;
      });

      examQuestionList = examQuestionList.map(eq => {
        const paperStructQuestion = paperStruct.defaultPaper.questionGroupList[
          eq.mainNumber - 1
        ].questionWrapperList.find(q => q.questionId === eq.questionId);
        return Object.assign(eq, {
          limitedPlayTimes: paperStructQuestion.limitedPlayTimes
        });
      });

      this.updateExamState({
        exam: exam,
        paperStruct: paperStruct,
        examQuestionList: examQuestionList,
        allAudioPlayTimes: JSON.parse(examQuestionList[0].audioPlayTimes) || [],
        questionAudioFileUrl: []
      });
      // console.log(examQuestionList);
      // console.log(examQuestionList.find(v => v.answerType === "SINGLE_AUDIO"));
      if (examQuestionList.find(v => v.answerType === "SINGLE_AUDIO")) {
        // console.log("have single");
        const examRecordDataId = this.$route.params.examRecordDataId;
        openWS({ examRecordDataId });
      }
    },
    updateQuestion: async function(next) {
      // 初始化套题的答案，为回填部分选项做准备
      // for (let q of this.examQuestionList) {
      //   if (q.subQuestionList.length > 0) {
      //     q.studentAnswer = [];
      //     for (let sq of q.subQuestionList) {
      //       q.studentAnswer.push(sq.studentAnswer);
      //     }
      //   }
      // }

      next && next();
      if (!this.exam) return;
    },
    closeFaceId() {
      this.showFaceId = false;
    },
    async answerAllQuestions(ignoreDirty) {
      const answers = this.examQuestionList
        .filter(eq => !ignoreDirty && eq.dirty)
        .filter(eq => eq.getQuestionContent)
        .map(eq => {
          return Object.assign(
            {
              order: eq.order,
              studentAnswer: eq.studentAnswer
            },
            eq.audioPlayTimes && { audioPlayTimes: eq.audioPlayTimes },
            eq.isSign && { isSign: eq.isSign }
          );
        });
      if (answers.length > 0) {
        try {
          await this.$http.post(
            "/api/ecs_oe_student/examQuestion/submitQuestionAnswer",
            answers
          );
          this.resetExamQuestionDirty();
        } catch (error) {
          console.log(error);
          this.$Message.error("提交答案失败");
          window._hmt.push([
            "_trackEvent",
            "正在考试页面",
            "提交答案失败",
            error.message +
              " |||| " +
              (((error.response || {}).data || {}).desc || "")
          ]);
          this.serverLog(
            "debug/S-008001",
            `提交答案失败 => 考试剩余时间：${this.remainTime / 1000}`
          );
        }
      }
    },
    async submitPaper() {
      try {
        // 交卷前强制提交所有答案
        await this.answerAllQuestions(true);
      } catch (error) {
        return;
      }

      if (
        this.exam.freezeTime &&
        this.remainTime >
          (this.exam.duration - this.exam.freezeTime) * 60 * 1000
      ) {
        this.$Message.info({
          content: `考试开始${this.exam.freezeTime}分钟后才允许交卷。`,
          duration: 5,
          closable: true
        });
        return;
      }

      const answered = this.examQuestionList.filter(
        q => q.studentAnswer !== null
      ).length;
      const unanswered = this.examQuestionList.filter(
        q => q.studentAnswer === null
      ).length;
      const signed = this.examQuestionList.filter(q => q.isSign).length;
      this.$Modal.confirm({
        title: "确认交卷",
        content: `<p>已答题目：${answered}</p><p>未答题目：${unanswered}</p><p>标记题目：${signed}</p>`,
        onOk: this.realSubmitPaper
      });
    },
    async realSubmitPaper() {
      this.$Spin.show({
        render: () => {
          return <div style="font-size: 44px">正在交卷，请耐心等待...</div>;
        }
      });
      if (this.faceEnable) {
        this.serverLog("debug/S-002001", "交卷前抓拍");
        this.toggleSnapNow();
      }
      // 确保抓拍指令在交卷前执行
      setTimeout(() => this.realSubmitPaperStep2(), 1000);
      this.submitCount = 1;
    },
    async realSubmitPaperStep2() {
      if (this.snapProcessingCount > 0) {
        this.submitCount++;
        if (this.submitCount < 200) {
          // 一分钟后，强制交卷
          setTimeout(() => this.realSubmitPaperStep2(), 300);
          return;
        }
      }
      if (this.submitLock) {
        return;
      } else {
        this.submitLock = true;
      }

      if (this.$route.name !== "OnlineExamingHome") {
        // 非考试页，不在交卷
        this.$Spin.hide();
        return;
      }
      try {
        const examId = this.$route.params.examId;
        const examRecordDataId = this.$route.params.examRecordDataId;
        const res = await this.$http.get(
          "/api/ecs_oe_student/examControl/endExam"
        );
        if (res.status === 200) {
          this.$router.replace({
            path: `/online-exam/exam/${examId}/examRecordData/${examRecordDataId}/end`
          });
          // 确保交卷成功后，不会再次交卷
          this.submitLock = true;
          this.$Spin.hide();
          return;
        } else {
          this.$Message.error("交卷失败");
        }
        this.submitLock = false;
      } catch (e) {
        this.$Message.error("交卷失败");
        console.log(e);
      }
      this.submitLock = false;
      this.$Spin.hide();
      closeWsWithoutReconnect();
    },
    examQuestion() {
      return (
        this.examQuestionList &&
        this.examQuestionList.find(
          eq => eq.order == this.$route.params.order // number == string
        )
      );
    },
    reloadPage() {
      window._hmt.push([
        "_trackEvent",
        "正在考试页面",
        "页面加载失败",
        "reload"
      ]);
      window.location.reload();
    }
  },
  computed: {
    ...mapState([
      "exam",
      "paperStruct",
      "examQuestionList",
      "snapNow",
      "snapProcessingCount",
      "shouldSubmitPaper",
      "remainTime",
      "questionAudioFileUrl"
    ]),
    previousQuestionOrder: vm => {
      if (vm.examQuestion().order > 1) {
        return vm.examQuestion().order - 1;
      } else {
        return null;
      }
    },
    nextQuestionOrder: vm => {
      if (vm.examQuestion().order < vm.examQuestionList.length) {
        return vm.examQuestion().order + 1;
      } else {
        return null;
      }
    }
  },
  watch: {
    $route: function() {
      this.examQuestion();
    },
    shouldSubmitPaper() {
      this.realSubmitPaper();
    },
    questionAudioFileUrl(value) {
      // console.log(this.examQuestion.studentAnswer);
      // console.log("watch", value);
      const examRecordDataId = this.$route.params.examRecordDataId;
      const that = this;
      for (const q of value) {
        if (!q.saved) {
          this.$http
            .post(
              "/api/ecs_oe_student/examControl/confirmAudioUploadSaveStatus",
              {
                examRecordDataId,
                filePath: q.audioFileUrl,
                order: q.order
              }
            )
            .then(() => {
              that.updateExamQuestion({
                order: q.order,
                studentAnswer: q.audioFileUrl
              });
              q.saved = true;
              this.$Message.info("音频题作答已更新");
            })
            .catch(() => {
              this.$Message.error({
                content: "更新音频题答案失败！",
                duration: 10,
                closable: true
              });
            });
        }
      }
    }
    // examQuestionList(val, oldVal) {
    //   // console.log(val, oldVal);
    // }
  },
  components: {
    RemainTime,
    OverallProgress,
    QuestionFilters,
    QuestionView,
    ArrowNavView,
    QuestionNavView,
    FaceRecognition,
    FaceId,
    FaceTracking
  }
};
</script>

<style scoped>
.container {
  display: grid;
  grid-template-areas:
    "header header"
    "main side";
  grid-template-rows: 80px minmax(0, 1fr);
  grid-template-columns: 1fr 400px;

  height: 100vh;
  width: 100vw;
}

.header {
  display: grid;
  align-items: center;
  justify-items: center;
  grid-template-columns: 200px 1fr 300px 100px;
  grid-area: header;
  height: 80px;
  background-color: #f5f5f5;
}

.main {
  display: grid;
  grid-area: main;
  grid-template-rows: 1fr 50px;
}

.side {
  display: grid;
  grid-area: side;
  grid-template-rows: 1fr 250px;
  background-color: #f5f5f5;
}

.side-row-size {
  grid-template-rows: 1fr;
}

.question-nav {
  overflow-y: scroll;
  max-height: calc(100vh - 300px);
}

.question-nav-long {
  max-height: calc(100vh - 100px);
}

.camera {
  align-self: flex-end;
  justify-self: flex-end;
}

@media screen and (max-height: 768px) {
  .container {
    grid-template-rows: 50px minmax(0, 1fr);
  }
  .header {
    height: 50px;
  }
  .side {
    grid-template-rows: minmax(0, 1fr) 200px;
  }
}
</style>

<style>
#examing-home-question img {
  max-width: 100%;
  height: auto !important;
}
</style>
