import { isAnEmptyRichText, numberToUpperCase } from "@/utils/utils";
import { getModel as getRichTextModel } from "../elements/rich-text/model";
import { maxNum, randomCode, deepCopy, calcSum } from "@/plugins/utils";
import { getModel as getPageModel } from "../elements/page/model";
import { getElementId } from "../../card/plugins/utils";
import { SELECTIVE_RULE_TYPE } from "@/constants/constants";

/**
- 根据试卷构建文本元素，序号和内容分开。同时确定分组信息。
- 第一次渲染元素，确定宽度信息。
- 根据分组信息，细化分组段落信息。
- 第二次渲染段落，确定各段落高度信息。
- 自动分页。
- 第三次渲染。
 */
export default {
  data() {
    return {
      elementList: [],
      groups: [],
      sections: [],
      structRelateElement: [],
      TEXT_INDENT_SIZE: 28,
      pages: [],
      SELECTIVE_RULE_TYPE,
    };
  },
  methods: {
    // buildData() {
    //   this.maxColumnWidth = document.getElementById("column-0-0").offsetWidth;
    //   this.maxColumnHeight =
    //     document.getElementById("column-0-0").offsetHeight - 10;
    // },
    checkIsNouns(detail) {
      return (
        detail.name.includes("名词解释") &&
        !detail.paperDetailUnits.some(
          (q) => q.question.questionType !== "TEXT_ANSWER_QUESTION"
        )
      );
    },
    buildElementsFromStruct() {
      let elementList = [];
      let structRelateElement = [];
      // 考试说明
      const { elements: descElements, elementIds: descElementIds } =
        this.parseTitleOption(this.paperJson.examRemark, "");
      elementList.push(...descElements);
      structRelateElement.push({
        title: descElementIds,
        description: [],
        questions: [],
        options: [],
      });

      this.paperJson.paperDetails.forEach((detail) => {
        let detailRelateElement = {
          title: [],
          description: [],
          questions: [],
          options: [],
        };
        // 大题名称
        const detailTitleElement = this.parseDetailTitle(detail);
        elementList.push(detailTitleElement);
        detailRelateElement.title = [detailTitleElement.id];
        // 大题描述
        if (!isAnEmptyRichText(detail.description)) {
          const { elements, elementIds } = this.parseTitleOption(
            detail.description,
            ""
          );
          elementList.push(...elements);
          detailRelateElement.description = elementIds;
        }
        if (this.checkIsNouns(detail)) {
          // 名词解释，单独处理
          const { contents, options } = this.parseDetailNouns(detail);
          elementList.push(...contents);
          detailRelateElement.options = options;
        } else {
          // 小题
          detail.paperDetailUnits.forEach((question) => {
            let questionInfo = question.question;

            questionInfo.number = question.number;
            const { contents, questionRelateElement } =
              this.parseSimpleQuestion(questionInfo);
            elementList.push(...contents);
            detailRelateElement.questions.push(questionRelateElement);
          });
        }

        structRelateElement.push(detailRelateElement);
      });
      // console.log(elements);
      this.structRelateElement = structRelateElement;
      this.elementList = elementList;
    },
    updateElementWidthInfo() {
      this.elementList.forEach((element) => {
        element.w = document.getElementById(element.id).offsetWidth;
      });
    },
    buildGroupsFromStruct() {
      let groups = [];
      let elementMap = {};
      this.elementList.forEach((item) => {
        elementMap[item.id] = item;
      });
      // utils
      const getElementsByIds = (ids) => {
        return ids.map((id) => elementMap[id]);
      };
      const getGroupData = ({
        type = "content",
        sno = "",
        elements = [],
        styles = {},
      }) => {
        return {
          id: `group-${randomCode()}`,
          type,
          sno,
          elements,
          styles,
          h: null,
        };
      };
      const getLineGap = () => {
        return getGroupData({
          type: "gap",
          styles: { height: "10px" },
        });
      };
      // 选项
      const parseOptions = (options, questionType) => {
        const optionCount = options.length;
        const IS_PARAGRAPH_MATCHING = questionType === "PARAGRAPH_MATCHING";
        const IS_BANKED_CLOZE = questionType === "BANKED_CLOZE";
        const IS_NOUNS = questionType === "NOUNS";

        // 构建选项元素信息
        // console.log("options.length", options.length);
        const opitonList = options.map((optionIds) => {
          const elements = getElementsByIds(optionIds);
          const width = maxNum(elements.map((elem) => elem.w));
          // console.log(width, this.maxColumnWidth, this.TEXT_INDENT_SIZE);
          const percent = this.getSizePercent(
            width,
            this.maxColumnWidth - this.TEXT_INDENT_SIZE,
            options.length
          );
          // console.log("percent", percent);
          return {
            percent,
            resetPercent: null,
            elements,
          };
        });

        // 确定选项宽度比例
        let resetPercent = 1;
        // 奇数选项，段落匹配，全部一行
        if (
          (optionCount % 2 > 0 &&
            !IS_BANKED_CLOZE &&
            !IS_NOUNS &&
            optionCount !== 5) ||
          IS_PARAGRAPH_MATCHING
        ) {
          resetPercent = 1;
        } else {
          const maxPercent = maxNum(opitonList.map((item) => item.percent));
          resetPercent = this.getResetPercent(maxPercent, optionCount);
        }
        opitonList.forEach((item) => {
          item.resetPercent = resetPercent;
          // 不占一行的选项合并结构
          if (resetPercent < 1 && item.elements.length > 1) {
            let element = getRichTextModel({
              contType: "option",
              content: this.mergeRichStruct(
                item.elements.map((el) => el.content)
              ),
            });
            item.elements = [element];
          }
          // 更新选项元素宽度信息
          item.elements.forEach((elem) => {
            elem.textStyles.width = resetPercent * 100 + "%";
          });
        });

        // 选项分组
        let curGroupElements = [],
          optionGroups = [],
          curGroupPercent = 0;
        opitonList.forEach((option) => {
          // 占一行的选项可能会有多个分组。
          if (resetPercent === 1) {
            const optionItemGroups = option.elements.map((item, ind) => {
              // 第一个分组首行缩进，之后的首行不缩进
              const textStyles = IS_PARAGRAPH_MATCHING
                ? ind === 0
                  ? this.getTextIndentStyle()
                  : {}
                : ind === 0
                ? this.getFullTextIndentStyle()
                : this.getIndentStyle();
              item.textStyles = { ...item.textStyles, ...textStyles };
              return getGroupData({
                type: "option",
                elements: [item],
                styles: this.getIndentStyle(),
              });
            });
            optionGroups.push(...optionItemGroups);
            return;
          }

          // 不占一行的选项只创建一个分组
          if (curGroupPercent + option.resetPercent > 1) {
            if (curGroupElements.length) {
              optionGroups.push(
                getGroupData({
                  type: "option",
                  elements: curGroupElements,
                  styles: this.getIndentStyle(),
                })
              );
              curGroupElements = [];
              curGroupPercent = 0;
            }
          }

          curGroupElements.push(...option.elements);
          curGroupPercent += option.resetPercent;
        });

        if (curGroupElements.length) {
          optionGroups.push(
            getGroupData({
              type: "option",
              elements: curGroupElements,
              styles: this.getIndentStyle(),
            })
          );
        }
        return optionGroups;
      };
      // 试题
      const parseQuestion = (question) => {
        // 题干
        // 没有题目序号时，不缩进
        const hasQuestionSeq = !!question.questionSeq;
        const bodyGroups = getElementsByIds(question.body).map(
          (item, index) => {
            if (!hasQuestionSeq) {
              return getGroupData({
                elements: [item],
              });
            }

            if (!index) item.textStyles = this.getTextIndentStyle();
            return getGroupData({
              elements: [item],
              styles: this.getIndentStyle(),
            });
          }
        );
        groups.push(...bodyGroups);
        // 选项
        if (question.options.length) {
          let optionsGroups = parseOptions(
            question.options,
            question.questionType
          );
          // 无题干有选项时，题号放选项第一分组第一行
          // 主要是针对完形填空的特殊处理
          if (!bodyGroups.length && question.questionSeq) {
            optionsGroups[0].elements[0].content.sections[0].blocks.unshift({
              type: "text",
              value: `${question.questionSeq}.`,
              param: {
                width: this.TEXT_INDENT_SIZE,
              },
            });
            optionsGroups[0].elements[0].textStyles = {
              ...optionsGroups[0].elements[0].textStyles,
              textIndent: `-${this.TEXT_INDENT_SIZE * 2}px`,
              paddingLeft: `${this.TEXT_INDENT_SIZE}px`,
            };
          }
          groups.push(...optionsGroups);
        }
        // 小题
        if (question.subQuestions && question.subQuestions.length) {
          question.subQuestions.forEach((subQuestion) => {
            parseQuestion(subQuestion);
          });
        } else {
          groups.push(getLineGap());
        }
      };

      // body
      groups = [getLineGap(), getLineGap()];
      this.structRelateElement.forEach((detail) => {
        // 大题名称
        const detailTitleGroups = getElementsByIds(detail.title).map((item) =>
          getGroupData({
            elements: [item],
            type: "detail-title",
            styles: { fontWeight: 600 },
          })
        );
        groups.push(...detailTitleGroups);
        // 大题描述
        const detailDescriptionGroups = getElementsByIds(
          detail.description
        ).map((item) =>
          getGroupData({ elements: [item], type: "detail-description" })
        );
        groups.push(...detailDescriptionGroups);
        // 名词解释相关
        if (detail.options && detail.options.length) {
          let optionsGroups = parseOptions(detail.options, "NOUNS");
          optionsGroups.forEach((optionsGroup) => {
            optionsGroup.styles.paddingLeft = undefined;
          });
          groups.push(...optionsGroups);
          groups.push(getLineGap());
          return;
        }
        // 小题
        detail.questions.forEach((question) => {
          parseQuestion(question);
        });
      });

      // 去掉最后一题的间隔行
      this.groups = groups.slice(0, -1);
    },
    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.groups);
      this.pages = pages;
    },
    updateGroupHeightInfo() {
      this.groups.forEach((group) => {
        group.h = document.getElementById(group.id).offsetHeight;
      });
    },
    buildPagesByAutoPage() {
      let pages = [];
      let curPage = null;
      let curColumn = null;
      let curColumnNo = 0;
      let curColumnHeight = 0;
      let curGroup = [];

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

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

        if (curGroup.h + curColumnHeight > this.maxColumnHeight) {
          // 当前栏第一个元素就超过最大高度时，直接放当前栏
          if (!curColumn.texts.length) {
            curColumn.texts.push(curGroup);
            curGroup = getNextGroup();
          }
          // 当前栏满了
          if (curColumnNo >= curPage.columnNumber) {
            // 当前页满了
            pages.push(curPage);
            curPage = null;
            curColumnNo = 0;
          }
          curColumn = null;
          curColumnHeight = 0;
        } else {
          // 当前栏未满
          curColumnHeight += curGroup.h;
          curColumn.texts.push(curGroup);
          curGroup = getNextGroup();
        }
      }

      if (curPage) {
        pages.push(curPage);
        curPage = null;
      }
      // 正文部分保证偶数页
      if (this.configModalForm.pageCountMode == "DOUBLE" && 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")
        );
        if (this.configModalForm.pageCountMode === "DOUBLE") {
          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];
        } else {
          pages = [...coverPages, ...pages];
        }
      }

      this.pages = pages;
    },
    // other
    getFullTextIndentStyle() {
      return {
        textIndent: `-${this.TEXT_INDENT_SIZE}px`,
        paddingLeft: `${this.TEXT_INDENT_SIZE}px`,
      };
    },
    getIndentStyle() {
      return {
        paddingLeft: `${this.TEXT_INDENT_SIZE}px`,
      };
    },
    getTextIndentStyle() {
      return {
        textIndent: `-${this.TEXT_INDENT_SIZE}px`,
      };
    },
    getSizePercent(size, fullSize, optionLength) {
      const rate = size / fullSize;
      if (optionLength == 5) {
        if (rate <= 0.2) {
          return 0.2;
        } else if (rate <= 0.33) {
          return 0.33;
        } else if (rate <= 0.5) {
          return 0.5;
        } else {
          return 1;
        }
      }
      if (rate <= 0.25) return 0.25;
      if (rate <= 0.5) return 0.5;
      return 1;
    },
    getResetPercent(maxPercent, optionCount) {
      if (optionCount == 5) {
        if (maxPercent > 0.5) {
          return 1;
        } else if (maxPercent > 0.33) {
          return 0.5;
        } else if (maxPercent > 0.2) {
          return 0.33;
        } else {
          return 0.2;
        }
      }
      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));
    },
    checkIsMatches(structType) {
      const matchesTypes = ["BANKED_CLOZE", "PARAGRAPH_MATCHING"];
      return matchesTypes.includes(structType);
    },
    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 };
              }
            }),
          };
        }),
      };
    },
    getRichStruct(blocks) {
      return {
        sections: [
          {
            blocks: [...blocks],
          },
        ],
      };
    },
    mergeRichStruct(structs) {
      let sections = [];
      structs.forEach((item) => {
        sections.push(...item.sections);
      });
      return { sections };
    },
    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;
    },
    parseLineGap() {
      return getRichTextModel({
        contType: "gap",
        styles: { width: "100%", height: "10px" },
        content: this.getRichStruct([{ type: "text", value: "" }]),
      });
    },
    parseDetailTitle(data) {
      let blocks = [
        {
          type: "text",
          value: this.configModalForm.showDetailScoreInfo
            ? `${data.name}（共${data.unitCount}小题，满分${data.score}分）`
            : `${data.name}`,
        },
      ];
      if (this.configModalForm.showDetailNo) {
        blocks.unshift({
          type: "text",
          value: `${data.cnNum}、`,
        });
      }
      let content = this.getRichStruct(blocks);
      return getRichTextModel({
        styles: { width: "100%", fontWeight: 900 },
        content,
      });
    },
    parseTitleOption(richJson, noVal, contType = "content") {
      if (isAnEmptyRichText(richJson)) return { elements: [], elementIds: [] };
      const bodys = this.transformRichJson(richJson);
      const elements = bodys.map((body, index) => {
        let presetData = {
          content: body,
          contType,
        };

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

        return getRichTextModel(presetData);
      });
      return { elements, elementIds: elements.map((item) => item.id) };
    },
    parseDetailNouns(detail) {
      let contents = [];
      let options = [];

      detail.paperDetailUnits.forEach((question) => {
        let questionInfo = question.question;
        questionInfo.number = question.number;
        let noVal = `${questionInfo.number}.`;
        const { elements, elementIds } = this.parseTitleOption(
          questionInfo.quesBody,
          noVal,
          "option"
        );
        contents.push(...elements);
        options.push(elementIds);
      });

      return { contents, options };
    },
    parseSimpleQuestion(question) {
      let questionRelateElement = {
        questionType: question.questionType,
        questionSeq: question.questionSeq,
        body: [],
        options: [],
        subQuestions: [],
      };
      const isMatches = this.checkIsMatches(question.questionType);
      let contents = [];
      let quesBody = question.quesBody;
      if (question.questionType === "FILL_BLANK_QUESTION") {
        quesBody = this.changeRichTextCloze(quesBody);
      }
      const { elements: bodyElements, elementIds: bodyElementIds } =
        this.parseTitleOption(
          quesBody,
          question.questionSeq ? `${question.questionSeq}.` : ""
        );
      contents.push(...bodyElements);
      questionRelateElement.body = bodyElementIds;

      if (question.quesOptions && question.quesOptions.length) {
        question.quesOptions.forEach((op) => {
          let noVal = `${numberToUpperCase(op.number)}.`;
          const { elements, elementIds } = this.parseTitleOption(
            op.optionBody,
            noVal,
            "option"
          );
          contents.push(...elements);
          questionRelateElement.options.push(elementIds);
        });
      }

      // 选词填空不展示小题
      if (question.questionType === "BANKED_CLOZE") {
        return { contents, questionRelateElement };
      }

      if (question.subQuestions && question.subQuestions.length) {
        question.subQuestions.forEach((sq, sqindex) => {
          sq.subNumber = sqindex + 1;
          if (isMatches) sq.quesOptions = []; // 选词填空、段落匹配小题中不展示选项
          const {
            contents: subContents,
            questionRelateElement: subQuestionRelateElement,
          } = this.parseSimpleQuestion(sq);
          contents.push(...subContents);
          questionRelateElement.subQuestions.push(subQuestionRelateElement);
        });
      }

      return { contents, questionRelateElement };
    },
    // page
    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,
        pageNumberRule: pageTemp.pageNumberRule,
      });
      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 = document.getElementById(`preview-${elem.id}`).offsetHeight;
          if (nelem.elements && nelem.elements.length) {
            nelem.elements.forEach((celem) => {
              celem.id = getElementId();
              celem.key = randomCode();
            });
          }
          return nelem;
        });
        column.texts = [];
      });
      return newPage;
    },
  },
};
