import {
  getExplainElements,
  getFillQuesitonElements,
  getFillLineElements,
  getCompositionElements,
  getNewPage,
  getTopicHeadModel,
} from "../elementModel";
import {
  objAssign,
  deepCopy,
  calcSum,
  getElementId,
  numberIsOdd,
} from "../plugins/utils";

const state = {
  cardConfig: {},
  paperParams: {},
  paperSimpleStruct: "",
  curElement: {},
  curDragElement: {},
  curPage: {},
  curPageNo: 0,
  pageDefaultElems: {
    elements: [],
    sideLeft: [],
    sideRight: [],
  },
  pages: [],
  topics: [],
  topicSeries: [], // 大题顺序号
  insetTarget: {}, // 需要在其后面插入大题的大题
  openElementEditDialog: false,
};

const mutations = {
  setCardConfig(state, cardConfig) {
    state.cardConfig = Object.assign({}, state.cardConfig, cardConfig);
  },
  setPaperParams(state, paperParams) {
    state.paperParams = paperParams;
  },
  setPaperSimpleStruct(state, paperSimpleStruct) {
    state.paperSimpleStruct = paperSimpleStruct;
  },
  setCurElement(state, curElement) {
    state.curElement = curElement;
  },
  setCurDragElement(state, curDragElement) {
    state.curDragElement = curDragElement;
  },
  setCurPage(state, curPageNo) {
    const pageNo = state.pages[curPageNo] ? curPageNo : 0;
    state.curPage = state.pages[pageNo];
    state.curPageNo = pageNo;
  },
  setCurPageNo(state, curPageNo) {
    state.curPageNo = curPageNo;
  },
  setPages(state, pages) {
    state.pages = pages;
  },
  setPageDefaultElems(state, pageDefaultElems) {
    state.pageDefaultElems = pageDefaultElems;
  },
  setTopics(state, topics) {
    state.topics = topics;
  },
  setTopicSeries(state, topicSeries) {
    state.topicSeries = topicSeries;
  },
  setInsetTarget(state, insetTarget) {
    state.insetTarget = insetTarget;
  },
  addPage(state, page) {
    state.pages.push(page);
  },
  modifyPage(state, page) {
    state.pages.splice(page._pageNo, 1, page);
  },
  setOpenElementEditDialog(state, openElementEditDialog) {
    state.openElementEditDialog = openElementEditDialog;
  },
  initState(state) {
    state.curElement = {};
    state.curDragElement = {};
    state.curPage = {};
    state.curPageNo = 0;
    state.topics = [];
    state.pages = [];
    state.cardConfig = {};
    state.paperParams = {};
    state.openElementEditDialog = false;
    state.topicSeries = [];
  },
};

const fetchElementPositionInfos = (element, topics) => {
  return topics.findIndex((item) => item.id === element.id);
};

const fetchAllRelateParentElementPositionInfos = (parentElement, topics) => {
  // 当为解答题时，parentElement传入的值是EXPLAIN
  let postionInfos = [];
  topics.forEach((item, eindex) => {
    if (item["parent"] && item.parent.id === parentElement.id) {
      let pos = { _elementNo: eindex };
      if (parentElement.type === "EXPLAIN") {
        pos.serialNumber = item.serialNumber;
      }
      postionInfos.push(pos);
    }
  });

  return postionInfos;
};

const fetchFirstSubjectiveTopicPositionInfo = (topics) => {
  return topics.findIndex((item) => item.sign === "subjective");
};

const fetchSameSerialNumberChildrenPositionInfo = (
  elementChildernElement,
  topics
) => {
  let postionInfos = [];
  const elementId = elementChildernElement.parent.id;
  const serialNumber = elementChildernElement.serialNumber;

  topics.forEach((item, eindex) => {
    if (
      item.parent &&
      item.parent.id === elementId &&
      item.serialNumber === serialNumber
    ) {
      postionInfos.push({
        _elementNo: eindex,
        _elementId: item.id,
      });
    }
  });
  return postionInfos;
};

const groupByParams = (datas, paramKey) => {
  let elementGroupInfos = [];
  for (let i = 0, len = datas.length; i < len; i++) {
    if (i === 0 || datas[i][paramKey] !== datas[i - 1][paramKey]) {
      elementGroupInfos.push([datas[i]]);
    } else {
      elementGroupInfos[elementGroupInfos.length - 1].push(datas[i]);
    }
  }
  return elementGroupInfos;
};

const findElementById = (id, topics) => {
  let curElement = null;
  topics.forEach((element) => {
    if (curElement) return;
    if (element.id === id) {
      curElement = element;
      return;
    }

    if (element["elements"]) {
      element["elements"].forEach((elem) => {
        if (elem.id === id) curElement = elem;
      });
    }
  });
  return curElement;
};

const checkElementisCovered = (id, type) => {
  const elementDom = document.getElementById(id);

  if (type === "EXPLAIN") {
    const elemTitleDome = elementDom.querySelector(".elem-title");
    const limitHeight = elemTitleDome
      ? elementDom.offsetHeight - elemTitleDome.offsetHeight
      : elementDom.offsetHeight;

    let elementHeights = [];
    elementDom
      .querySelector(".elem-explain-elements")
      .childNodes.forEach((node) => {
        if (!node.className.includes("elem-explain-element")) return;
        elementHeights.push(
          node.firstChild.offsetHeight + node.firstChild.offsetTop
        );
      });
    return elementHeights.some((item) => item > limitHeight);
  }

  if (type === "COMPOSITION") {
    const elemTitleDome = elementDom.querySelector(".elem-title");
    const limitHeight = elemTitleDome
      ? elementDom.offsetHeight - elemTitleDome.offsetHeight
      : elementDom.offsetHeight;

    let elementHeights = [];
    elementDom
      .querySelector(".elem-composition-elements")
      .childNodes.forEach((node) => {
        if (!node.className.includes("elem-composition-element")) return;
        elementHeights.push(
          node.firstChild.offsetHeight + node.firstChild.offsetTop
        );
      });
    return elementHeights.some((item) => item > limitHeight);
  }

  return elementDom.offsetHeight < elementDom.firstChild.offsetHeight;
};

const createFunc = {
  EXPLAIN(element) {
    return getExplainElements(element);
  },
  FILL_QUESTION(element) {
    return getFillQuesitonElements(element, state.cardConfig);
  },
  FILL_LINE(element) {
    return getFillLineElements(element);
  },
  COMPOSITION(element) {
    return [getCompositionElements(element)];
  },
};

const actions = {
  initTopicsFromPages({ state, commit }) {
    let topics = [];
    state.pages.forEach((page) => {
      page.columns.forEach((column) => {
        column.elements.forEach((element) => {
          if (
            element.type === "TOPIC_HEAD" ||
            (element.type === "CARD_HEAD" && element.isSimple)
          )
            return;
          topics.push(element);
        });
      });
    });
    commit("setTopics", topics);
  },
  actElementById({ state, commit }, id) {
    const curElement = findElementById(id, state.topics);
    if (!curElement) return;

    commit("setCurElement", curElement);
  },
  resetTopicSeries({ state, commit }) {
    let curTopicId = "",
      curTopicNo = 0,
      topicSeries = [];
    state.topics.forEach((topic) => {
      if (!topic.parent) return;
      if (curTopicId !== topic.parent.id) {
        curTopicId = topic.parent.id;
        curTopicNo++;
        topicSeries.push({
          id: curTopicId,
          topicNo: curTopicNo,
          type: topic.type,
          sign: topic.sign,
        });
      }
      topic.topicNo = curTopicNo;
    });
    commit("setTopicSeries", topicSeries);
  },
  // 新增试题 --------------->
  addElement({ state, commit, dispatch }, element) {
    let pos = null;
    // 客观题和主观题分别对待
    if (state.insetTarget.id) {
      // 存在插入目标元素
      if (
        state.insetTarget.type === "FILL_QUESTION" &&
        element.type !== "FILL_QUESTION"
      ) {
        pos = fetchFirstSubjectiveTopicPositionInfo(state.topics);
      } else {
        let relateTopicPos = [];
        state.topics.forEach((item, index) => {
          if (item.parent && item.parent.id === state.insetTarget.id)
            relateTopicPos.push(index);
        });
        pos = relateTopicPos.slice(-1)[0] + 1;
      }
    } else {
      // 不存在插入目标元素
      if (element.sign === "objective") {
        pos = fetchFirstSubjectiveTopicPositionInfo(state.topics);
      }
    }

    let preElements = createFunc[element.type](element);
    preElements.forEach((preElement, index) => {
      if (pos && pos !== -1) {
        state.topics.splice(pos + index, 0, preElement);
      } else {
        state.topics.push(preElement);
      }
    });
    dispatch("resetTopicSeries");
    commit("setInsetTarget", {});

    commit("setCurElement", element);
  },
  // 修改试题 --------------->
  modifyTopic({ state }, element) {
    // 单独编辑某个细分题
    const pos = fetchElementPositionInfos(element, state.topics);
    state.topics.splice(pos, 1, element);
  },
  modifyComposition({ state }, element) {
    const positionInfos = fetchAllRelateParentElementPositionInfos(
      element,
      state.topics
    );
    positionInfos.forEach(({ _elementNo }) => {
      state.topics[_elementNo].topicNo = element.topicNo;
      state.topics[_elementNo].parent = objAssign(
        state.topics[_elementNo].parent,
        element
      );
    });
  },
  modifyExplain({ state }, element) {
    // 解答题既是拆分题，又是可复制题
    const positionInfos = fetchAllRelateParentElementPositionInfos(
      element,
      state.topics
    );
    const elementGroupPosInfos = groupByParams(positionInfos, "serialNumber");
    for (let i = 0; i < elementGroupPosInfos.length; i++) {
      elementGroupPosInfos[i].forEach((pos) => {
        let child = state.topics[pos._elementNo];
        child.parent = { ...element };
        child.topicName = element.topicName;
      });
    }
  },
  modifySplitTopic({ state }, element) {
    // 非作文题都是拆分题，即同一个题拆分成多个小题展示
    const positionInfos = fetchAllRelateParentElementPositionInfos(
      element,
      state.topics
    );
    // 缓存已编辑的小题高度信息。
    // const elementHeights = positionInfos.map(
    //   pos => state.topics[pos._elementNo].h
    // );
    // 删除所有小题
    positionInfos.reverse().forEach((pos) => {
      state.topics.splice(pos._elementNo, 1);
    });
    // 创建新的小题元素
    const newElements = createFunc[element.type](element);
    const pos = positionInfos.pop();
    newElements.forEach((newElement, index) => {
      // 不再复用缓存高度，修改于2022-03-10 09:23
      // newElement.h = Math.max(elementHeights[index] || 0, newElement.h);
      state.topics.splice(pos._elementNo + index, 0, newElement);
    });
  },
  modifyElement({ dispatch }, element) {
    if (element.type === "COMPOSITION") {
      dispatch("modifyComposition", element);
    } else if (element.type === "EXPLAIN") {
      dispatch("modifyExplain", element);
    } else {
      dispatch("modifySplitTopic", element);
    }
    dispatch("resetTopicSeries");
    // commit("setCurElement", element);
  },
  modifyCardHead({ state }, element) {
    state.topics.splice(0, 1, element);
  },
  // 修改试题包含元素
  modifyElementChild({ state, commit }, element) {
    // 修改解答题小题和作文题的子元素
    const pos = fetchElementPositionInfos(element.container, state.topics);
    const columnElements = state.topics[pos].elements;
    const childIndex = columnElements.findIndex(
      (item) => item.id === element.id
    );
    element.id = getElementId();
    // 作文题中的多线条和网格元素重新计算高度。
    if (element.container.type === "COMPOSITION") {
      if (element.type === "LINES") {
        element.h = element.lineCount * (element.lineSpacing + 1);
      }
      if (element.type === "GRIDS") {
        if (element.halving) {
          const columnWs = {
            2: 703,
            3: 461,
            4: 349,
          };
          const columnSize =
            columnWs[state.cardConfig.columnNumber] / element.columnCount;
          element.h = element.rowCount * (columnSize + element.rowSpace) + 1;
        } else {
          element.h =
            element.rowCount * (element.columnSize + element.rowSpace) + 1;
        }
      }
    }
    if (childIndex === -1) {
      columnElements.push(element);
    } else {
      columnElements.splice(childIndex, 1, element);
    }

    commit("setCurElement", element);
  },
  // 粘贴试题内的元素
  pasteExplainElementChild({ state }, { curElement, pasteElement }) {
    let element = {
      id: curElement.container ? curElement.container.id : curElement.id,
    };
    const pos = fetchElementPositionInfos(element, state.topics);
    if (pos === -1) return;

    element = state.topics[pos];
    const newElement = Object.assign({}, pasteElement, {
      id: getElementId(),
      container: {
        id: element.id,
        type: element.type,
      },
    });
    element.elements.push(newElement);
  },
  // 删除试题 --------------->
  removeElement({ state, commit, dispatch }, element) {
    const positionInfos = fetchAllRelateParentElementPositionInfos(
      element.parent,
      state.topics
    );
    positionInfos.reverse().forEach((pos) => {
      state.topics.splice(pos._elementNo, 1);
    });

    dispatch("resetTopicSeries");

    commit("setCurElement", {});
  },
  // 删除试题包含元素 --------------->
  removeElementChild({ state, commit }, element) {
    // 删除解答题小题和作文题的子元素
    const pos = fetchElementPositionInfos(element.container, state.topics);
    const columnElements = state.topics[pos].elements;
    const childIndex = columnElements.findIndex(
      (item) => item.id === element.id
    );
    columnElements.splice(childIndex, 1);

    commit("setCurElement", {});
  },
  // 扩展答题区操作 --------------->
  copyExplainChildren({ state }, element) {
    let curElement = {
      id: element.container ? element.container.id : element.id,
    };
    const pos = fetchElementPositionInfos(curElement, state.topics);
    curElement = state.topics[pos];

    let newElement = Object.assign({}, curElement, {
      id: getElementId(),
      elements: [],
      h: 200,
      isExtend: true,
      showTitle: false,
    });

    state.topics.splice(pos + 1, 0, newElement);
    // 更新小题答题区isLast
    let positionInfos = fetchSameSerialNumberChildrenPositionInfo(
      curElement,
      state.topics
    );
    positionInfos.forEach((pos, pindex) => {
      state.topics[pos._elementNo].isLast = pindex + 1 === positionInfos.length;
    });
  },
  deleteExplainChildren({ state }, element) {
    let curElement = {
      id: element.container ? element.container.id : element.id,
    };
    const curPos = fetchElementPositionInfos(curElement, state.topics);
    curElement = state.topics[curPos];

    let positionInfos = fetchSameSerialNumberChildrenPositionInfo(
      curElement,
      state.topics
    );
    if (positionInfos.length < 2) return;
    const pindex = positionInfos.findIndex(
      (item) => item._elementId === curElement.id
    );
    const pos = positionInfos[pindex]._elementNo;
    positionInfos.splice(pindex, 1);
    const nextPos = positionInfos[0]._elementNo;
    // 当删除的是非扩展区域时，则下一个答题区要被设置成非扩展区
    if (!curElement.isExtend) {
      state.topics[nextPos].isExtend = false;
    }
    // 当删除的是含有标题答题区时，则需要将下一个答题区开启显示标题。
    if (curElement.showTitle) {
      state.topics[nextPos].showTitle = true;
    }
    state.topics.splice(pos, 1);
    // 更新小题答题区isLast
    positionInfos = fetchSameSerialNumberChildrenPositionInfo(
      curElement,
      state.topics
    );
    positionInfos.forEach((pos, pindex) => {
      state.topics[pos._elementNo].isLast = pindex + 1 === positionInfos.length;
    });
  },
  // 大题顺序操作 --------------->
  topicMoveUp({ state, dispatch }, topicId) {
    const curTopicPos = state.topicSeries.findIndex(
      (item) => item.id === topicId
    );
    const prevTopicId = state.topicSeries[curTopicPos - 1].id;
    let relateTopicPos = [];
    state.topics.forEach((item, index) => {
      if (item.parent && item.parent.id === topicId) relateTopicPos.push(index);
    });
    const prevTopicFirstIndex = state.topics.findIndex(
      (item) => item.parent && item.parent.id === prevTopicId
    );
    const relateTopics = state.topics.splice(
      relateTopicPos[0],
      relateTopicPos.length
    );
    relateTopics.reverse().forEach((topic) => {
      state.topics.splice(prevTopicFirstIndex, 0, topic);
    });

    dispatch("resetTopicSeries");
  },
  // 重构页面
  resetElementProp({ state }, isResetId = false) {
    state.topics.forEach((element) => {
      const elementDom = document.getElementById(element.id);
      if (elementDom) {
        element.h = elementDom.offsetHeight;
        element.w = elementDom.offsetWidth;
      }
      if (isResetId) {
        element.id = getElementId();
      }
    });
  },
  rebuildPages({ state, commit }) {
    const columnNumber = state.cardConfig.columnNumber;
    const pageSize = state.cardConfig.pageSize;
    // 更新元件最新的高度信息
    // 整理所有元件
    state.topics.forEach((element) => {
      const elementDom = document.getElementById(`preview-${element.id}`);

      if (elementDom) {
        element.h = elementDom.offsetHeight;
        element.w = elementDom.offsetWidth;
        // 解答题小题与其他题有些区别。
        // 其他题都是通过内部子元素自动撑高元件，而解答题则需要手动设置高度。
        const ESCAPE_ELEMENTS = ["CARD_HEAD"];
        element.isCovered =
          !ESCAPE_ELEMENTS.includes(element.type) &&
          checkElementisCovered(`preview-${element.id}`, element.type);
      }
    });

    // 动态计算每列可以分配的元件
    const columnHeight = document.getElementById("topic-column").offsetHeight;
    let pages = [];
    let page = {};
    let columns = [];
    let curColumnElements = [];
    let curColumnHeight = 0;

    const initCurColumnElements = () => {
      curColumnElements = [];
      curColumnHeight = 0;
    };

    const checkElementIsCurColumnFirstType = (element) => {
      if (element.type === "CARD_HEAD") return;

      const topicHeadIndex = curColumnElements.findIndex(
        (elem) => elem.type === "TOPIC_HEAD" && elem.sign === element.sign
      );
      return topicHeadIndex === -1;
    };

    // 放入元素通用流程
    const pushElement = (element) => {
      // 当前栏中第一个题型之前新增题型头元素（topic-head）。
      // 题型头和当前题要组合加入栏中，不可拆分。
      let elementList = [element];
      if (checkElementIsCurColumnFirstType(element)) {
        elementList.unshift(
          getTopicHeadModel(
            state.cardConfig[`${element.sign}Attention`],
            element.sign,
            !curColumnElements.length
          )
        );
      }

      const elementHeight = calcSum(elementList.map((elem) => elem.h));
      if (curColumnHeight + elementHeight > columnHeight) {
        // 当前栏第一个元素高度超过一栏时，不拆分，直接放在当前栏。
        // 解决可能空栏的情况
        const curElementIsFirst = !curColumnElements.length;
        if (curElementIsFirst) {
          curColumnElements = [...curColumnElements, ...elementList];
          curColumnHeight += elementHeight;
        } else {
          columns.push([...curColumnElements]);
          initCurColumnElements();
          pushElement(element);
        }
      } else {
        curColumnElements = [...curColumnElements, ...elementList];
        curColumnHeight += elementHeight;
      }
    };

    // 批量添加所有元素。
    initCurColumnElements();
    state.topics.forEach((element, eindex) => {
      element.elementSerialNo = eindex;
      pushElement(element);
    });

    // 最后一栏的处理。
    columns.push([...curColumnElements]);
    // 构建pages
    columns.forEach((column, cindex) => {
      const columnNo = cindex % columnNumber;
      if (!columnNo) {
        page = getNewPage(pages.length, { pageSize, columnNumber });
      }
      page.columns[columnNo].elements = column;

      if (columnNo + 1 === columnNumber || cindex === columns.length - 1) {
        pages.push(page);
      }
    });
    // 保证页面总是偶数页
    if (numberIsOdd(pages.length)) {
      pages.push(getNewPage(pages.length, { pageSize, columnNumber }));
    }

    pages.forEach((page, pindex) => {
      if (numberIsOdd(pindex + 1)) {
        page.sides = deepCopy(state.pageDefaultElems.sideLeft);
      } else {
        page.sides = deepCopy(state.pageDefaultElems.sideRight);
      }
    });

    commit("setPages", pages);
    commit("setCurPage", state.curPageNo);
  },
};

export { fetchSameSerialNumberChildrenPositionInfo, checkElementisCovered };

export default {
  namespaced: true,
  state,
  mutations,
  actions,
};
