<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"
          @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"
          @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" @click="toDownload">下载试卷</el-button>
      </div>
      <paper-template-view
        ref="PaperTemplateView"
        class="preview-body"
        :pages="pages"
        :page-config="paperTempJson.pageConfig"
      ></paper-template-view>
    </div>
  </div>
</template>

<script>
import PaperTemplateView from "../components/PaperTemplateView.vue";
import { getModel as getRichTextModel } from "../elements/rich-text/model";
import { getModel as getPageModel } from "../elements/page/model";
import { getElementId, randomCode, deepCopy } from "../../card/plugins/utils";
import { calcSum, maxNum } from "@/plugins/utils";
import previewTemp from "../previewTemp";
import { paperDetailInfoApi } from "../../paper/api";
import { paperTemplateListApi, paperPdfDownloadApi } from "../api";
import { downloadByApi } from "@/plugins/download";
// import paperJson from "./data/paper.json";
// import paperTempJson from "./data/paper-temp.json";

const numberToUpperCase = function (val) {
  if (val < 1 || val > 26) return;

  return String.fromCharCode(64 + val);
};

const checkRichTextHasCont = function (data) {
  if (!data) return false;
  if (!data.sections || !data.sections.length) return false;

  if (!data.sections[0].blocks || !data.sections[0].blocks.length) return false;

  return true;
};

export default {
  name: "PaperTemplateBuild",
  components: { PaperTemplateView },
  data() {
    return {
      paperId: this.$route.params.paperId,
      viewType: this.$route.params.viewType,
      seqMode: "MODE1",
      renderStructList: [],
      pages: [],
      paperJson: {},
      paperTempJson: {
        pages: [],
        pageConfig: {},
      },
      maxColumnWidth: 200,
      maxColumnHeight: 200,
      paperTempList: [],
      curPaperTemp: {},
      downloading: false,
      fieldData: {},
      paperStructs: [],
      TEXT_INDENT_SIZE: 28,
      textIndent: 28,
    };
  },
  mounted() {
    if (this.viewType === "frame") {
      this.initFrame();
      return;
    }
    this.initData();
  },
  methods: {
    getTextIndexStyle() {
      return {
        textIndent: `-${this.textIndent}px`,
        paddingLeft: `${this.textIndent}px`,
      };
    },
    async initFrame() {
      try {
        const paperSet = window.parent.paperSet;
        if (!paperSet) {
          this.emitFrameResult(false, "数据缺失");
          return;
        }

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

        await this.getPaperJson();

        let paperTempJson = this.curPaperTemp.content
          ? JSON.parse(this.curPaperTemp.content)
          : { pages: [], pageConfig: {} };
        this.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.parseRenderStructList();
          this.buildPrePages();
        } catch (error) {
          this.emitFrameResult(false, "构建错误");
        }

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

          this.$nextTick(() => {
            this.emitFrameResult(true, "", this.getPreviewTemp());
          });
        });
      });
    },
    emitFrameResult(success = true, errorMsg = "", htmlCont = "") {
      window.parent &&
        window.parent.submitPaperTemp &&
        window.parent.submitPaperTemp({
          success,
          errorMsg,
          htmlCont,
          templateId: this.curPaperTemp.id,
        });
    },
    async initData() {
      await this.getPaperJson();
      await this.getPaperTempList();

      if (!this.paperTempList.length) {
        this.$message.error("导出模板缺失！");
        return;
      }
      this.paperTempChange(this.paperTempList[0]);

      // test--->
      // this.paperJson = paperJson;
      // this.paperTempJson = paperTempJson;
      // this.pages = paperTempJson.pages;
      // this.$nextTick(() => {
      //   this.buildData();
      // });
    },
    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}（${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 seqModeChange() {
      await this.getPaperJson();
      this.$nextTick(() => {
        this.buildData();
      });
    },
    async getPaperTempList() {
      const res = await paperTemplateListApi("PAPER_EXPORT");
      this.paperTempList = res.data;
    },
    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.updaterFieldInfo();

      this.$nextTick(() => {
        this.buildData();
      });
    },
    updaterFieldInfo() {
      const VALID_ELEMENTS_FOR_EXTERNAL = ["FIELD_TEXT"];
      this.paperTempJson.pages.forEach((page) => {
        page.columns.forEach((column) => {
          column.elements.forEach((elem) => {
            if (elem.type === "PAPER_STRUCT") {
              elem.structs = this.paperStructs;
            }

            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 buildData() {
      this.maxColumnWidth = document.getElementById("column-0-0").offsetWidth;
      this.maxColumnHeight =
        document.getElementById("column-0-0").offsetHeight - 10;
      this.parseRenderStructList();
      this.buildPrePages();

      const loadRes = await this.waitAllImgLoaded().catch(() => {});
      if (!loadRes) {
        this.$message.error("图片加载有误！");
        return;
      }
      this.$nextTick(() => {
        this.buildReleasePages();
      });
    },
    parseRenderStructList() {
      let renderStructList = [];

      this.paperJson.paperDetails.forEach((detail) => {
        renderStructList.push(this.parseDetailTitle(detail));
        if (checkRichTextHasCont(detail.description)) {
          const descData = this.parseTitleOption(detail.description, "");
          renderStructList.push(...descData);
        }
        detail.paperDetailUnits.forEach((question) => {
          let questionInfo = question.question;
          if (questionInfo.subQuestions && questionInfo.subQuestions.length) {
            const bodys = this.parseTitleOption(questionInfo.quesBody, "");
            renderStructList.push(...bodys);

            const isMatches = this.checkIsMatches(questionInfo.questionType);
            if (
              isMatches &&
              questionInfo.quesOptions &&
              questionInfo.quesOptions.length
            ) {
              questionInfo.quesOptions.forEach((op) => {
                const obodys = this.parseTitleOption(
                  op.optionBody,
                  `${numberToUpperCase(op.number)}、`,
                  true,
                  {
                    contType: "option",
                    textStyles: { paddingLeft: `${this.textIndent}px` },
                  }
                );
                renderStructList.push(...obodys);
              });
            }

            // 选词填空不展示小题
            if (questionInfo.questionType === "BANKED_CLOZE") {
              renderStructList.push(this.parseLineGap());
              return;
            }

            questionInfo.subQuestions.forEach((sq, sqindex) => {
              sq.subNumber = sqindex + 1;
              if (isMatches) sq.quesOptions = []; // 选词填空、段落匹配小题中不展示选项
              const contents = this.parseSimpleQuestion(sq, false);
              renderStructList.push(...contents);
              renderStructList.push(this.parseLineGap());
            });
          } else {
            questionInfo.number = question.number;
            const datas = this.parseSimpleQuestion(questionInfo, true);
            renderStructList.push(...datas);
            renderStructList.push(this.parseLineGap());
          }
        });
      });

      // 去掉最后一题的间隔行
      // console.log(renderStructList);
      this.renderStructList = renderStructList.slice(0, -1);
    },
    getRichStruct(blocks) {
      return {
        sections: [
          {
            blocks: [...blocks],
          },
        ],
      };
    },
    transformRichJson(richJson) {
      if (!richJson || !richJson.sections) return [];
      let contents = [];
      let curBlock = [];
      const checkNeedSplitSection = (block) => {
        if (block.type !== "image") return false;

        if (block.param) {
          if (block.param.width)
            return block.param.width > this.maxColumnWidth / 2;
          if (block.param.height) return block.param.height > 150;
        }
        return true;
      };

      richJson.sections.forEach((section) => {
        section.blocks.forEach((block) => {
          if (checkNeedSplitSection(block) && curBlock.length) {
            contents.push(this.getRichStruct(curBlock));
            curBlock = [];
          }
          curBlock.push(block);
        });

        if (curBlock.length) {
          contents.push(this.getRichStruct(curBlock));
          curBlock = [];
        }
      });
      return contents;
    },
    changeRichTextCloze(richText) {
      return {
        sections: richText.sections.map((section) => {
          return {
            blocks: section.blocks.map((item) => {
              if (item.type === "cloze") {
                return {
                  type: "text",
                  value: "_____",
                };
              } else {
                return { ...item };
              }
            }),
          };
        }),
      };
    },
    parseSimpleQuestion(question) {
      let contents = [];
      let quesBody = question.quesBody;
      if (question.questionType === "FILL_BLANK_QUESTION") {
        quesBody = this.changeRichTextCloze(quesBody);
      }

      const tbodys = this.parseTitleOption(
        quesBody,
        `${question.questionSeq}、`,
        true,
        {
          textStyles: { paddingLeft: `${this.textIndent}px` },
        }
      );
      contents.push(...tbodys);
      const hasNobody = !tbodys.length;

      if (question.quesOptions && question.quesOptions.length) {
        question.quesOptions.forEach((op, oIndex) => {
          let noVal = `${numberToUpperCase(op.number)}、`;
          if (!hasNobody) {
            const obodys = this.parseTitleOption(op.optionBody, noVal, false, {
              contType: "option",
              textStyles: { paddingLeft: `${this.textIndent}px` },
            });
            contents.push(...obodys);
            return;
          }

          if (!oIndex) {
            // 针对如完形填空的小题做的特殊处理
            noVal = `${question.questionSeq}、${noVal}`;
          }
          this.textIndent = 2 * this.TEXT_INDENT_SIZE;
          const obodys = this.parseTitleOption(op.optionBody, noVal, true, {
            contType: "option",
            textStyles: { paddingLeft: `${this.textIndent}px` },
          });
          contents.push(...obodys);
          this.textIndent = this.TEXT_INDENT_SIZE;
        });
      }
      return contents;
    },
    parseDetailTitle(data) {
      let content = this.getRichStruct([
        {
          type: "text",
          value: `${data.cnNum}、`,
        },
        {
          type: "text",
          value: `${data.name}（共${data.unitCount}小题，满分${data.score}分）`,
        },
      ]);
      return getRichTextModel({
        styles: { width: "100%", fontWeight: 600 },
        content,
      });
    },
    parseTitleOption(
      richJson,
      noVal,
      needIndent = false,
      modelData = { textStyles: null, styles: null, contType: "" }
    ) {
      if (!richJson) return [];
      const { textStyles, styles, contType } = modelData;
      const bodys = this.transformRichJson(richJson);

      return bodys.map((body, index) => {
        let presetData = {
          content: body,
        };
        if (contType) presetData.contType = contType;
        if (textStyles) presetData.textStyles = textStyles;
        if (styles) {
          presetData.styles = styles;
        } else {
          presetData.styles = {
            width: contType === "option" ? "auto" : "100%",
          };
        }

        if (index === 0 && noVal) {
          let cont = {
            type: "text",
            value: noVal,
          };
          if (needIndent) {
            cont.param = {
              width: this.textIndent,
            };
            presetData.textStyles = {
              ...(presetData.textStyles || {}),
              ...this.getTextIndexStyle(),
            };
          }
          body.sections[0].blocks.unshift(cont);
        }

        return getRichTextModel(presetData);
      });
    },
    parseLineGap() {
      return getRichTextModel({
        contType: "gap",
        styles: { width: "100%", height: "10px" },
        content: this.getRichStruct([{ type: "text", value: "" }]),
      });
    },
    checkIsMatches(structType) {
      const matchesTypes = ["BANKED_CLOZE", "PARAGRAPH_MATCHING"];
      return matchesTypes.includes(structType);
    },
    buildPrePages() {
      let pages = deepCopy(this.paperTempJson.pages);
      const firstPageNo = pages.findIndex((p) => p.pageType !== "cover");
      pages[firstPageNo].columns[0].texts = [];
      pages[firstPageNo].columns[0].texts.push(...this.renderStructList);
      this.pages = pages;
    },
    buildReleasePages() {
      this.resetRenderStructSize();
      // console.log(this.renderStructList);
      this.buildPageAutoPage();
    },
    resetRenderStructSize() {
      let curOptions = [];
      this.renderStructList.forEach((elem, eindex) => {
        const elemDom = document.getElementById(`rich-text-${elem.id}`);
        elem.w = elemDom.offsetWidth;
        elem.h = elemDom.offsetHeight;

        if (elem.contType !== "option") return;

        curOptions.push(elem);

        // 全选选项逻辑
        const nextElem = this.renderStructList[eindex + 1];
        if (nextElem && nextElem.contType === "option") return;

        curOptions.forEach((optionElem) => {
          optionElem._percent = this.getSizePercent(
            optionElem.w,
            this.maxColumnWidth
          );
        });

        const optionCount = curOptions.length;
        // 奇数选项，全部一行
        if (optionCount % 2 > 0) {
          curOptions.forEach((optionElem) => {
            optionElem._percent = 1;
            optionElem.styles.width = "100%";
          });
          curOptions = [];
          return;
        }

        const percents = curOptions.map((item) => item._percent);
        const maxPercent = maxNum(percents);
        let aveOptionPercent = 1;
        if (optionCount % 4 === 0) {
          aveOptionPercent = this.calcAveOptionPercent(maxPercent);
        } else {
          aveOptionPercent = maxPercent > 0.5 ? 1 : 0.5;
        }
        curOptions.forEach((optionElem) => {
          optionElem._percent = aveOptionPercent;
          optionElem.styles.width = aveOptionPercent * 100 + "%";
        });

        curOptions = [];
      });
      this.renderStructList.forEach((elem) => {
        if (elem.styles.width === "100%") {
          this.$set(elem.styles, "display", "block");
        }
      });
    },
    buildPageAutoPage() {
      let pages = [];
      let curPage = null,
        curElem = null;
      let curColumn = null,
        curColumnNo = 0,
        curColumnHeight = 0;
      let curLinePercent = 0;
      let groups = [],
        curGroup = [];

      // 分组自动分页 选项分组
      const getNextElem = () => {
        return this.renderStructList.shift();
      };

      curElem = getNextElem();
      while (curElem) {
        if (
          curElem.contType !== "option" ||
          (curElem.contType === "option" && curElem._percent === 1)
        ) {
          if (curGroup.length) {
            groups.push(curGroup);
            curGroup = [];
            curLinePercent = 0;
          }

          groups.push([curElem]);
          curElem = getNextElem();
        } else {
          if (curLinePercent + curElem._percent > 1) {
            groups.push(curGroup);
            curGroup = [];
            curLinePercent = 0;
          } else {
            curGroup.push(curElem);
            curLinePercent += curElem._percent;
            curElem = getNextElem();
          }
        }
      }
      if (curGroup.length) {
        groups.push(curGroup);
        curGroup = [];
      }

      const getNextGroup = () => {
        return groups.shift();
      };
      curGroup = getNextGroup();
      while (curGroup) {
        if (!curPage) {
          curPage = this.getNewPageModel(pages.length);
        }

        if (!curColumn) {
          curColumn = curPage.columns[curColumnNo++];
          curColumnHeight = this.calcInitColumnHeight(curColumn);
        }

        let curGroupHeigth =
          groups.length === 1
            ? curGroup[0].h
            : Math.max.apply(
                null,
                curGroup.map((item) => item.h)
              );

        if (curGroupHeigth + curColumnHeight > this.maxColumnHeight) {
          // 当前栏满了
          if (curColumnNo >= curPage.columnNumber) {
            // 当前页满了
            pages.push(curPage);
            curPage = null;
            curColumnNo = null;
          }
          curColumn = null;
          curColumnHeight = 0;
        } else {
          // 当前栏未满
          curColumnHeight += curGroupHeigth;
          curColumn.texts.push(...curGroup);
          curGroup = getNextGroup();
        }
      }

      if (curPage) {
        pages.push(curPage);
        curPage = null;
      }
      // 正文部分保证偶数页
      if (pages.length % 2) {
        pages.push(this.getNewPageModel(pages.length));
      }

      if (this.paperTempJson.pageConfig.showCover) {
        // 封面自动插入反面空白页
        let coverPages = deepCopy(
          this.paperTempJson.pages.filter((p) => p.pageType === "cover")
        );
        let coverBackPage = deepCopy(coverPages[0]);
        coverBackPage.columns.forEach((column) => {
          column.elements = [];
        });
        let nCoverPages = [];
        coverPages.forEach((cpage) => {
          nCoverPages.push(cpage);
          nCoverPages.push(coverBackPage);
        });
        pages = [...nCoverPages, ...pages];
      }

      this.pages = pages;
    },
    getNewPageModel(pageNo) {
      let contentPages = this.paperTempJson.pages.slice(-2);
      let pNo = pageNo % 2;
      const pageTemp = contentPages[pNo];
      let newPage = getPageModel({
        ...this.paperTempJson.pageConfig,
        pageType: pageTemp.pageType,
      });
      newPage.sides = pageTemp.sides.map((elem) => {
        let nelem = deepCopy(elem);
        nelem.id = getElementId();
        nelem.key = randomCode();

        // if (pNo === 1 && nelem.type === "GUTTER") {
        //   nelem.direction = "right";
        // }
        return nelem;
      });
      newPage.columns.forEach((column) => {
        column.texts = [];
      });

      if (pageNo > 1) return newPage;

      newPage.columns.forEach((column, cindex) => {
        column.elements = pageTemp.columns[cindex].elements.map((elem) => {
          let nelem = deepCopy(elem);
          nelem.id = getElementId();
          nelem.key = randomCode();
          nelem.h = this.getElementHeight(`preview-${elem.id}`);
          if (nelem.elements && nelem.elements.length) {
            nelem.elements.forEach((celem) => {
              celem.id = getElementId();
              celem.key = randomCode();
            });
          }
          return nelem;
        });
        column.texts = [];
      });
      return newPage;
    },
    getElementHeight(elementId) {
      const dom = document.getElementById(elementId);
      return dom ? dom.offsetHeight : 0;
    },
    calcAveOptionPercent(maxPercent) {
      if (maxPercent > 0.5) return 1;
      if (maxPercent > 0.25) return 0.5;
      return 0.25;
    },
    calcInitColumnHeight(column) {
      return calcSum(column.elements.map((item) => item.h));
    },
    getSizePercent(size, fullSize) {
      const rate = size / fullSize;
      if (rate <= 0.25) return 0.25;
      if (rate <= 0.5) return 0.5;
      return 1;
    },
    // img
    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.renderStructList.forEach((item) => {
        if (item.contType === "gap") return;
        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();
      }
    },
    getPreviewTemp() {
      const elementDoms =
        this.$refs.PaperTemplateView.$el.querySelectorAll(".elem-rich-text");
      elementDoms.forEach((eDom) => {
        const width = eDom.offsetWidth;
        if (eDom.firstChild && eDom.firstChild.nodeName === "DIV") {
          eDom.firstChild.style.width = width + "px";
          if (
            eDom.firstChild.firstChild &&
            eDom.firstChild.firstChild.nodeName === "DIV"
          )
            eDom.firstChild.firstChild.style.width = width + "px";
        }
      });
      return previewTemp(this.$refs.PaperTemplateView.$el.outerHTML);
    },
    async toDownload() {
      const htmlCont = this.getPreviewTemp();

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

      const res = await downloadByApi(() => {
        return paperPdfDownloadApi({
          content: htmlCont,
          templateId: this.curPaperTemp.id,
          paperId: this.paperId,
        });
      }).catch((e) => {
        this.$message.error(e || "下载失败，请重新尝试！");
      });
      this.downloading = false;

      if (!res) return;
      this.$message.success("下载成功！");
    },
  },
};
</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;
}
</style>
