<template>
  <div class="question-import-edit">
    <el-dialog
      custom-class="question-import-edit-dialog"
      :visible.sync="modalIsShow"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      append-to-body
      fullscreen
      destroy-on-close
      :show-close="false"
      @opened="visibleChange"
      @closed="initData"
    >
      <div slot="title">
        <div class="box-justify">
          <div>
            <h2>文件上传</h2>
          </div>
          <div style="display: flex; align-items: center">
            <el-button
              style="margin-left: 10px"
              size="mini"
              type="danger"
              @click="cancel"
              >返回</el-button
            >
          </div>
        </div>
        <div class="head-form">
          <el-form ref="modalFormComp" :model="modalForm" :rules="rules" inline>
            <el-form-item prop="courseId" label="课程名称：">
              <course-select
                v-model="modalForm.courseId"
                @change="courseChange"
              >
              </course-select>
            </el-form-item>
            <el-form-item>
              <el-checkbox v-model="modalForm.useOriginalPaper"
                >是否以导入试题同步生成试卷</el-checkbox
              >
            </el-form-item>
            <template v-if="modalForm.useOriginalPaper">
              <el-form-item>
                <el-input
                  v-model="modalForm.name"
                  placeholder="请输入试卷名称"
                ></el-input>
              </el-form-item>
              <el-form-item>
                <el-checkbox v-model="modalForm.checkTotalScore"
                  >是否校验导入试卷总分</el-checkbox
                >
              </el-form-item>
              <el-form-item v-if="modalForm.checkTotalScore">
                <el-input-number
                  v-model="modalForm.totalScore"
                  style="width: 80px"
                  :min="1"
                  :max="1000"
                  :step="1"
                  step-strictly
                  :controls="false"
                ></el-input-number>
              </el-form-item>
            </template>
          </el-form>
        </div>
      </div>
      <div class="qe-body">
        <div class="qe-part qe-part-edit">
          <div class="qe-part-main">
            <div class="qe-part-head">
              <div class="qe-part-head-title">
                <h3>题目编辑</h3>
                <div>
                  <el-button
                    size="small"
                    type="primary"
                    plain
                    icon="icon icon-edit-warning"
                    @click="showDocx"
                    >录入说明</el-button
                  >

                  <el-button
                    size="small"
                    type="primary"
                    plain
                    icon="icon icon-export-prop"
                    class="margin-right-10"
                    @click="getWordTemplate"
                    >模板下载</el-button
                  >
                  <upload-button
                    btn-content="上传文件"
                    btn-icon="icon icon-import"
                    :disabled="loading || !modalForm.courseId"
                    :upload-data="uploadData"
                    :upload-url="uploadUrl"
                    :format="importFileTypes"
                    @valid-error="validError"
                    @upload-success="uploaded"
                    :auto-upload="false"
                  ></upload-button>
                </div>
              </div>
              <div class="qe-part-head-desc">
                <i class="icon icon-tips"></i>
                提示：若识别有误，可点击左侧题目按格式进行修改后重新识别
              </div>
            </div>
            <div class="qe-part-body">
              <div id="qe-part-richtext-list">
                <div
                  v-for="(richJsonItem, rindex) in paperRichJsonGroup"
                  :key="rindex"
                  :class="[
                    'qe-part-richtext',
                    { 'is-error': richJsonItem.exceptions.length },
                  ]"
                >
                  <v-editor
                    ref="RichTextEditor"
                    :value="richJsonItem"
                    :show-menu="false"
                    custom-emit-input
                    :custom-render-action="renderRichText"
                    :custom-tojson-action="richTextToJSON"
                    @focus="() => richTextFocus(richJsonItem)"
                  ></v-editor>
                  <div
                    v-if="richJsonItem.exceptions.length"
                    class="qe-part-richtext-error"
                  >
                    <p
                      class="tips-info tips-error"
                      v-for="(exception, index) in richJsonItem.exceptions"
                      :key="index"
                      @click="highLightErrorText(exception)"
                      :class="{ hide: inHasIgnore(exception.indexs) }"
                    >
                      {{ exception.message }}
                    </p>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="qe-part qe-part-view">
          <div class="qe-part-main">
            <div class="qe-part-head">
              <div class="qe-part-head-title">
                <h3>题目阅览</h3>
                <div>
                  <el-button
                    size="small"
                    type="primary"
                    plain
                    icon="icon icon-export-answer"
                    @click="toImportAnswer"
                    >导入答案属性</el-button
                  >
                  <el-button
                    size="small"
                    type="primary"
                    icon="icon icon-save-white"
                    :loading="loading"
                    :disabled="!paperData.length || hasErrorTips"
                    @click="confirm"
                    >识别无误，加入题库</el-button
                  >
                </div>
              </div>
              <div class="qe-part-head-desc">
                <p class="desc-qcout">
                  <span>共识别 </span>
                  <span class="color-success">
                    {{ questionStatData.successCount }}
                  </span>
                  <span> 题，其中识别有误 </span>
                  <span class="color-danger">
                    {{ questionStatData.errorCount }}
                  </span>
                  <span> 题</span>
                </p>
                <el-checkbox
                  v-model="onlyErrorQuestion"
                  @change="onlyErrorQuestionChange"
                  >仅查看识别有误试题</el-checkbox
                >
              </div>
              <div class="qe-part-head-menu">
                <el-tabs
                  v-model="filterQuestionType"
                  @tab-click="filterQuestionTypeChange"
                >
                  <el-tab-pane
                    :label="`全部(${
                      onlyErrorQuestion
                        ? questionStatData.errorCount
                        : questionStatData.total
                    })`"
                    name="all"
                  ></el-tab-pane>
                  <el-tab-pane
                    v-for="item in questionStatData.qtypes"
                    :key="item.questionType"
                    :label="`${item.questionTypeName}(${item.questionCount})`"
                    :name="item.questionType"
                  ></el-tab-pane>
                </el-tabs>
              </div>
            </div>
            <div id="qe-part-paper" class="qe-part-body">
              <question-import-paper-edit
                v-if="filterPaperData.length"
                ref="QuestionImportPaperEdit"
                :key="questionKey"
                :paper="filterPaperData"
                :course-id="data.importData.courseId"
              ></question-import-paper-edit>
            </div>
          </div>
        </div>
        <div class="qe-middle">
          <div class="qe-middle-arrow"></div>
          <el-button
            size="small"
            type="primary"
            :loading="loading"
            @click="toParse"
            >识别</el-button
          >
        </div>
      </div>
    </el-dialog>

    <!-- 录入说明 -->
    <el-dialog
      title="录入说明"
      :visible.sync="showIframeDialog"
      append-to-body
      width="900px"
      top="30px"
    >
      <div
        style="width: 100%; height: calc(100vh - 250px); overflow: auto"
        id="doc-box"
      ></div>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="showIframeDialog = false"
          >关闭</el-button
        >
      </span>
    </el-dialog>

    <!-- 上传答案文件 -->
    <import-file-dialog
      ref="ImportAnswerDialog"
      dialog-title="导入答案"
      :template-download-handle="answerTemplateDownload"
      :upload-url="uploadAnswerUrl"
      :upload-data="uploadAnswerData"
      add-file-param="dataFile"
      @uploaded="answerUploaded"
    ></import-file-dialog>
  </div>
</template>

<script>
// import paperRichTextJson from "../datas/paperRichText.json";
// import paperParseData from "../datas/paperParseData.json";

import { calcSum, deepCopy, objTypeOf, randomCode } from "@/plugins/utils";
import QuestionImportPaperEdit from "./QuestionImportPaperEdit.vue";
import UploadButton from "@/components/UploadButton.vue";
import { getRichTextAnswerPointCount, isAnEmptyRichText } from "@/utils/utils";
import {
  questionImportPaperSave,
  questionImportParseRichText,
  questionImportDownloadTemplate,
  propertyNameQueryApi,
  questionWordImportTemplate,
} from "../api";
import ImportFileDialog from "@/components/ImportFileDialog.vue";
import { QUESTION_API, QUESTION_TYPES } from "@/constants/constants";
import { downloadByApi } from "@/plugins/download";
import { richTextToJSON, renderRichText } from "./import-edit/richText";
import scrollMixins from "./import-edit/scrollMixins";
import timeMixin from "@/mixins/timeMixin";
import { renderAsync } from "docx-preview";

const questionInfoField = [
  "courseId",
  "difficulty",
  "quesProperties",
  "score",
  "publicity",
  "control",
  "answerAnalysis",
  "quesAnswer",
];

export default {
  name: "QuestionImportEdit",
  components: { QuestionImportPaperEdit, ImportFileDialog, UploadButton },
  mixins: [scrollMixins, timeMixin],
  props: {
    data: {
      type: Object,
      default() {
        return {
          richText: { sections: [] },
          detailInfo: [],
          importData: {
            courseId: "",
            courseName: "",
            name: "",
            checkTotalScore: false,
            useOriginalPaper: false,
            totalScore: 0,
          },
        };
      },
    },
  },
  computed: {
    hasErrorTips() {
      // return (this.paperRichJsonGroup || []).some((item) => {
      //   return item?.exceptions?.length;
      // });
      let detailInfo = this.paperData;
      if (!Array.isArray(detailInfo)) {
        return false;
      }
      return detailInfo.some((detail) => {
        return detail?.questions?.some((item) => {
          let questionExceptions = item.questionExceptions;
          let arr = item.ignoreOptionRepeat
            ? questionExceptions.filter(
                (v) => !v.cause.includes("选项内容相同")
              )
            : questionExceptions;
          if (!item.subQuestions?.length) {
            return !!arr.length;
          } else {
            return item.subQuestions.some((sub) => {
              let { questionExceptions = [] } = sub;
              let ar = sub.ignoreOptionRepeat
                ? questionExceptions.filter(
                    (v) => !v.cause.includes("选项内容相同")
                  )
                : questionExceptions;
              return !!ar.length;
            });
          }
        });
      });
    },
  },
  data() {
    return {
      ignoreRepeatExceptionIndexArr: [],
      modalIsShow: false,
      loading: false,
      questionKey: "",
      filterPaperData: [],
      paperData: [],
      paperRichJson: { sections: [] },
      paperRichJsonGroup: [],
      richTextToJSON,
      renderRichText,
      lastPaperScrollTop: 0,
      lastRichTextScrollTop: 0,
      richTextIndexList: [],
      scrollType: "",
      curException: null,
      // upload answer
      uploadAnswerUrl: `${QUESTION_API}/word/parse/import`,
      uploadAnswerData: {},
      // word upload
      importFileTypes: ["docx", "doc"],
      uploadData: {},
      uploadUrl: `${QUESTION_API}/word/parse/struct`,
      showIframeDialog: false,
      // question types
      onlyErrorQuestion: false,
      questionStatData: {
        total: 0,
        successCount: 0,
        errorCount: 0,
        qtypes: [],
      },
      filterQuestionType: "all",
      modalForm: this.getInitForm(),
      rules: {
        courseId: [
          {
            required: true,
            message: "请选择课程",
            trigger: "change",
          },
        ],
        name: [
          {
            required: true,
            message: "请输入试卷名称",
            trigger: "change",
          },
        ],
        totalScore: [
          {
            required: true,
            message: "请输入试卷总分",
            trigger: "change",
          },
        ],
      },
    };
  },
  created() {
    this.$bus.on("markIgnoreRepeatQuestion", this.markIgnoreRepeat);
  },
  watch: {
    paperData: {
      handler() {
        this.parseQuestionStatData();
        this.filterQuestionTypeChange({ name: this.filterQuestionType });
        this.questionKey = randomCode();
      },
    },
  },
  methods: {
    getInitForm() {
      return {
        courseId: null,
        courseName: null,
        name: "",
        checkTotalScore: false,
        useOriginalPaper: false,
        totalScore: 0,
        toOtherCourse: false,
      };
    },
    courseChange(val) {
      this.modalForm.courseName = val ? val.name : "";
      this.getCourseProperty();
      this.uploadData = { courseId: this.modalForm.courseId };
    },
    parseQuestionStatData() {
      const total = calcSum(
        this.paperData.map((item) => item.questions.length)
      );
      const successCount = calcSum(
        this.paperData.map(
          (item) =>
            item.questions.filter((v) => !v.questionExceptions.length).length
        )
      );
      const errorCount = calcSum(
        this.paperData.map(
          (item) =>
            item.questions.filter((v) => v.questionExceptions.length).length
        )
      );
      const questionTypeStat = {};
      this.paperData.forEach((detail) => {
        let questions = detail.questions;
        if (this.onlyErrorQuestion) {
          questions = questions.filter((v) => v.questionExceptions.length);
        }
        questions.forEach((question) => {
          const { questionType } = question;
          if (questionTypeStat[questionType]) {
            questionTypeStat[questionType]++;
          } else {
            questionTypeStat[questionType] = 1;
          }
        });
      });
      const qtMap = {};
      QUESTION_TYPES.forEach((item) => {
        qtMap[item.code] = item.name;
      });
      const qtypes = Object.keys(questionTypeStat).map((key) => ({
        questionType: key,
        questionTypeName: qtMap[key],
        questionCount: questionTypeStat[key],
      }));

      this.questionStatData = {
        total,
        successCount,
        errorCount,
        qtypes,
      };
    },
    onlyErrorQuestionChange() {
      this.parseQuestionStatData();
      this.filterQuestionTypeChange({ name: this.filterQuestionType });
      this.questionKey = randomCode();
    },
    inHasIgnore(indexes) {
      return this.ignoreRepeatExceptionIndexArr.includes(indexes.toString());
    },
    markIgnoreRepeat(exceptionIndex, bool) {
      this.paperData.forEach((detail) => {
        detail.questions.forEach((question) => {
          if (
            question.questionExceptions?.length &&
            question.questionExceptions.find(
              (v) => v.exceptionIndex.toString() == exceptionIndex
            )
          ) {
            question.ignoreOptionRepeat = bool;
          }
          if (question.subQuestions?.length) {
            question.subQuestions.forEach((sub) => {
              if (
                sub.questionExceptions?.length &&
                sub.questionExceptions.find(
                  (v) => v.exceptionIndex.toString() == exceptionIndex
                )
              ) {
                sub.ignoreOptionRepeat = bool;
              }
            });
          }
        });
      });
      this.paperData = JSON.parse(JSON.stringify(this.paperData));
      this.paperRichJsonGroup = this.getRichTextGroup();
      this.ignoreRepeatExceptionIndexArr.push(exceptionIndex);
    },
    urlToBlob(url, callback) {
      let xhr = new XMLHttpRequest();
      xhr.open("GET", url, true);
      xhr.responseType = "blob";
      xhr.onload = function () {
        if (xhr.status == 200) {
          callback(xhr.response);
        }
      };
      xhr.send();
    },
    showDocx() {
      this.showIframeDialog = true;
      this.$nextTick(() => {
        this.urlToBlob("/admin/inputDesc.docx", (data) => {
          let box = document.getElementById("doc-box");
          renderAsync(data, box);
        });
      });
    },
    async getWordTemplate() {
      const res = await downloadByApi(() => {
        return questionWordImportTemplate();
      }).catch((e) => {
        this.$message.error(e || "下载失败，请重新尝试！");
      });

      if (!res) return;
      this.$message.success("下载成功！");
    },
    async visibleChange() {
      this.ignoreRepeatExceptionIndexArr = [];
      this.getCourseProperty();

      if (this.data) this.resetData(this.data);
      this.$nextTick(() => {
        this.registScrollEvent();
      });
    },
    resetData({ richText, detailInfo }) {
      this.paperData = deepCopy(detailInfo);
      this.paperRichJson = this.buildRichText(deepCopy(richText));
      this.transformDataInfo();
      this.paperRichJsonGroup = this.getRichTextGroup();

      this.uploadData = { courseId: this.modalForm.courseId };
      this.questionKey = randomCode();

      this.$nextTick(() => {
        this.getRichTextIndexList();
      });
    },
    filterQuestionTypeChange(val) {
      this.filterQuestionType = val.name;

      const onlyErrorValidater = (question) => {
        if (this.onlyErrorQuestion) {
          return Boolean(question.questionExceptions.length);
        }
        return true;
      };

      if (this.filterQuestionType === "all") {
        this.filterPaperData = !this.onlyErrorQuestion
          ? this.paperData
          : this.paperData
              .map((detail) => {
                return {
                  ...detail,
                  questions: detail.questions.filter((question) =>
                    onlyErrorValidater(question)
                  ),
                };
              })
              .filter((detail) => detail.questions.length);
        return;
      }

      this.filterPaperData = this.paperData
        .map((detail) => {
          return {
            ...detail,
            questions: detail.questions.filter(
              (question) =>
                question.questionType === this.filterQuestionType &&
                onlyErrorValidater(question)
            ),
          };
        })
        .filter((detail) => detail.questions.length);
    },
    getRichTextIndexList() {
      const richTextListDom = document.getElementById("qe-part-richtext-list");
      const elPos = richTextListDom.getBoundingClientRect();
      let richTextIndexList = [];
      const richTextBodyDoms =
        richTextListDom.querySelectorAll(".v-editor-body");
      richTextBodyDoms.forEach((richTextBodyDom) => {
        richTextBodyDom.childNodes.forEach((sectionNode) => {
          const id = sectionNode.getAttribute("id");
          if (!id) return;
          if (
            sectionNode.className &&
            sectionNode.className.includes("section-error")
          )
            return;

          const index = id.replace("section-", "") * 1;
          const sectionPos = sectionNode.getBoundingClientRect();

          richTextIndexList.push([index, sectionPos.y - elPos.y]);
        });
      });
      this.richTextIndexList = richTextIndexList;
    },
    async getCourseProperty() {
      if (!this.modalForm.courseId) return;
      const res = await propertyNameQueryApi(this.modalForm.courseId, "");
      const optionList = res.data || [];
      window.sessionStorage.setItem(
        "coursePropertys",
        JSON.stringify({ optionList, courseId: this.modalForm.courseId })
      );
    },
    buildRichText(richText) {
      let nsections = [];
      richText.sections.forEach((section) => {
        nsections.push({
          ...section,
          attributes: { id: `section-${section.remark.index}` },
        });
      });
      return { sections: nsections };
    },
    transformDataInfo() {
      this.transformRichImg(this.paperRichJson);
      this.paperData.forEach((detail) => {
        detail.questions.forEach((question) => {
          this.transformQuestion(question);
          if (question.subQuestions && question.subQuestions.length) {
            question.subQuestions.forEach((subq) => {
              this.transformQuestion(subq);
            });
          }
        });
      });
    },
    transformQuestion(question) {
      this.transformRichImg(question.body);
      this.transformRichImg(question.answerRichTexts);
      if (question.options && question.options.length) {
        question.options.forEach((item) => {
          this.transformRichImg(item.body);
        });
      }
      question.quesAnswer = this.transformQuestionAnser(question.quesAnswer);
    },
    transformRichImg(richText) {
      if (isAnEmptyRichText(richText)) return;

      const rate = 96 / 600;
      richText.sections.forEach((section) => {
        section.blocks.forEach((block) => {
          if (block.type !== "image" || !block.param) return;
          block.param.width = block.param.width * rate;
          block.param.height = block.param.height * rate;
        });
      });
    },
    transformQuestionAnser(quesAnswer) {
      let qAnswer = null;
      try {
        qAnswer = quesAnswer ? JSON.parse(quesAnswer) : null;
      } catch (error) {
        console.log(error);
      }
      if (!qAnswer || objTypeOf(qAnswer) !== "array") return quesAnswer;

      qAnswer.forEach((item) => {
        this.transformRichImg(item);
      });
      return JSON.stringify(qAnswer);
    },
    getRichTextGroup() {
      let groupSetList = [];
      this.paperData.forEach((detail) => {
        groupSetList.push({
          id: randomCode(),
          indexs: detail.detailIndex,
        });
        detail.questions.forEach((question) => {
          groupSetList.push({
            id: randomCode(),
            indexs: question.integralIndex,
          });
          if (question.subQuestions && question.subQuestions.length) {
            question.subQuestions.forEach((subq) => {
              groupSetList.push({
                id: randomCode(),
                indexs: subq.integralIndex,
              });
            });
          }
        });
      });

      let groups = [];
      let curGroupId = 0;
      let curGroup = [];
      const findGroupId = (ind) => {
        let data = groupSetList.find((item) => item.indexs.includes(ind));
        return data ? data.id : null;
      };
      this.paperRichJson.sections.forEach((section) => {
        const sectionGroupId = findGroupId(section.remark.index);
        if (sectionGroupId !== curGroupId) {
          if (curGroup.length) {
            groups.push({ sections: curGroup, exceptions: [] });
            curGroup = [];
          }
        }
        curGroupId = sectionGroupId;
        curGroup.push(section);
      });
      if (curGroup.length) {
        groups.push({ sections: curGroup, exceptions: [] });
        curGroup = [];
      }

      const getExceptions = (sections) => {
        let cause = {};
        sections.forEach((section) => {
          if (section.remark.status) return;
          if (!cause[section.remark.cause]) {
            cause[section.remark.cause] = [];
          }
          cause[section.remark.cause].push(section.remark.index);
        });
        const causeList = Object.keys(cause).map((key) => {
          return {
            message: key,
            indexs: cause[key],
          };
        });
        causeList.sort((a, b) => a.indexs[0] - b.indexs[0]);
        return causeList;
      };

      groups.forEach((group) => {
        group.indexs = group.sections.map((item) => item.remark.index);
        group.exceptions = getExceptions(group.sections);
      });
      return groups;
    },
    highLightErrorText(exception) {
      if (this.curException) {
        this.curException.indexs.forEach((ind) => {
          const sectionDoms = document.querySelectorAll(`#section-${ind}`);
          if (!sectionDoms.length) return;
          sectionDoms.forEach((sectionDom) => {
            sectionDom.style = null;
          });
        });
      }
      this.clearSetTs();

      this.curException = exception;
      let firstSectionDom = null;
      exception.indexs.forEach((ind) => {
        const sectionDom = document.getElementById(`section-${ind}`);
        if (!sectionDom) return;
        if (!firstSectionDom) firstSectionDom = sectionDom;
        sectionDom.style.background = "#fef0f0";
      });

      if (!firstSectionDom) return;

      const richTextListDom = document.getElementById("qe-part-richtext-list");
      const elPos = richTextListDom.getBoundingClientRect();
      const sectionOffsetTop =
        firstSectionDom.getBoundingClientRect().y - elPos.y - 100;
      if (sectionOffsetTop < richTextListDom.parentNode.scrollTop) {
        richTextListDom.parentNode.scrollTop = sectionOffsetTop;
        this.scrollType = "rich-text";
        setTimeout(() => {
          this.scrollType = "";
        }, 100);
      }

      this.addSetTime(() => {
        this.curException.indexs.forEach((ind) => {
          const sectionDoms = document.querySelectorAll(`#section-${ind}`);
          if (!sectionDoms.length) return;
          sectionDoms.forEach((sectionDom) => {
            sectionDom.style = null;
          });
        });
        this.curException = null;
      }, 5000);
    },
    initData() {
      this.filterPaperData = [];
      this.filterQuestionType = "all";
      this.paperData = [];
      this.paperRichJson = { sections: [] };
      window.sessionStorage.removeItem("coursePropertys");
      this.$message.closeAll();
      this.removeScrollEvent();
    },
    cancel() {
      this.modalIsShow = false;
    },
    open() {
      this.modalIsShow = true;
    },
    getRichTextJsons() {
      let sections = [];
      this.$refs.RichTextEditor.forEach((item) => {
        const itemRichJson = item.emitJsonAction();
        sections.push(...itemRichJson.sections);
      });
      return { sections };
    },
    async toParse() {
      if (isAnEmptyRichText(this.paperRichJson)) {
        this.$message.error("请输入试卷内容！");
        return;
      }

      if (this.loading) return;
      this.loading = true;

      let richText = this.getRichTextJsons();
      const res = await questionImportParseRichText({
        richText,
        courseId: this.modalForm.courseId,
      }).catch(() => {});
      this.loading = false;
      if (!res) return;

      const cacheData = this.getCachePaperInfo(
        this.getImportPaperData(),
        questionInfoField
      );
      // console.log(cacheData);
      this.paperData = this.assignCachePaperData(
        res.data.detailInfo,
        cacheData
      );
      this.paperRichJson = this.buildRichText(deepCopy(res.data.richText));
      this.paperRichJsonGroup = this.getRichTextGroup();
      this.questionKey = randomCode();

      this.$nextTick(() => {
        this.getRichTextIndexList();
      });
    },
    getCachePaperInfo(paperData, cacheFields = []) {
      let cachePaperInfo = {};
      paperData.forEach((detail, dIndex) => {
        detail.questionInfo.forEach((question, qIndex) => {
          let info = {};
          let k = `${dIndex + 1}_${qIndex + 1}`;
          if (cacheFields.length) {
            cacheFields.forEach((field) => {
              info[field] = question[field];
            });
          } else {
            info = { ...question };
          }

          cachePaperInfo[k] = info;

          if (question.subQuestions && question.subQuestions.length) {
            question.subQuestions.forEach((subq, subqIndex) => {
              let info = {};
              let k = `${dIndex + 1}_${qIndex + 1}_${subqIndex + 1}`;
              if (cacheFields.length) {
                cacheFields.forEach((field) => {
                  info[field] = subq[field];
                });
              } else {
                info = { ...subq };
              }

              cachePaperInfo[k] = info;
            });
          }
        });
      });
      // console.log(cachePaperInfo);
      return cachePaperInfo;
    },
    assignCachePaperData(paperData, cacheData, mergeReverse = false) {
      return paperData.map((detail, dIndex) => {
        detail.questions = detail.questions.map((question, qIndex) => {
          let k = `${dIndex + 1}_${qIndex + 1}`;
          let nq = this.mergeObjData(
            question,
            cacheData[k] || {},
            mergeReverse
          );
          if (question.subQuestions && question.subQuestions.length) {
            nq.subQuestions = question.subQuestions.map((subq, subqIndex) => {
              let k = `${dIndex + 1}_${qIndex + 1}_${subqIndex + 1}`;
              return this.mergeObjData(subq, cacheData[k] || {}, mergeReverse);
            });
          }
          return nq;
        });
        return detail;
      });
    },
    isNull(val) {
      if (val) {
        if (val === "[]") return true;
        if (objTypeOf(val) === "array" && !val.length) return true;
      }
      return val === null || val === "" || val === undefined;
    },
    mergeObjData(targetObj, cacheObj, mergeReverse) {
      let data = { ...targetObj };
      Object.keys(cacheObj).forEach((k) => {
        if (mergeReverse) {
          data[k] = this.isNull(cacheObj[k]) ? targetObj[k] : cacheObj[k];
        } else {
          data[k] = this.isNull(targetObj[k]) ? cacheObj[k] : targetObj[k];
        }
      });
      return data;
    },
    getImportPaperData() {
      if (!this.$refs.QuestionImportPaperEdit) return [];
      let paperData = deepCopy(this.$refs.QuestionImportPaperEdit.getData());
      const transformFieldMap = { body: "quesBody", options: "quesOptions" };
      const fields = Object.keys(transformFieldMap);
      const course = {
        id: this.modalForm.courseId,
        name: this.modalForm.courseName,
      };

      const transformQuestion = (question) => {
        question.id = null;
        question.course = course;
        fields.forEach((field) => {
          question[transformFieldMap[field]] = question[field];
          delete question[field];
        });
        if (question.quesOptions && question.quesOptions.length) {
          question.quesOptions = question.quesOptions.map((option) => {
            option.optionBody = option.body;
            delete option.body;
            return option;
          });
        }
        return question;
      };

      const detailInfo = paperData.map((detail) => {
        const questionInfo = detail.questions.map((question) => {
          transformQuestion(question);

          if (question.subQuestions && question.subQuestions.length) {
            question.subQuestions = question.subQuestions.map((subq) =>
              transformQuestion(subq)
            );
            question.score = calcSum(
              question.subQuestions.map((q) => q.score || 0)
            );
          }
          return question;
        });

        return {
          name: detail.name,
          number: detail.number,
          questionCount: questionInfo.length,
          questionInfo,
          questionScore: detail.questionScore,
          totalScore: calcSum(questionInfo.map((q) => q.score || 0)),
        };
      });
      // console.log(detailInfo);
      return detailInfo;
    },
    checkImportPaperData(paperData) {
      this.$message.closeAll();

      // 题目内容校验
      const MATCHING_QUESTION = ["PARAGRAPH_MATCHING", "BANKED_CLOZE"];
      const SELECT_QUESTION = [
        "SINGLE_ANSWER_QUESTION",
        "MULTIPLE_ANSWER_QUESTION",
        ...MATCHING_QUESTION,
      ];
      const NESTED_QUESTION = [
        ...MATCHING_QUESTION,
        "READING_COMPREHENSION",
        "CLOZE",
        "LISTENING_QUESTION",
      ];
      const ALLOW_EMPTY_BODY_QUESTION = [
        "LISTENING_QUESTION",
        ...MATCHING_QUESTION,
      ];
      let errInfos = [];
      paperData.forEach((detail) => {
        detail.questionInfo.forEach((question) => {
          const { questionType, quesBody } = question;
          const questionTitle = `第${detail.number}大题第${question.number}小题`;
          let qErrInfo = [];
          // 题干
          if (
            !ALLOW_EMPTY_BODY_QUESTION.includes(questionType) &&
            (!quesBody || isAnEmptyRichText(quesBody))
          ) {
            qErrInfo.push(`没有题干`);
          }

          // 选项
          if (SELECT_QUESTION.includes(questionType)) {
            if (question.quesOptions.length < 2) {
              qErrInfo.push(`选项少于2个`);
            }
            if (
              question.quesOptions.some((option) =>
                isAnEmptyRichText(option.optionBody)
              )
            ) {
              qErrInfo.push(`有选择内容为空`);
            }
          }

          // 小题数
          if (
            NESTED_QUESTION.includes(questionType) &&
            !question.subQuestions.length
          ) {
            qErrInfo.push(`没有小题`);
          }

          if (qErrInfo.length) {
            errInfos.push(`${questionTitle}${qErrInfo.join("、")}`);
            qErrInfo = [];
          }

          // 完形填空
          if (questionType === "CLOZE") {
            const answerPointCount = getRichTextAnswerPointCount(quesBody);
            if (answerPointCount !== question.subQuestions.length) {
              errInfos.push(
                `第${detail.number}大题题干答题点数量与选项数不匹配`
              );
            }
            if (
              question.subQuestions.some(
                (q) => q.questionType !== "SINGLE_ANSWER_QUESTION"
              )
            ) {
              errInfos.push(`第${detail.number}大题存在不是单选题的子题`);
            }
          }

          // 听力题
          if (questionType === "LISTENING_QUESTION") {
            if (
              question.subQuestions.some(
                (q) => q.questionType !== "SINGLE_ANSWER_QUESTION"
              )
            ) {
              errInfos.push(`第${detail.number}大题存在不是单选题的子题`);
            }
          }

          // 选词填空、段落匹配，单用模式时校验输入答案是否重复
          if (
            MATCHING_QUESTION.includes(questionType) &&
            question.quesParam.matchingMode === 1
          ) {
            // 选词填空
            if (questionType === "BANKED_CLOZE") {
              const answerPointCount = getRichTextAnswerPointCount(quesBody);
              if (answerPointCount > question.quesOptions.length) {
                errInfos.push(`第${detail.number}大题题干答题点数量超过选项数`);
              }
            } else {
              if (question.subQuestions.length > question.quesOptions.length) {
                errInfos.push(`第${detail.number}大题小题数量超过选项数`);
              }
            }

            let selectedAnswer = [],
              errorQuestionIndexs = [];
            question.subQuestions.forEach((subq, sindex) => {
              if (selectedAnswer.includes(subq.quesAnswer)) {
                errorQuestionIndexs.push(`${question.number}-${sindex + 1}`);
              } else {
                if (subq.quesAnswer !== "[]")
                  selectedAnswer.push(subq.quesAnswer);
              }
            });
            if (errorQuestionIndexs.length) {
              errInfos.push(
                `第${
                  detail.number
                }大题${errorQuestionIndexs.join()}小题答案重复`
              );
            }
          }

          if (!NESTED_QUESTION.includes(questionType)) return;

          // 套题小题校验
          question.subQuestions.forEach((subq, sindex) => {
            const subqTitle = `第${detail.number}大题第${question.number}-${
              sindex + 1
            }小题`;
            if (
              questionType === "READING_COMPREHENSION" &&
              (!subq.quesBody || isAnEmptyRichText(subq.quesBody))
            ) {
              qErrInfo.push(`没有题干`);
            }
            if (
              SELECT_QUESTION.includes(subq.questionType) &&
              !MATCHING_QUESTION.includes(questionType)
            ) {
              if (subq.quesOptions.length < 2) {
                qErrInfo.push(`选项少于2个`);
              }
              if (
                subq.quesOptions.some((option) =>
                  isAnEmptyRichText(option.optionBody)
                )
              ) {
                qErrInfo.push(`有选择内容为空`);
              }
            }

            if (qErrInfo.length) {
              errInfos.push(`${subqTitle}${qErrInfo.join("、")}`);
              qErrInfo = [];
            }
          });
        });
      });
      if (errInfos.length) {
        this.$message({
          showClose: true,
          message: errInfos.join("。"),
          type: "error",
          duration: 0,
        });
        return;
      }

      if (!this.modalForm.useOriginalPaper) return true;

      let detailNumbers = paperData.map((detail) => detail.number);
      // 大题号重复性校验
      let repeatDetaiNumbers = [];
      let detailNums = [];
      for (let i = 0; i < detailNumbers.length; i++) {
        const num = detailNumbers[i];
        if (detailNums.includes(num)) {
          if (!repeatDetaiNumbers.includes(num)) repeatDetaiNumbers.push(num);
        } else {
          detailNums.push(num);
        }
      }
      if (repeatDetaiNumbers.length) {
        this.$message({
          showClose: true,
          message: `大题号${repeatDetaiNumbers.join("、")}重复`,
          type: "error",
          duration: 0,
        });
        return;
      }
      // 大题号连续性校验
      for (let i = 0; i < detailNumbers.length; i++) {
        if (detailNumbers[i] - 1 !== i) {
          this.$message({
            showClose: true,
            message: "大题号不连续",
            type: "error",
            duration: 0,
          });
          return;
        }
      }

      // 答案、分数校验
      let totalScore = calcSum(paperData.map((d) => d.totalScore));
      let errQuestions = [];
      paperData.forEach((detail) => {
        detail.questionInfo.forEach((question) => {
          if (question.subQuestions && question.subQuestions.length) {
            let subIndexs = [];
            question.subQuestions.forEach((subq, sind) => {
              if (!subq.score)
                subIndexs.push(question.number + "-" + (sind + 1));
            });
            if (subIndexs.length)
              errQuestions.push(
                `第${detail.number}大题第${subIndexs.join()}小题`
              );
          } else {
            if (!question.score) {
              errQuestions.push(
                `第${detail.number}大题第${question.number}小题`
              );
            }
          }
        });
      });
      if (errQuestions.length) {
        this.$message({
          showClose: true,
          message: `请设置如下试题的分值：${errQuestions.join("、")}。`,
          type: "error",
          duration: 0,
        });
        return;
      }

      if (
        this.modalForm.checkTotalScore &&
        totalScore !== this.modalForm.totalScore
      ) {
        this.$message({
          showClose: true,
          message: `试卷总分与导入设置的总分不一致！`,
          type: "error",
          duration: 0,
        });
        return;
      }

      return true;
    },
    async confirm() {
      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
      if (!valid) return;

      const confirm = await this.$confirm("确认加入题库吗?", "提示", {
        type: "warning",
      }).catch(() => {});
      if (confirm !== "confirm") return;

      const detailInfo = this.getImportPaperData();
      if (!this.checkImportPaperData(detailInfo)) return;

      if (this.loading) return;
      this.loading = true;
      console.log("detailInfo", detailInfo);
      const res = await questionImportPaperSave({
        ...this.modalForm,
        detailInfo,
      }).catch(() => {});

      this.loading = false;
      if (!res) return;
      if (res.data) {
        this.$confirm(
          "系统正在计算试题情况，请在后续检查试题查重与试题审核数据。",
          "系统通知",
          {
            type: "warning",
          }
        );
      }
      this.$message.success("提交成功！");
      this.$emit("modified");
      this.cancel();
    },
    // 导入答案属性
    toImportAnswer() {
      const detailInfo = this.getImportPaperData();
      this.uploadAnswerData = {
        detailInfo: JSON.stringify(detailInfo),
        ...this.modalForm,
      };
      this.$refs.ImportAnswerDialog.open();
    },
    async answerTemplateDownload() {
      const detailInfo = this.getImportPaperData();

      const res = await downloadByApi(() => {
        return questionImportDownloadTemplate({
          detailInfo,
          ...this.modalForm,
        });
      }).catch((e) => {
        this.$message.error(e || "下载失败，请重新尝试！");
      });

      if (!res) return;
      this.$message.success("下载成功！");
    },
    answerUploaded(res) {
      const cacheData = this.getCachePaperInfo(
        res.data.detailInfo,
        questionInfoField
      );
      this.paperData = this.assignCachePaperData(
        this.paperData,
        cacheData,
        true
      );
      this.questionKey = randomCode();
    },
    // word upload
    uploaded(res) {
      this.$message.success("上传成功！");
      this.resetData({
        richText: res.data.richText,
        detailInfo: res.data.detailInfo,
      });
    },
    validError(error) {
      console.log("err", error);
      this.$message.error(error.message);
    },
    // rich test editor
    richTextFocus(richTextGroup) {
      this.$refs.QuestionImportPaperEdit.scrollToContentByIndex(
        richTextGroup.indexs
      );
      this.scrollType = "rich-text";
      setTimeout(() => {
        this.scrollType = "";
      }, 100);
    },
  },
};
</script>
