
function setAlign(sheet, headers) {
    const fuc = () => {
        headers.forEach(({ hAlign, vAlign }, index) => {
            sheetCommonObj.setAreaAlign(sheet.getRange(-1, index, -1, 1), hAlign, vAlign)
        });
    };
    sheetCommonObj.renderSheetFunc(sheet, fuc);
}

function setFormatter(sheet, headers) {
    const fuc = () => {
        headers.forEach(({ formatter }, index) => {
            if (formatter) {
                sheet.setFormatter(-1, index, formatter);
            }
        });
    };
    sheetCommonObj.renderSheetFunc(sheet, fuc);
}

function initSheet(dom, setting) {
    const workBook = sheetCommonObj.buildSheet(dom, setting);
    const sheet = workBook.getSheet(0);
    setAlign(sheet, setting.header);
    setFormatter(sheet, setting.header);
    return workBook;
}

function showData(sheet, data, headers, emptyRows) {
    const fuc = () => {
        sheet.setRowCount(data.length);
        data.forEach((item, row) => {
            headers.forEach(({ dataCode }, col) => {
                sheet.setValue(row, col, item[dataCode] || '');
            });
        });
        if (emptyRows) {
            sheet.addRows(data.length, emptyRows);
        }
    };
    sheetCommonObj.renderSheetFunc(sheet, fuc);
}

const TIME_OUT = 10000;
const libID = window.location.search.match(/libID=([^&]+)/)[1];

const UpdateType = {
    UPDATE: 'update',
    DELETE: 'delete',
    CREATE: 'create',
};

const DEBOUNCE_TIME = 200;

const locked = lockUtil.getLocked();

// 地区表
const AREA_BOOK = (() => {
    const cache = areaList;
    const setting = {
        header: [{ headerName: '地区', headerWidth: $('#area-spread').width(), dataCode: 'name', dataType: 'String', hAlign: 'center', vAlign: 'center' }]
    };
    // 初始化表格
    const workBook = initSheet($('#area-spread')[0], setting);
    lockUtil.lockSpreads([workBook], locked);
    workBook.options.allowExtendPasteRange = false;
    workBook.options.allowUserDragDrop = true;
    workBook.options.allowUserDragFill = true;
    const sheet = workBook.getSheet(0);

    // 排序显示
    cache.sort((a, b) => a.serialNo - b.serialNo);

    // 显示数据
    showData(sheet, cache, setting.header);

    // 编辑处理
    async function handleEdit(changedCells) {
        const updateData = [];
        changedCells.forEach(({ row, col }) => {
            updateData.push({
                row,
                ID: cache[row].ID,
                name: sheet.getValue(row, col)
            });
        });
        try {
            await ajaxPost('/priceInfo/editArea', { updateData }, TIME_OUT);
            updateData.forEach(({ row, name }) => cache[row].name = name);
        } catch (err) {
            // 恢复各单元格数据
            sheetCommonObj.renderSheetFunc(sheet, () => {
                changedCells.forEach(({ row }) => {
                    sheet.setValue(cache[row].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 curArea = { ID: null };
    // 焦点变更处理
    const debounceSelectionChanged = _.debounce(function (e, info) {
        const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
        handleSelectionChanged(row);
    }, DEBOUNCE_TIME, { leading: true }); // leading = true : 先触发再延迟
    function handleSelectionChanged(row) {
        const areaItem = cache[row];
        curArea.ID = areaItem && areaItem.ID || null;
        CLASS_BOOK.initData(libID, curArea.ID);
    }
    sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged);

    // 新增
    async function insert() {
        const data = {
            compilationID,
            ID: uuid.v1(),
            name: '',
        };
        try {
            $.bootstrapLoading.start();
            await ajaxPost('/priceInfo/insertArea', { insertData: [data] });
            // 新增的数据总是添加在最后
            sheet.addRows(cache.length, 1);
            cache.push(data);
            const lastRow = cache.length - 1;
            sheet.setSelection(lastRow, 0, 1, 1);
            sheet.showRow(lastRow, GC.Spread.Sheets.VerticalPosition.top);
            handleSelectionChanged(lastRow);
        } catch (err) {
            alert(err);
        } finally {
            $.bootstrapLoading.end();
        }
    }

    // 删除
    async function del() {
        try {
            $.bootstrapLoading.start();
            await ajaxPost('/priceInfo/deleteArea', { deleteData: [curArea.ID] });
            const index = cache.findIndex(item => item.ID === curArea.ID);
            sheet.deleteRows(index, 1);
            cache.splice(index, 1);
            const row = sheet.getActiveRowIndex();
            handleSelectionChanged(row);
        } catch (err) {
            alert(err);
        } finally {
            $.bootstrapLoading.end();
        }
    }

    // 右键功能
    function buildContextMenu() {
        $.contextMenu({
            selector: '#area-spread',
            build: function ($triggerElement, e) {
                // 控制允许右键菜单在哪个位置出现
                const offset = $('#area-spread').offset();
                const x = e.pageX - offset.left;
                const y = e.pageY - offset.top;
                const target = sheet.hitTest(x, y);
                if (target.hitTestType === 3) { // 在表格内
                    const sel = sheet.getSelections()[0];
                    if (sel && sel.rowCount === 1 && typeof target.row !== 'undefined') {
                        const orgRow = sheet.getActiveRowIndex();
                        if (orgRow !== target.row) {
                            sheet.setActiveCell(target.row, target.col);
                            handleSelectionChanged(target.row);
                        }
                    }
                    return {
                        items: {
                            insert: {
                                name: '新增',
                                icon: "fa-arrow-left",
                                disabled: function () {
                                    return locked;
                                },
                                callback: function (key, opt) {
                                    insert();
                                }
                            },
                            del: {
                                name: '删除',
                                icon: "fa-arrow-left",
                                disabled: function () {
                                    return locked || !cache[target.row];
                                },
                                callback: function (key, opt) {
                                    del();
                                }
                            },
                        }
                    };
                }
                else {
                    return false;
                }
            }
        });
    }
    buildContextMenu();

    return {
        handleSelectionChanged,
        curArea,
    }

})();

// 分类表
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');

    // 插入
    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) {
        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);

    return {
        initData,
        handleSelectionChanged,
        curClass,
    }

})();

// 价格信息表
const PRICE_BOOK = (() => {
    const setting = {
        header: [
            { headerName: '编码', headerWidth: 100, dataCode: 'code', dataType: 'String', hAlign: 'left', vAlign: 'center' ,formatter: "@"},
            { headerName: '名称', headerWidth: 200, dataCode: 'name', dataType: 'String', hAlign: 'left', vAlign: 'center' },
            { headerName: '规格型号', headerWidth: 120, dataCode: 'specs', dataType: 'String', hAlign: 'left', vAlign: 'center' },
            { headerName: '单位', headerWidth: 80, dataCode: 'unit', dataType: 'String', hAlign: 'center', vAlign: 'center' },
            { headerName: '不含税价', headerWidth: 80, dataCode: 'noTaxPrice', dataType: 'String', hAlign: 'right', vAlign: 'center' },
            { headerName: '含税价', headerWidth: 80, dataCode: 'taxPrice', dataType: 'String', hAlign: 'right', vAlign: 'center' },
        ],
    };
    // 初始化表格
    const workBook = initSheet($('#price-spread')[0], setting);
    workBook.options.allowUserDragDrop = true;
    workBook.options.allowUserDragFill = true;
    lockUtil.lockSpreads([workBook], locked);
    const sheet = workBook.getSheet(0);

    let cache = [];
    // 清空
    function clear() {
        cache = [];
        sheet.setRowCount(0);
    }
    // 初始化数据
    async function initData(classIDList) {
        if (!classIDList || !classIDList.length) {
            return clear();
        }
        $.bootstrapLoading.start();
        try {
            cache = await ajaxPost('/priceInfo/getPriceData', { classIDList }, TIME_OUT);
            showData(sheet, cache, setting.header, 5);
        } catch (err) {
            cache = [];
            sheet.setRowCount(0);
            alert(err);
        } finally {
            $.bootstrapLoading.end();
        }
    }

    // 获取当前表中行数据
    function getRowData(sheet, row, headers) {
        const item = {};
        headers.forEach(({ dataCode }, index) => {
            const value = sheet.getValue(row, index) || '';
            if (value) {
                item[dataCode] = value;
            }
        });
        return item;
    }

    // 获取表数据和缓存数据的不同数据
    function getRowDiffData(curRowData, cacheRowData, headers) {
        let item = null;
        headers.forEach(({ dataCode }) => {
            const curValue = curRowData[dataCode];
            const cacheValue = cacheRowData[dataCode];
            if (!cacheValue && !curValue) {
                return;
            }
            if (cacheValue !== curValue) {
                if (!item) {
                    item = {};
                }
                item[dataCode] = curValue || '';
            }
        });
        return item;
    }

    // 编辑处理
    async function handleEdit(changedCells) {
        const postData = []; // 请求用
        // 更新缓存用
        const updateData = [];
        const deleteData = [];
        const insertData = [];
        try {
            changedCells.forEach(({ row }) => {
                if (cache[row]) {
                    const rowData = getRowData(sheet, row, setting.header);
                    if (Object.keys(rowData).length) { // 还有数据，更新
                        const diffData = getRowDiffData(rowData, cache[row], setting.header);
                        if (diffData) {
                            postData.push({ type: UpdateType.UPDATE, ID: cache[row].ID, data: diffData });
                            updateData.push({ row, data: diffData });
                        }
                    } else { // 该行无数据了，删除
                        postData.push({ type: UpdateType.DELETE, ID: cache[row].ID });
                        deleteData.push(cache[row]);
                    }
                } else { // 新增
                    const rowData = getRowData(sheet, row, setting.header);
                    if (Object.keys(rowData).length) {
                        rowData.ID = uuid.v1();
                        rowData.libID = libID;
                        rowData.compilationID = compilationID;
                        rowData.areaID = AREA_BOOK.curArea.ID;
                        rowData.classID = CLASS_BOOK.curClass.ID;
                        rowData.period = curLibPeriod;
                        postData.push({ type: UpdateType.CREATE, data: rowData });
                        insertData.push(rowData);
                    }
                }
            });
            if (postData.length) {
                await ajaxPost('/priceInfo/editPriceData', { postData }, TIME_OUT);
                // 更新缓存，先更新然后删除，最后再新增，防止先新增后缓存数据的下标与更新、删除数据的下标对应不上
                updateData.forEach(item => {
                    Object.assign(cache[item.row], item.data);
                });
                deleteData.forEach(item => {
                    const index = cache.indexOf(item);
                    if (index >= 0) {
                        cache.splice(index, 1);
                    }
                });
                insertData.forEach(item => cache.push(item));
                if (deleteData.length || insertData.length) {
                    showData(sheet, cache, setting.header, 5);
                }
            }
        } catch (err) {
            // 恢复各单元格数据
            showData(sheet, cache, setting.header, 5);
        }
    }
    sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) {
        const changedCells = [{ row: info.row }];
        handleEdit(changedCells);
    });
    sheet.bind(GC.Spread.Sheets.Events.RangeChanged, function (e, info) {
        const changedRows = [];
        let preRow;
        info.changedCells.forEach(({ row }) => {
            if (row !== preRow) {
                changedRows.push({ row });
            }
            preRow = row;
        });
        handleEdit(changedRows);
    });

    return {
        clear,
        initData,
    }
})();

$(document).ready(() => {
    $('[data-toggle="tooltip"]').tooltip();
    AREA_BOOK.handleSelectionChanged(0);
    const $range = $(document.body);
    lockUtil.lockTools($range, locked);
});