<template>
  <div class="paper-template-build">
    <div class="paper-template-build-body">
      <div class="margin_top_10">
        <el-select
          v-model="seqMode"
          class="margin-right-10"
          size="small"
          @change="seqModeChange"
        >
          <!-- <el-option value="MODE1" label="单题型连续"></el-option>
            <el-option value="MODE2" label="客观题整体连续"></el-option> -->
          <el-option value="MODE3" label="按大题独立"></el-option>
          <el-option value="MODE5" label="整卷连续"></el-option>
        </el-select>
        <el-select
          v-model="curPaperTemp"
          class="margin-right-10"
          placeholder="请选择"
          value-key="id"
          size="small"
          @change="paperTempChange"
        >
          <el-option
            v-for="item in paperTempList"
            :key="item.id"
            :label="item.name"
            :value="item"
          >
          </el-option>
        </el-select>
        <el-button
          type="primary"
          size="small"
          :disabled="downloading"
          @click="toAction('downloadPdf')"
          >下载试卷</el-button
        >
      </div>
      <paper-build-config
        ref="PaperBuildConfig"
        :config-sources="configSources"
        :confirm-disabled="downloading"
        @confirm="toAction('buildPackage')"
      ></paper-build-config>
      <paper-template-view
        ref="PaperTemplateView"
        id="paper-template-view"
        class="preview-body"
        :pages="pages"
        :page-config="paperTempJson.pageConfig"
      >
        <template #texts="{ texts }">
          <div
            v-for="groupItem in texts"
            :key="groupItem.id"
            :id="groupItem.id"
            :class="[
              'group-item',
              { 'is-detail-title': groupItem.type === 'detail-title' },
              {
                'is-detail-description':
                  groupItem.type === 'detail-description',
              },
            ]"
            :style="groupItem.styles"
          >
            <table
              v-if="
                configModalForm.showDetailScoreTable &&
                groupItem.type === 'detail-title'
              "
              class="detail-score-table"
            >
              <tr>
                <th>得分</th>
                <th>评分人</th>
              </tr>
              <tr>
                <td></td>
                <td></td>
              </tr>
            </table>
            <!-- 内容 -->
            <template v-if="groupItem.elements && groupItem.elements.length">
              <elem-rich-text
                v-for="elem in groupItem.elements"
                :id="`rich-text-${elem.id}`"
                :key="elem.id"
                :data="elem"
              ></elem-rich-text>
            </template>
          </div>
        </template>
      </paper-template-view>
      <!-- process dom -->
      <div v-if="elementList.length" class="element-list">
        <elem-rich-text
          v-for="elem in elementList"
          :id="elem.id"
          :key="elem.id"
          :data="elem"
        ></elem-rich-text>
      </div>

      <!-- answer dom -->
      <answer-template-view
        ref="AnswerTemplateView"
        id="answer-template-view"
        class="preview-body"
        :answerData="paperJson"
        :pageCountMode="configModalForm.pageCountMode"
      ></answer-template-view>
    </div>
  </div>
</template>

<script>
import { mapState } from "vuex";
import ElemRichText from "../elements/rich-text/ElemRichText.vue";
import PaperTemplateView from "../components/PaperTemplateView.vue";
import PaperBuildConfig from "../components/PaperBuildConfig.vue";
import AnswerTemplateView from "../components/AnswerTemplateView.vue";

import { deepCopy } from "../../card/plugins/utils";
import { paperDetailInfoApi } from "../../paper/api";
import { paperTemplateListApi, paperAndAnswerPdfDownloadApi } from "../api";
import paperTemplateBuildMixins from "./paperTemplateBuildMixins";
import { buildPdf } from "@/plugins/htmlToPdf";

export default {
  name: "PaperTemplateBuild",
  components: {
    PaperTemplateView,
    PaperBuildConfig,
    ElemRichText,
    AnswerTemplateView,
  },
  mixins: [paperTemplateBuildMixins],
  data() {
    return {
      paperId: this.$route.params.paperId,
      viewType: this.$route.params.viewType,
      seqMode: "MODE3",
      paperJson: {},
      paperTempJson: {
        pages: [],
        pageConfig: {},
      },
      maxColumnWidth: 200,
      maxColumnHeight: 200,
      paperTempList: [],
      curPaperTemp: {},
      downloading: false,
      fieldData: {},
      paperStructs: [],
      configModalForm: {
        showDetailNo: true,
        showDetailScoreInfo: true,
        showDetailScoreTable: false,
        pageCountMode: "SIMPLE",
      },
      configSources: [],
      prepareDownloadPdf: false,
      actionType: "",
      watermarkBg: "",
    };
  },
  computed: {
    ...mapState({ user: (state) => state.user }),
  },
  mounted() {
    if (this.viewType === "frame") {
      this.initFrame();
      return;
    }

    this.initData();
  },
  methods: {
    async initFrame() {
      try {
        const paperSet = window.parent.paperSet;
        if (!paperSet) {
          this.emitFrameResult(false, "数据缺失");
          return;
        }

        this.seqMode = paperSet.seqMode;
        this.curPaperTemp = paperSet.paperTemp;
        this.configModalForm = paperSet.configModalForm;

        await this.getPaperJson();

        let paperTempJson = this.curPaperTemp.content
          ? JSON.parse(this.curPaperTemp.content)
          : { pages: [], pageConfig: {} };
        this.paperTempJson = paperTempJson;
        console.log("paperTempJson", paperTempJson);
        this.pages = paperTempJson.pages;
        this.updaterFieldInfo();
      } catch (error) {
        this.emitFrameResult(false, "数据错误");
      }

      this.$nextTick(async () => {
        try {
          this.maxColumnWidth =
            document.getElementById("column-0-0").offsetWidth;
          this.maxColumnHeight =
            document.getElementById("column-0-0").offsetHeight - 10;
          this.buildElementsFromStruct();
        } catch (error) {
          this.emitFrameResult(false, "构建元素错误");
        }

        const loadRes = await this.waitAllImgLoaded().catch(() => {});
        if (!loadRes) {
          this.emitFrameResult(false, "数据缓存错误");
          return;
        }
        this.$nextTick(() => {
          try {
            this.updateElementWidthInfo();
            this.buildGroupsFromStruct();
            this.buildPrePages();
          } catch (error) {
            this.emitFrameResult(false, "预构建页面错误");
          }

          this.$nextTick(() => {
            try {
              this.updateGroupHeightInfo();
              this.buildPagesByAutoPage();
            } catch (error) {
              this.emitFrameResult(false, "构建pdf错误");
            }

            this.$nextTick(async () => {
              const paperBlob = await buildPdf(
                {
                  element: document.getElementById("paper-template-view"),
                  pageSize: this.paperTempJson.pageConfig.pageSize,
                },
                true
              ).catch((error) => {
                console.error(error);
              });
              if (!paperBlob) {
                this.emitFrameResult(false, "生成试卷pdf错误");
                return;
              }

              this.emitFrameResult(true, "", paperBlob);
            });
          });
        });
      });
    },
    emitFrameResult(success = true, errorMsg = "", blobCont = null) {
      window.parent &&
        window.parent.submitPaperTemp &&
        window.parent.submitPaperTemp({
          success,
          errorMsg,
          blobCont,
          contType: "paper",
        });
    },
    async initData() {
      this.watermarkBg = await this.initWatermark();
      await this.getPaperJson();
      await this.getPaperTempList();

      if (!this.paperTempList.length) {
        this.$message.error("导出模板缺失！");
        return;
      }
      this.paperTempChange(this.paperTempList[0]);
    },
    async getPaperJson() {
      const res = await paperDetailInfoApi({
        paperId: this.paperId,
        seqMode: this.seqMode,
      });
      this.paperJson = res.data;
      this.resetClozeSerialNo(this.paperJson);
      this.fieldData = {
        paperName: res.data.name,
        courseName: res.data.course.name,
        courseCode: res.data.course.code,
        totalScore: res.data.totalScore,
        rootOrgName: res.data.rootOrgName,
      };
      this.paperStructs = this.paperJson.paperDetails.map((detail) => {
        return {
          detailName: detail.name,
          questionCount: detail.unitCount,
          totalScore: detail.score,
        };
      });
    },
    resetClozeSerialNo(paperData) {
      const clozeQuestionTypes = ["CLOZE", "BANKED_CLOZE"];
      paperData.paperDetails.forEach((detail) => {
        detail.paperDetailUnits.forEach((question) => {
          if (!clozeQuestionTypes.includes(question.questionType)) return;
          question.question.quesBody.sections.forEach((section) => {
            section.blocks.forEach((block) => {
              if (block.type !== "cloze") return;
              block.value =
                question.question.subQuestions[block.value - 1].questionSeq;
            });
          });
        });
      });
    },
    async getPaperTempList() {
      const res = await paperTemplateListApi("PAPER_EXPORT");
      this.paperTempList = res.data;
    },
    getConfigSources() {
      const { pages } = this.paperTempJson;
      let sources = [],
        fieldAble = {};
      pages.forEach((page) => {
        page.columns.forEach((column) => {
          column.elements.forEach((element) => {
            if (element.type !== "PAPER_PROPS") return;
            if (!sources.length) {
              sources = deepCopy(element.props);
            }
            element.props.forEach((prop) => {
              fieldAble[prop.field] = fieldAble[prop.field] || prop.enable;
            });
          });
        });
      });

      sources.forEach((item) => {
        item.enable = fieldAble[item.field];
      });
      this.configSources = sources;
    },
    updaterFieldInfo() {
      const VALID_ELEMENTS_FOR_EXTERNAL = ["FIELD_TEXT"];
      this.paperTempJson.pages.forEach((page) => {
        if (page.pageNumberRule) {
          Object.keys(this.fieldData).forEach((field) => {
            page.pageNumberRule = page.pageNumberRule.replace(
              "${" + field + "}",
              this.fieldData[field]
            );
          });
        }
        page.columns.forEach((column) => {
          column.elements.forEach((elem) => {
            if (elem.type === "PAPER_STRUCT") {
              elem.structs = this.paperStructs;
            } else if (elem.type === "SCORE_TABLE") {
              elem.detailCount = this.paperStructs.length;
            } else if (elem.type === "PAPER_PROPS") {
              elem.props.forEach((prop) => {
                prop.value = this.configModalForm[prop.field];
              });
            }

            if (!elem.elements || !elem.elements.length) return;

            elem.elements.forEach((element) => {
              if (!VALID_ELEMENTS_FOR_EXTERNAL.includes(element.type)) return;

              if (element.type === "FIELD_TEXT" && element.field) {
                element.content = this.fieldData[element.field];
              }
            });
          });
        });
      });
    },
    async seqModeChange() {
      await this.getPaperJson();
      this.$nextTick(() => {
        this.buildData();
      });
    },
    buildConfigChange(val) {
      this.configModalForm = val;
      this.updaterFieldInfo();

      this.$nextTick(() => {
        this.buildData();
      });
    },
    paperTempChange(paperTemp) {
      // console.log(paperTemp);
      this.curPaperTemp = paperTemp;
      let paperTempJson = paperTemp.content
        ? JSON.parse(paperTemp.content)
        : { pages: [], pageConfig: {} };
      this.paperTempJson = paperTempJson;
      this.pages = paperTempJson.pages;
      this.getConfigSources();
      this.updaterFieldInfo();

      this.$nextTick(() => {
        this.buildData();
      });
    },
    async buildData() {
      this.maxColumnWidth = document.getElementById("column-0-0").offsetWidth;
      this.maxColumnHeight =
        document.getElementById("column-0-0").offsetHeight - 10;

      this.buildElementsFromStruct();
      const loadRes = await this.waitAllImgLoaded().catch(() => {});
      if (!loadRes) {
        this.$message.error("图片加载有误！");
        return;
      }
      this.$nextTick(() => {
        this.updateElementWidthInfo();
        this.buildGroupsFromStruct();
        this.buildPrePages();

        this.$nextTick(() => {
          this.updateGroupHeightInfo();
          this.buildPagesByAutoPage();
          if (this.prepareDownloadPdf) {
            this.$nextTick(async () => {
              await this.runAction().catch(() => {});
              this.prepareDownloadPdf = false;
            });
          } else {
            this.$nextTick(() => {
              this.setWatermark();
            });
          }
        });
      });
    },
    // img ------ start >
    loadImg(url) {
      return new Promise((resolve, reject) => {
        const img = new Image();
        img.onload = function () {
          resolve(true);
        };
        img.onerror = function () {
          reject();
        };
        img.src = url;
      });
    },
    getRichJsonImgUrls(richJson) {
      let urls = [];
      if (!richJson) return urls;
      richJson.sections.forEach((section) => {
        section.blocks.forEach((elem) => {
          if (elem.type === "image" && elem.value.startsWith("http")) {
            urls.push(elem.value);
          }
        });
      });
      return urls;
    },
    async waitAllImgLoaded() {
      let imgUrls = [];
      this.elementList.forEach((item) => {
        imgUrls.push(...this.getRichJsonImgUrls(item.content));
      });

      // console.log(imgUrls);

      if (!imgUrls.length) return Promise.resolve(true);
      const imgLoads = imgUrls.map((item) => this.loadImg(item));
      const imgLoadResult = await Promise.all(imgLoads).catch(() => {});
      if (imgLoadResult && imgLoadResult.length) {
        return Promise.resolve(true);
      } else {
        return Promise.reject();
      }
    },
    // img ------ end >
    // download ------ start >
    async toAction(actionType) {
      const valid = await this.$refs.PaperBuildConfig.checkData().catch(
        () => {}
      );
      if (!valid) return;

      this.actionType = actionType;
      const configData = this.$refs.PaperBuildConfig.getData();
      if (JSON.stringify(configData) === JSON.stringify(this.configModalForm)) {
        this.runAction();
      } else {
        this.prepareDownloadPdf = true;
        this.buildConfigChange(configData);
      }
    },
    async runAction() {
      this.clearWatermark();
      if (this.actionType === "downloadPdf") {
        await this.downloadPaperPdf();
      } else {
        await this.buildPackage();
      }
      this.setWatermark();
    },
    async downloadPaperPdf() {
      if (this.downloading) return;
      this.downloading = true;

      let result = true;
      await buildPdf({
        element: document.getElementById("paper-template-view"),
        filename: `${this.fieldData.courseName}(${this.fieldData.courseCode})_${this.fieldData.paperName}.pdf`,
        pageSize: this.paperTempJson.pageConfig.pageSize,
      }).catch((error) => {
        result = false;
        console.error(error);
        this.$message.error(error.message || "下载失败，请重新尝试！");
      });

      this.downloading = false;
      if (!result) return;
      this.$message.success("下载成功！");
    },
    async buildPackage() {
      if (this.downloading) return;
      this.downloading = true;

      // 试卷PDF
      const paperPdfName = `${this.fieldData.courseName}(${this.fieldData.courseCode})_${this.fieldData.paperName}.pdf`;
      const paperBlob = await buildPdf(
        {
          element: document.getElementById("paper-template-view"),
          pageSize: this.paperTempJson.pageConfig.pageSize,
        },
        true
      ).catch((error) => {
        this.downloading = false;
        console.error(error);
        this.$message.error("生成试卷pdf失败，请重新尝试！");
      });
      if (!paperBlob) return;

      // 答案pdf
      const answerPdfName = `${this.fieldData.courseName}(${this.fieldData.courseCode})_${this.fieldData.paperName}_答案.pdf`;
      const answerBlob = await buildPdf(
        {
          element: document.getElementById("answer-template-view"),
          pageSize: "A4",
        },
        true
      ).catch((error) => {
        this.downloading = false;
        console.error(error);
        this.$message.error("生成答案pdf失败，请重新尝试！");
      });
      if (!answerBlob) return;

      const data = new FormData();
      data.append(
        "paperPdf",
        new File([paperBlob], paperPdfName, { type: "application/pdf" })
      );
      data.append(
        "answerPdf",
        new File([answerBlob], answerPdfName, { type: "application/pdf" })
      );
      data.append("paperId", this.paperId);

      let result = true;
      await paperAndAnswerPdfDownloadApi(data).catch((error) => {
        result = false;
        console.error(error);
      });
      this.downloading = false;

      if (!result) return;
      this.$message.success("生成数据包成功！");
    },
    initWatermark() {
      const content = this.user.displayName;

      const canvas = document.createElement("canvas");
      const ctx = canvas.getContext("2d");

      const fontSize = 40;
      ctx.font = `${fontSize}px serif`;
      const cInfo = ctx.measureText(content);
      const cwidth = Math.max(360, cInfo.width) * 1.2;
      canvas.width = cwidth;
      canvas.height = cwidth;

      ctx.font = `${fontSize}px serif`;
      ctx.fillStyle = "rgba(212,212,212,0.5)";
      ctx.textAlign = "center";
      ctx.textBaseline = "middle";
      const angle = (315 * Math.PI) / 180;
      const x = canvas.width / 2;
      const y = canvas.height / 2;

      ctx.translate(x, y);
      ctx.rotate(angle);
      ctx.fillText(content, 0, 0);

      return new Promise((resolve, reject) => {
        canvas.toBlob((val) => {
          if (!val) return reject("获取水印blob错误");

          resolve(window.URL.createObjectURL(val));
        });
      });
    },
    setWatermark() {
      const bgSize = 240;
      document
        .getElementById("paper-template-view")
        .querySelectorAll(".page-box")
        .forEach((dom) => {
          dom.setAttribute(
            "style",
            `background-image: url(${this.watermarkBg});background-repeat: repeat;background-size: ${bgSize}px ${bgSize}px;`
          );
        });
    },
    clearWatermark() {
      document
        .getElementById("paper-template-view")
        .querySelectorAll(".page-box")
        .forEach((dom) => {
          dom.setAttribute("style", undefined);
        });
    },
  },
};
</script>

<style>
.paper-template-build {
  text-align: center;
}
.paper-template-build-body {
  display: inline-block;
  text-align: initial;
}

.paper-template-build .page-box {
  margin-top: 10px;
  margin-bottom: 10px;
}
.paper-template-build .paper-build-config {
  padding: 10px 15px 2px;
  margin-top: 5px;
  background: #fff;
  border-radius: 10px;
}
.paper-build-config .el-form-item {
  margin-bottom: 16px;
  margin-right: 30px;
}
.paper-template-build .element-list {
  visibility: hidden;
  position: absolute;
  width: 1200px;
  height: 600px;
  overflow: hidden;
  left: -9999px;
  top: 0;
  z-index: 1;
}

.paper-template-build .answer-template-view {
  position: absolute;
  left: -9999px;
  z-index: 999;
  visibility: hidden;
}
.paper-template-build .page-column-element .element-item {
  background-color: inherit;
}
</style>
