// 分类表
const CLASS_BOOK = (() => {
  const setting = {
    header: [{ headerName: '分类', headerWidth: $('#area-spread').width(), dataCode: 'name', dataType: 'String', hAlign: 'left', vAlign: 'center' }],
    controller: {
      cols: [
        {
          data: {
            field: 'name',
            vAlign: 1,
            hAlign: 0,
            font: 'Arial'
          },
        }
      ],
      headRows: 1,
      headRowHeight: [30],
      emptyRows: 0,
      treeCol: 0
    },
    tree: {
      id: 'ID',
      pid: 'ParentID',
      nid: 'NextSiblingID',
      rootId: -1
    }
  };
  // 初始化表格
  const workBook = initSheet($('#class-spread')[0], setting);
  workBook.options.allowExtendPasteRange = false;
  workBook.options.allowUserDragDrop = true;
  workBook.options.allowUserDragFill = true;
  const sheet = workBook.getSheet(0);

  let tree;
  let controller;
  // 初始化数据
  async function initData(libID, areaID) {
    if (!areaID) {
      tree = null;
      controller = null;
      sheet.setRowCount(0);
      PRICE_BOOK.clear();
      return;
    }
    $.bootstrapLoading.start();
    try {
      const data = await ajaxPost('/priceInfo/getClassData', { libID, areaID }, TIME_OUT);
      tree = idTree.createNew(setting.tree);
      tree.loadDatas(data);
      tree.selected = tree.items.length > 0 ? tree.items[0] : null;
      controller = TREE_SHEET_CONTROLLER.createNew(tree, sheet, setting.controller, false);
      controller.showTreeData();
      handleSelectionChanged(0);
      sheet.setSelection(0, 0, 1, 1);
      lockUtil.lockSpreads([workBook], locked);
    } catch (err) {
      tree = null;
      controller = null;
      sheet.setRowCount(0);
      alert(err);
    } finally {
      $.bootstrapLoading.end();
    }
  }

  // 编辑处理
  async function handleEdit(changedCells) {
    const updateData = [];
    changedCells.forEach(({ row, col }) => {
      updateData.push({
        row,
        type: UpdateType.UPDATE,
        filter: { ID: tree.items[row].data.ID },
        update: { name: sheet.getValue(row, col) }
      });
    });
    try {
      await ajaxPost('/priceInfo/editClassData', { updateData }, TIME_OUT);
      updateData.forEach(({ row, update: { name } }) => tree.items[row].data.name = name);
    } catch (err) {
      // 恢复各单元格数据
      sheetCommonObj.renderSheetFunc(sheet, () => {
        changedCells.forEach(({ row }) => {
          sheet.setValue(tree.items[row].data.name);
        });
      });
    }
  }
  sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) {
    const changedCells = [{ row: info.row, col: info.col }];
    handleEdit(changedCells);
  });
  sheet.bind(GC.Spread.Sheets.Events.RangeChanged, function (e, info) {
    handleEdit(info.changedCells);
  });

  // 树操作相关
  const $insert = $('#tree-insert');
  const $remove = $('#tree-remove');
  const $upLevel = $('#tree-up-level');
  const $downLevel = $('#tree-down-level');
  const $downMove = $('#tree-down-move');
  const $upMove = $('#tree-up-move');
  const $calcPriceIndex = $('#calc-price-index');
  const $matchSummary = $('#match-summary');
  const $showEmpty = $('#show-empty');

  // 插入
  let canInsert = true;
  async function insert() {
    try {
      if (!canInsert) {
        return false;
      }
      canInsert = false;
      $.bootstrapLoading.start();
      const updateData = [];
      const selected = tree.selected;
      const newItem = {
        libID,
        areaID: AREA_BOOK.curArea.ID,
        ID: uuid.v1(),
        name: '',
        ParentID: '-1',
        NextSiblingID: '-1'
      };
      if (selected) {
        newItem.ParentID = selected.data.ParentID;
        updateData.push({
          type: UpdateType.UPDATE,
          filter: { ID: selected.data.ID },
          update: { NextSiblingID: newItem.ID }
        });
        if (selected.nextSibling) {
          newItem.NextSiblingID = selected.nextSibling.data.ID;
        }
      }
      updateData.push({
        type: UpdateType.CREATE,
        document: newItem
      });
      await ajaxPost('/priceInfo/editClassData', { updateData });
      controller.insertByID(newItem.ID);
      handleSelectionChanged(sheet.getActiveRowIndex());
    } catch (err) {
      alert(err);
    } finally {
      canInsert = true;
      $.bootstrapLoading.end();
    }
  }

  $insert.click(_.debounce(insert, DEBOUNCE_TIME, { leading: true }));

  // 删除
  let canRemove = true;
  async function remove() {
    try {
      if (!canRemove) {
        return false;
      }
      canRemove = false;
      $.bootstrapLoading.start();
      const updateData = [];
      const selected = tree.selected;
      const children = selected.getPosterity();
      [selected, ...children].forEach(node => updateData.push({
        type: UpdateType.DELETE,
        filter: { ID: node.data.ID }
      }));
      if (selected.preSibling) {
        updateData.push({
          type: UpdateType.UPDATE,
          filter: { ID: selected.preSibling.data.ID },
          update: { NextSiblingID: selected.data.NextSiblingID }
        });
      }
      await ajaxPost('/priceInfo/editClassData', { updateData });
      controller.delete();
      handleSelectionChanged(sheet.getActiveRowIndex());
    } catch (err) {
      alert(err);
    } finally {
      canRemove = true;
      $.bootstrapLoading.end();
    }
  }

  $remove.click(_.debounce(remove, DEBOUNCE_TIME, { leading: true }));

  // 升级
  let canUpLevel = true;
  async function upLevel() {
    try {
      if (!canUpLevel) {
        return false;
      }
      canUpLevel = false;
      $.bootstrapLoading.start();
      const updateData = [];
      const selected = tree.selected;
      if (selected.preSibling) {
        updateData.push({
          type: UpdateType.UPDATE,
          filter: { ID: selected.preSibling.data.ID },
          update: { NextSiblingID: -1 }
        });
      }
      if (selected.parent) {
        updateData.push({
          type: UpdateType.UPDATE,
          filter: { ID: selected.parent.data.ID },
          update: { NextSiblingID: selected.data.ID }
        });
      }
      updateData.push({
        type: UpdateType.UPDATE,
        filter: { ID: selected.data.ID },
        update: { ParentID: selected.parent.data.ParentID, NextSiblingID: selected.parent.data.NextSiblingID }
      });
      let curNode = selected.nextSibling;
      while (curNode) {
        updateData.push({
          type: UpdateType.UPDATE,
          filter: { ID: curNode.data.ID },
          update: { ParentID: selected.data.ID }
        });
        curNode = curNode.nextSibling;
      }
      await ajaxPost('/priceInfo/editClassData', { updateData });
      controller.upLevel();
      refreshTreeButton(tree.selected);
    } catch (err) {
      alert(err);
    } finally {
      canUpLevel = true;
      $.bootstrapLoading.end();
    }
  }

  $upLevel.click(_.debounce(upLevel, DEBOUNCE_TIME, { leading: true }));

  // 降级
  let canDownLevel = true;
  async function downLevel() {
    try {
      if (!canDownLevel) {
        return false;
      }
      canDownLevel = false;
      $.bootstrapLoading.start();
      const updateData = [];
      const selected = tree.selected;
      if (selected.preSibling) {
        updateData.push({
          type: UpdateType.UPDATE,
          filter: { ID: selected.preSibling.data.ID },
          update: { NextSiblingID: selected.data.NextSiblingID }
        });
        const preSiblingLastChild = selected.preSibling.children[selected.preSibling.children.length - 1];
        if (preSiblingLastChild) {
          updateData.push({
            type: UpdateType.UPDATE,
            filter: { ID: preSiblingLastChild.data.ID },
            update: { NextSiblingID: selected.data.ID }
          });
        }
        updateData.push({
          type: UpdateType.UPDATE,
          filter: { ID: selected.data.ID },
          update: { ParentID: selected.preSibling.data.ID, NextSiblingID: -1 }
        });
      }
      await ajaxPost('/priceInfo/editClassData', { updateData });
      controller.downLevel();
      refreshTreeButton(tree.selected);
    } catch (err) {
      alert(err);
    } finally {
      canDownLevel = true;
      $.bootstrapLoading.end();
    }
  }

  $downLevel.click(_.debounce(downLevel, DEBOUNCE_TIME, { leading: true }));

  // 下移
  let canDownMove = true;
  async function downMove() {
    try {
      if (!canDownMove) {
        return false;
      }
      canDownMove = false;
      $.bootstrapLoading.start();
      const updateData = [];
      const selected = tree.selected;
      if (selected.preSibling) {
        updateData.push({
          type: UpdateType.UPDATE,
          filter: { ID: selected.preSibling.data.ID },
          update: { NextSiblingID: selected.data.NextSiblingID }
        });
      }
      updateData.push({
        type: UpdateType.UPDATE,
        filter: { ID: selected.data.ID },
        update: { NextSiblingID: selected.nextSibling.data.NextSiblingID }
      });
      updateData.push({
        type: UpdateType.UPDATE,
        filter: { ID: selected.nextSibling.data.ID },
        update: { NextSiblingID: selected.data.ID }
      });
      await ajaxPost('/priceInfo/editClassData', { updateData });
      controller.downMove();
      refreshTreeButton(tree.selected);
    } catch (err) {
      alert(err);
    } finally {
      canDownMove = true;
      $.bootstrapLoading.end();
    }
  }

  $downMove.click(_.debounce(downMove, DEBOUNCE_TIME, { leading: true }));

  // 上移
  let canUpMove = true;
  async function upMove() {
    try {
      if (!canUpMove) {
        return false;
      }
      canUpMove = false;
      $.bootstrapLoading.start();
      const updateData = [];
      const selected = tree.selected;
      if (selected.preSibling) {
        updateData.push({
          type: UpdateType.UPDATE,
          filter: { ID: selected.preSibling.data.ID },
          update: { NextSiblingID: selected.data.NextSiblingID }
        });
      }
      const prePreSibling = selected.preSibling.preSibling;
      if (prePreSibling) {
        updateData.push({
          type: UpdateType.UPDATE,
          filter: { ID: prePreSibling.data.ID },
          update: { NextSiblingID: selected.data.ID }
        });
      }
      updateData.push({
        type: UpdateType.UPDATE,
        filter: { ID: selected.data.ID },
        update: { NextSiblingID: selected.preSibling.data.ID }
      });
      await ajaxPost('/priceInfo/editClassData', { updateData });
      controller.upMove();
      refreshTreeButton(tree.selected);
    } catch (err) {
      alert(err);
    } finally {
      canUpMove = true;
      $.bootstrapLoading.end();
    }
  }

  $upMove.click(_.debounce(upMove, DEBOUNCE_TIME, { leading: true }));


  // 刷新树操作按钮有效性
  function refreshTreeButton(selected) {
    if (locked) {
      return;
    }
    $insert.removeClass('disabled');
    $remove.removeClass('disabled');
    $upLevel.removeClass('disabled');
    $downLevel.removeClass('disabled');
    $downMove.removeClass('disabled');
    $upMove.removeClass('disabled');
    if (!selected) {
      $remove.addClass('disabled');
      $upLevel.addClass('disabled');
      $downLevel.addClass('disabled');
      $downMove.addClass('disabled');
      $upMove.addClass('disabled');
    } else {
      if (!selected.preSibling) {
        $downLevel.addClass('disabled');
        $upMove.addClass('disabled');
      }
      if (!selected.nextSibling) {
        $downMove.addClass('disabled');
      }
      if (!selected.parent) {
        $upLevel.addClass('disabled');
      }
    }
  }

  // 焦点变更处理
  const curClass = { ID: null };
  function handleSelectionChanged(row) {
    curRow = row;
    const classNode = tree.items[row] || null;
    tree.selected = classNode;
    refreshTreeButton(classNode);
    curClass.ID = classNode && classNode.data && classNode.data.ID || null;
    const classIDList = []
    if (classNode) {
      classIDList.push(classNode.data.ID);
      const children = classNode.getPosterity();
      children.forEach(child => classIDList.push(child.data.ID));
    }
    PRICE_BOOK.initData(classIDList);
  }
  const debounceSelectionChanged = _.debounce(function (e, info) {
    const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
    handleSelectionChanged(row);
  }, DEBOUNCE_TIME, { leading: true });
  sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged);

  const reload = () => {
    if (curClass.ID) {
      const node = tree.nodes[tree.prefix + curClass.ID];
      if (node) {
        handleSelectionChanged(node.serialNo())
      }
    }
  }



  $calcPriceIndex.click(_.debounce(async () => {
    $.bootstrapLoading.start();
    try {
      const data = await ajaxPost('/priceInfo/calcPriceIndex', { libID, period: curLibPeriod, compilationID }, TIME_OUT);
      //alert(data);

      if (data) {
        const htmlStr = data.replace(/\n/gm, '<br>'); //replaceAll('\n','<br>',data);
        $("#result-info-body").html(htmlStr);
        $("#result-info").modal('show');
      } else {
        alert('计算完成！')
      }


    } catch (error) {
      console.log(error);
    }
    $.bootstrapLoading.end();

  }, DEBOUNCE_TIME, { leading: true }));

  // 匹配总表
  $matchSummary.click(_.debounce(async () => {
    $.bootstrapLoading.progressStart('匹配总表', true);
    $("#progress_modal_body").text('正在匹配总表，请稍后...');
    try {
      const matchAll = $('#match-all-input')[0].checked;
      const areaID = matchAll ? '' : AREA_BOOK.curArea?.ID;
      await ajaxPost('/priceInfo/matchSummary', { libID, compilationID, areaID }, 1000 * 60 * 10);
      setTimeout(() => {
        $.bootstrapLoading.progressEnd();
        window.location.reload()
      }, 1000)
    } catch (error) {
      alert(error)
      console.log(error);
      $.bootstrapLoading.progressEnd();
    }
  }, DEBOUNCE_TIME, { leading: true }));

  // 显示空数据
  $showEmpty.click(() => {
    $('#empty-area').modal('show');
  });


  return {
    initData,
    handleSelectionChanged,
    curClass,
    reload,
  }

})();
