'use strict';

/**
 *
 *
 * @author Mai
 * @date 2018/6/20
 * @version
 */

const moment = require('moment');
const auditConst = require('../const/audit');
const spreadConst = require('../const/spread');
const tenderConst = require('../const/tender');
const measureType = tenderConst.measureType;
const path = require('path');

module.exports = app => {
    class StageController extends app.BaseController {
        /**
         * 构造函数
         *
         * @param {Object} ctx - egg全局变量
         * @return {void}
         */
        constructor(ctx) {
            super(ctx);
            ctx.showProject = true;
            ctx.showTender = true;
            ctx.showTitle = true;
        }

        /**
         * 获取通用的renderData（用于layout, Menu, subMenu部分）
         * @param ctx
         * @returns {{tender, tenderMenu, auditConst}}
         * @private
         */
        _getDefaultRenderData (ctx) {
            const data = {
                tender: ctx.tender.data,
                tenderMenu: JSON.parse(JSON.stringify(this.menu.stageMenu)),
                auditConst: auditConst.flow,
                measureType,
                preUrl: '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order,
                stage: ctx.stage,
            };
            data.tenderMenu.back.children[0].url = '/tender/' + ctx.tender.id + '/measure/stage';
            return data;
        }

        _stageReadOnly(stage) {
            return stage.status === auditConst.flow.status.checked;
        }

        /**
         * 获取SpreadSetting
         * @private
         */
        _getSpreadSetting() {
            const _ = this.app._;
            function removeFieldCols(setting, cols) {
                _.remove(setting.cols, function (c) {
                    return cols.indexOf(c.field) > -1;
                });
            }
            function setColFormat(cols, field, formatter) {
                const filterCols = cols.filter(function (c) {
                    return c.field.search(field) !== -1;
                });
                for (const col of filterCols) {
                    col.formatter = formatter;
                }
            }
            const tpFormatter = this.ctx.helper.getNumberFormatter(this.ctx.tender.info.decimal.tp);
            const upFormatter = this.ctx.helper.getNumberFormatter(2);
            const ledger = JSON.parse(JSON.stringify(spreadConst.stage.ledger));
            setColFormat(ledger.cols, 'unit_price', upFormatter);
            setColFormat(ledger.cols, 'total_price', tpFormatter);
            setColFormat(ledger.cols, 'tp', tpFormatter);
            const pos = JSON.parse(JSON.stringify(spreadConst.stage.pos));
            const tender = this.ctx.tender, stage = this.ctx.stage;
            if (this._stageReadOnly(stage)) {
                ledger.readOnly = true;
                pos.readOnly = true;
            }
            if (tender.data.measure_type === measureType.tz.value) {
                removeFieldCols(ledger, spreadConst.filterCols.tzWithoutCols);
                removeFieldCols(pos, spreadConst.filterCols.posTzWithoutCols);
            }
            if (!tender.info.display.ledger.dgnQty) {
                removeFieldCols(ledger, spreadConst.filterCols.dgnCols);
            }
            return [ledger, pos];
        }

        /**
         * 获取期数据
         * @param ctx
         * @returns {Promise<void>}
         * @private
         */
        async _getStage(ctx) {
            const stageOrder = parseInt(ctx.params.order);
            ctx.stage = await ctx.service.stage.getDataByCondition({
                tid: ctx.tender.id,
                order: stageOrder,
            });
            ctx.stage.auditors = await ctx.service.stageAudit.getAuditors(ctx.stage.id, ctx.stage.times);
            ctx.stage.curAuditor = await ctx.service.stageAudit.getCurAuditor(ctx.stage.id, ctx.stage.times);
        }

        /**
         * 期计量页面 (Get)
         * @param {Object} ctx - egg全局变量
         * @returns {Promise<void>}
         */
        async index(ctx) {
            try {
                await this._getStage(ctx);
                const renderData = this._getDefaultRenderData(ctx);
                [renderData.ledgerSpread, renderData.posSpread] = this._getSpreadSetting();
                renderData.ledgerData = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1);
                renderData.curStageData = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, 0);
                renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.index);
                // 查询截止上期数据
                //if (ctx.stage.order > 0) {
                    //renderData.preStageData
                //}
                await this.layout('stage/index.ejs', renderData, 'stage/modal.ejs');
            } catch (err) {
                this.log(err);
                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage');
            }
        }

        /**
         * 获取期数据(截止上期 & 本期)
         * @param ctx
         * @returns {Promise<void>}
         */
        async getStagePosData(ctx) {
            try {
                await this._getStage(ctx);
                const condition = JSON.parse(ctx.request.body.data) || {};
                condition.tid = ctx.tender.id;
                const responseData = {err: 0, msg: '', data: {}};
                responseData.data.pos = await ctx.service.pos.getPosData(condition);
                // todo 根据当前人，或指定对象查询数据
                responseData.data.curStageData = await ctx.service.stagePos.getAuditorStageData(ctx.tender.id,
                    ctx.stage.id, ctx.stage.times, ctx.stage.curAuditor ? ctx.stage.curAuditor.order : 0,
                    this.app._.map(responseData.data.pos, 'id'));
                ctx.body = responseData;
            } catch (err) {
                this.log(err);
                ctx.body = {err: 1, msg: err.toString(), data: null};
            }
        }

        /**
         * 保存数据
         * @param ctx
         * @returns {Promise<void>}
         */
        async updateStageData(ctx) {
            try {
                await this._getStage(ctx);
                // 检查登录用户，是否可操作
                if (ctx.session.sessionUser.accountId === ctx.stage.user_id) {
                    if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) {
                        throw '该计量期当前您无权操作';
                    }
                } else {
                    // 检查是否可修改
                    //const curAuditor = await ctx.service.stageAudit.get
                }

                const data = JSON.parse(ctx.request.body.data);
                const responseData = { err: 0, msg: '', data: {}, };
                if (data.pos) {
                    responseData.data = await ctx.service.stagePos.updateStageData(data.pos);
                } else if (data.bills) {
                    responseData.data.bills = await ctx.service.stageBills.updateStageData(data.bills);
                }
                ctx.body = responseData;
            } catch (err) {
                this.log(err);
                ctx.body = {err: 1, msg: err.toString(), data: null};
            }
        }

        /**
         * 中间计量
         * @param ctx
         * @returns {Promise<void>}
         */
        async detail(ctx) {
            try {
                await this._getStage(ctx);
                const renderData = this._getDefaultRenderData(ctx);
                renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.detail);
                renderData.imType = tenderConst.imType;
                await this.layout('stage/detail.ejs', renderData, 'stage/detail_modal.ejs');
            } catch (err) {
                this.log(err);
                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order);
            }
        }

        /**
         * 设置中间计量生成规则，并生成中间计量数据
         * @param ctx
         * @returns {Promise<void>}
         */
        async buildDetailData (ctx) {
            try {
                await this._getStage(ctx);
                // 检查登录用户，是否可操作
                if (ctx.session.sessionUser.accountId === ctx.stage.user_id) {
                    if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) {
                        throw '该计量期当前您无权操作';
                    }
                }

                const data = JSON.parse(ctx.request.body.data);
                await ctx.service.stage.buildDetailData(ctx.tender.id, ctx.stage.order, data);

                ctx.body = {err: 0, msg: '', data: null};
            } catch (err) {
                this.log(err);
                ctx.body = {err: 1, msg: err.toString(), data: null};
            }
        }

        /**
         * 加载数据
         * @param ctx
         * @returns {Promise<void>}
         */
        async loadDetailRelaData(ctx) {
            try {
                await this._getStage(ctx);
                const data = JSON.parse(ctx.request.body.data);
                // 加载台账数据
                if (data.loadType === 'ledger') {
                    const ledgerData = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1);
                    ctx.body = {err: 0, msg: '', data: ledgerData };
                } else if (data.loadType === 'all') {
                    const ledger = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1);
                    const curStage = await ctx.service.stageBills.getLastestStageData(ctx.tender.id, ctx.stage.id);
                    const stageDetail = await ctx.service.stageDetail.getLastestStageData(ctx.tender.id, ctx.stage.id);
                    ctx.body = {
                        err: 0,
                        msg: '',
                        data: {
                            ledger,
                            curStage,
                            stageDetail,
                        }
                    };
                }
            } catch (err) {
                this.log(err);
                ctx.body = {err: 1, msg: err.toString(), data: null};
            }
        }

        /**
         * 中间计量，生成规则，高级设置
         * @param ctx
         * @returns {Promise<void>}
         */
        async setAdvancedConfig(ctx) {
            try {
                await this._getStage(ctx);
                // 检查登录用户，是否可操作
                if (ctx.session.sessionUser.accountId === ctx.stage.user_id) {
                    if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) {
                        throw '该计量期当前您无权操作';
                    }
                }

                const data = JSON.parse(ctx.request.body.data);
                await ctx.service.stage.update(data, { id: ctx.stage.id });

                ctx.body = {err: 0, msg: '', data: this.ctx.stage};
            } catch (err) {
                this.log(err);
                ctx.body = {err: 1, msg: err.toString(), data: null};
            }
        }

        /**
         * 中间计量，编辑中间计量数据
         * @param ctx
         * @returns {Promise<void>}
         */
        async saveDetailData(ctx) {
            try {
                await this._getStage(ctx);
                // 检查登录用户，是否可操作
                if (ctx.session.sessionUser.accountId === ctx.stage.user_id) {
                    if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) {
                        throw '该计量期当前您无权操作';
                    }
                } else {
                    // 检查是否可修改
                    //const curAuditor = await ctx.service.stageAudit.get
                }

                const data = JSON.parse(ctx.request.body.data);
                const responseData = { err: 0, msg: '', data: {}, };
                responseData.data = await ctx.service.stageDetail.saveDetailData(data);
                ctx.body = responseData;
            } catch (err) {
                this.log(err);
                ctx.body = {err: 1, msg: err.toString(), data: null};
            }
        }

        /**
         * 中间计量，添加草图，上传图片
         * @param ctx
         * @returns {Promise<void>}
         */
        async addCalcImage(ctx) {
            try {
                const stream = await ctx.getFileStream();
                const create_time = Date.parse(new Date()) / 1000;
                const fileInfo = path.parse(stream.filename);
                const fileName = path.join('public/upload', this.ctx.tender.id.toString(), 'im', 'calcImg_' + create_time + fileInfo.ext);
                await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, 'app', fileName));
                ctx.body = {err: 0, msg: '', data: fileName};
            } catch(err) {
                this.log(err);
                ctx.body = {err: 1, msg: err.toString(), data: null};
            }
        }

        /**
         * 中间计量，设置草图
         * @param ctx
         * @returns {Promise<void>}
         */
        async mergeCalcImage(ctx) {
            try {
                await this._getStage(ctx);
                // 检查登录用户，是否可操作
                if (ctx.session.sessionUser.accountId === ctx.stage.user_id) {
                    if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) {
                        throw '该计量期当前您无权操作';
                    }
                } else {
                    // 检查是否可修改
                    //const curAuditor = await ctx.service.stageAudit.get
                }
                const data = JSON.parse(ctx.request.body.data);

                if (data.updateType === 'update') {
                    const create_time = Date.parse(new Date()) / 1000;
                    const fileName = path.join('public/upload', this.ctx.tender.id.toString(), 'im', 'calcImg_' + create_time + '.jpg');
                    const base64Data = data.img.replace(/^data:image\/\w+;base64,/, "");
                    const dataBuffer = new Buffer(base64Data, 'base64');
                    await this.ctx.helper.saveBufferFile(dataBuffer, path.join(this.app.baseDir, 'app', fileName));
                    data.calc_img = fileName;
                    data.calc_img_org = JSON.stringify(data.imgInfo);
                    delete data.updateType;
                    delete data.img;
                    delete data.imgInfo;
                } else if (data.updateType === 'clear') {
                    data.calc_img = null;
                    data.calc_img_org = null;
                    delete data.updateType;
                }
                await this.ctx.service.stageDetail.saveDetailData(data);
                const imData = await ctx.service.stageDetail.getLastestImStageData(this.ctx.tender.id, this.ctx.stage.id, data.lid, data.uuid);
                const responseData = {err: 0, msg: '', data: imData};
                ctx.body = responseData;
            } catch (err) {
                this.log(err);
                ctx.body = {err: 1, msg: err.toString(), data: null};
            }
        }

        /**
         * 合同支付
         * @param ctx
         * @returns {Promise<void>}
         */
        async pay(ctx) {
            try {
                await this._getStage(ctx);
                const renderData = this._getDefaultRenderData(ctx);
                await this.layout('stage/pay.ejs', renderData, 'stage/pay_modal.ejs');
            } catch (err) {
                this.log(err);
                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage');
            }
        }

        /**
         * 变更令
         * @param ctx
         * @returns {Promise<void>}
         */
        async change(ctx) {
            try {
                await this._getStage(ctx);
                const renderData = this._getDefaultRenderData(ctx);
                await this.layout('stage/change.ejs', renderData);
            } catch (err) {
                this.log(err);
                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage');
            }
        }

        // 审批相关
        /**
         * 添加审批人
         * @param ctx
         * @returns {Promise<void>}
         */
        async addAudit(ctx) {
            try {
                await this._getStage(ctx);
                const data = JSON.parse(ctx.request.body.data);
                const id = data.auditorId;
                if (isNaN(id) || id <= 0) {
                    throw '参数错误';
                }

                const result = await ctx.service.stageAudit.addAuditor(ctx.stage.id, id);
                if (!result) {
                    throw '添加审核人失败';
                }

                const audit = await ctx.service.stageAudit.getAuditor(ctx.stage.id, id);
                ctx.body = {err: 0, msg: '', data: audit};
            } catch (err) {
                this.log(err);
                ctx.body = {err: 1, msg: err.toString(), data: null};
            }
        }
        /**
         * 移除审批人
         * @param ctx
         * @returns {Promise<void>}
         */
        async deleteAudit(ctx) {
            try {
                await this._getStage(ctx);
                const data = JSON.parse(ctx.request.body.data);
                const id = data.auditorId instanceof Number ? data.auditorId : this.app._.toNumber(data.auditorId);
                if (isNaN(id) || id <= 0) {
                    throw '参数错误';
                }

                const result = await ctx.service.stageAudit.deleteAuditor(ctx.stage.id, id, ctx.stage.times);
                if (!result) {
                    throw '移除审核人失败';
                }

                const auditors = await ctx.service.stageAudit.getAuditors(ctx.stage.id);
                ctx.body = {err: 0, msg: '', data: auditors};
            } catch (err) {
                ctx.body = {err: 1, msg: err.toString(), data: null};
            }
        }
        /**
         * 上报
         * @param ctx
         * @returns {Promise<void>}
         */
        async startAudit(ctx) {

        }
        /**
         * 审批
         * @param ctx
         * @returns {Promise<void>}
         */
        async checkAudit(ctx) {

        }

        _getGatherSpreadSetting() {
            const _ = this.app._;
            function removeFieldCols(setting, cols) {
                _.remove(setting.cols, function (c) {
                    return cols.indexOf(c.field) > -1;
                });
            }
            function setColFormat(cols, field, formatter) {
                const filterCols = cols.filter(function (c) {
                    return c.field.search(field) !== -1;
                });
                for (const col of filterCols) {
                    col.formatter = formatter;
                }
            }
            const tpFormatter = this.ctx.helper.getNumberFormatter(this.ctx.tender.info.decimal.tp);
            const upFormatter = this.ctx.helper.getNumberFormatter(2);
            const gcl = JSON.parse(JSON.stringify(spreadConst.stageGather.gcl));
            setColFormat(gcl.cols, 'unit_price', upFormatter);
            setColFormat(gcl.cols, 'total_price', tpFormatter);
            setColFormat(gcl.cols, 'tp', tpFormatter);

            const leafXmj = JSON.parse(JSON.stringify(spreadConst.stageGather.leafXmj));
            const tender = this.ctx.tender;
            if (tender.data.measure_type === measureType.tz.value) {
                removeFieldCols(gcl, spreadConst.filterCols.tzWithoutCols);
            }
            return [gcl, leafXmj];
        }

        /**
         * 清单汇总
         * @param ctx
         * @returns {Promise<void>}
         */
        async gather(ctx) {
            try {
                await this._getStage(ctx);
                const renderData = this._getDefaultRenderData(ctx);
                [renderData.gclSpread, renderData.leafXmjSpread] = this._getGatherSpreadSetting();
                renderData.ledger = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1);
                renderData.curLedgerData = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, 0);

                renderData.pos = await ctx.service.pos.getPosData({tid: ctx.tender.id});
                // todo 根据当前人，或指定对象查询数据
                renderData.curPosData = await ctx.service.stagePos.getAuditorStageData(ctx.tender.id,
                    ctx.stage.id, ctx.stage.times, ctx.stage.curAuditor ? ctx.stage.curAuditor.order : 0);
                //renderData.gcl = await this.ctx.service.ledger.getAllLeafGclBills(this.ctx.tender.id);

                renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.gather);
                await this.layout('stage/gather.ejs', renderData);
            } catch (err) {
                this.log(err);
                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order);
            }
        }

        /**
         * 审核比较
         * @param ctx
         * @returns {Promise<void>}
         */
        async compare(ctx) {
            function getCompareSpreadSetting () {
                function setColFormat(cols, field, formatter) {
                    const filterCols = cols.filter(function (c) {
                        return c.field.search(field) !== -1;
                    });
                    for (const col of filterCols) {
                        col.formatter = formatter;
                    }
                }
                const tpFormatter = ctx.helper.getNumberFormatter(ctx.tender.info.decimal.tp);
                const upFormatter = ctx.helper.getNumberFormatter(2);
                const ledger = JSON.parse(JSON.stringify(spreadConst.stageCompare.ledger));
                setColFormat(ledger.baseCols, 'unit_price', upFormatter);
                setColFormat(ledger.extraCols, 'total_price', tpFormatter);
                setColFormat(ledger.extraCols, 'tp', tpFormatter);

                const pos = JSON.parse(JSON.stringify(spreadConst.stageCompare.pos));
                return [ledger, pos];
            };
            try {
                await this._getStage(ctx);
                const renderData = this._getDefaultRenderData(ctx);
                [renderData.ledgerSpread, renderData.posSpread] = getCompareSpreadSetting();
                renderData.ledger = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1);
                renderData.orgStageLedger = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, 0);
                renderData.pos = await ctx.service.pos.getPosData({tid: ctx.tender.id});
                renderData.orgStagePos = await ctx.service.stagePos.getAuditorStageData(ctx.tender.id,
                    ctx.stage.id, ctx.stage.times, ctx.stage.curAuditor ? ctx.stage.curAuditor.order : 0);
                renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.compare);
                await this.layout('stage/compare.ejs', renderData, 'stage/compare_modal.ejs');
            } catch (err) {
                this.log(err);
                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order);
            }
        }

        async compareAuditor(ctx) {
            try {
                await this._getStage(ctx);
                const data = JSON.parse(ctx.request.body.data);
                const result = [];
                for (const order of data.auditors) {
                    const data = { order: order, bills: [], pos: [] };
                    data.bills = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, order);
                    data.pos = await ctx.service.stagePos.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, order);
                    result.push(data);
                }
                ctx.body = {err: 0, msg: '', data: result};
            } catch (err) {
                this.log(err);
                ctx.body = {err: 1, msg: err.toString(), data: null};
            }
        }

        /**
         * 报表
         * @param ctx
         * @returns {Promise<void>}
         */
        async report(ctx) {
            try {
                await this._getStage(ctx);
                const renderData = this._getDefaultRenderData(ctx);
                await this.layout('stage/report.ejs', renderData, 'stage/report_modal.ejs');
            } catch (err) {
                this.log(err);
                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage');
            }
        }
    }

    return StageController;
};