'use strict';

/**
 *
 *
 * @author Mai
 * @date 2018/7/16
 * @version
 */

const auditConst = require('../const/audit').flow;

module.exports = app => {
    class MeasureAudit extends app.BaseService {
        /**
         * 构造函数
         *
         * @param {Object} ctx - egg全局变量
         * @return {void}
         */
        constructor(ctx) {
            super(ctx);
            this.tableName = 'measure_audit';
        }

        /**
         * 获取 中间计量 审核人信息
         *
         * @param {uuid} mid - 中间计量id
         * @param {Number} auditorId - 审核人id
         * @param {Number} times - 第几次审批
         * @returns {Promise<*>}
         */
        async getAuditor(mid, auditorId, times = 1) {
            const sql = 'SELECT ma.*, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone` ' +
                'FROM ?? AS ma, ?? AS pa ' +
                'WHERE ma.`mid` = ? and ma.`audit_id` = ? and ma.`times` = ?' +
                '    and ma.`audit_id` = pa.`id`';
            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, mid, auditorId, times];
            return await this.db.queryOne(sql, sqlParam);
        }

        /**
         * 获取 中间计量 审核人列表信息
         *
         * @param {uuid} mid - 中间计量id
         * @param {Number} times - 第几次审批
         * @returns {Promise<*>}
         */
        async getAuditors(mid, times = 1) {
            const sql = 'SELECT ma.*, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone` ' +
                'FROM ?? AS ma, ?? AS pa ' +
                'WHERE ma.`mid` = ? and ma.`times` = ?' +
                '    and ma.`audit_id` = pa.`id` and ma.`order` > 0';
            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, mid, times];
            return await this.db.query(sql, sqlParam);
        }

        /**
         * 获取 中间计量 当前审核人
         *
         * @param {uuid} mid - 中间计量id
         * @param {Number} times - 第几次审批
         * @returns {Promise<*>}
         */
        async getCurAuditor(mid, times = 1) {
            const sql = 'SELECT ma.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, ma.`times`, ma.`order`, ma.`status`, ma.`opinion`, ma.`begin_time`, ma.`end_time` ' +
                'FROM ?? AS ma, ?? AS pa ' +
                'WHERE ma.`mid` = ? and ma.`status` = ? and ma.`times` = ?' +
                '    and ma.`audit_id` = pa.`id`';
            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, mid, auditConst.status.checking, times];
            return await this.db.queryOne(sql, sqlParam);
        }

        /**
         * 获取 中间计量 最新审核顺序
         *
         * @param {uuid} mid - 中间计量id
         * @param {Number} times - 第几次审批
         * @returns {Promise<number>}
         */
        async getNewOrder(mid, times = 1) {
            const sql = 'SELECT Max(??) As max_order FROM ?? Where `mid` = ? and `times` = ? and `order` > 0';
            const sqlParam = ['order', this.tableName, mid, times];
            const result = await this.db.queryOne(sql, sqlParam);
            return result && result.max_order ? result.max_order + 1 : 1;
        }

        /**
         * 新增审核人
         *
         * @param {Number} tenderId - 标段id
         * @param {uuid} mid - 中间计量id
         * @param {Number} auditorId - 审核人id
         * @param {Number} times - 第几次审批
         * @returns {Promise<number>}
         */
        async addAuditor(tenderId, mid, auditorId, times = 1) {
            const newOrder = await this.getNewOrder(mid, times);
            const data = {
                tender_id: tenderId,
                mid: mid,
                audit_id: auditorId,
                times: times,
                order: newOrder,
                status: auditConst.status.uncheck,
            };
            const result = await this.db.insert(this.tableName, data);
            return result.effectRows = 1;
        }

        /**
         * 移除审核人时，同步其后审核人order
         * @param transaction - 事务
         * @param {uuid} mid - 中间计量id
         * @param {Number} auditorId - 审核人id
         * @param {Number} times - 第几次审批
         * @returns {Promise<*>}
         * @private
         */
        async _syncOrderByDelete(transaction, mid, order, times) {
            this.initSqlBuilder();
            this.sqlBuilder.setAndWhere('mid', {
                value: this.db.escape(mid),
                operate: '='
            });
            this.sqlBuilder.setAndWhere('order', {
                value: order,
                operate: '>=',
            });
            this.sqlBuilder.setAndWhere('times', {
                value: times,
                operate: '=',
            });
            this.sqlBuilder.setUpdateData('order', {
                value: 1,
                selfOperate: '-',
            });
            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
            const data = await transaction.query(sql, sqlParam);

            return data;
        }

        /**
         * 移除审核人
         *
         * @param {uuid} mid - 中间计量id
         * @param {Number} auditorId - 审核人id
         * @param {Number} times - 第几次审批
         * @returns {Promise<boolean>}
         */
        async deleteAuditor(mid, auditorId, times = 1) {
            const transaction = await this.db.beginTransaction();
            try {
                const condition = {mid: mid, audit_id: auditorId, times: times};
                const auditor = await this.getDataByCondition(condition);
                if (!auditor) {
                    throw '该审核人不存在';
                }
                await this._syncOrderByDelete(transaction, mid, auditor.order, times);
                await transaction.delete(this.tableName, condition);
                await transaction.commit();
            } catch(err) {
                await transaction.rollback();
                throw err;
            }
            return true;
        }

        _sumBills(bills) {
            const result = {deal: 0, qc: 0};
            for (const b of bills) {
                result.deal = result.deal + (b.deal_totalprice ? b.deal_totalprice : 0);
                result.qc = result.qc + (b.qc_totalprice ? b.qc_totalprice : 0);
            }
            return result;
        }
        /**
         * 拷贝原报的历史数据
         *
         * @param transacation - 事务
         * @param {uuid} mid - 中间计量
         * @param {Number} times - 次数
         * @returns {Promise<void>}
         * @private
         */
        async _copyReportBillsHistory(transacation, mid, times) {
            const bills = await this.ctx.service.measureBills.getAllDataByCondition({ where: {mid: mid}});
            const sum = this._sumBills(bills);
            const history = await this.getDataByCondition({mid: mid, times: times, order: 0});
            if (history) {
                await transacation.update(this.tableName, {
                    id: history.id,
                    bills: JSON.stringify(bills),
                    deal_sum: sum.deal,
                    qc_sum: sum.qc,
                });
            } else {
                const measure = await this.ctx.service.measure.getDataByCondition({mid: mid});
                await transacation.insert(this.tableName, {
                    tender_id: measure.tender_id,
                    mid: mid,
                    times: times,
                    order: 0,
                    audit_id: measure.user_id,
                    status: 0,
                    bills: JSON.stringify(bills),
                    deal_sum: sum.deal,
                    qc_sum: sum.qc,
                });
            }
            return sum;
        }
        /**
         * 开始审批
         *
         * @param {uuid} mid - 中间计量id
         * @param {Number} times - 第几次审批
         * @returns {Promise<boolean>}
         */
        async start(mid, times = 1) {
            const audit = await this.getDataByCondition({mid: mid, times: times, order: 1});
            if (!audit) {
                throw '审核人信息错误';
            }

            const transaction = await this.db.beginTransaction();
            try {
                // 记录历史数据
                const sum = await this._copyReportBillsHistory(transaction, mid, times);
                // 更新审核人状态
                await transaction.update(this.tableName, {
                    id: audit.id,
                    status: auditConst.status.checking,
                    begin_time: new Date(),
                });
                // 改变中间计量状态
                await transaction.update(this.ctx.service.measure.tableName, {
                    times: times,
                    status: auditConst.status.checking,
                    deal_sum: sum.deal,
                    qc_sum: sum.qc,
                }, {where: {mid: mid}});
                await transaction.commit();
            } catch(err) {
                await transaction.rollback();
                throw err;
            }
            return true;
        }

        /**
         * 审批
         * @param {uuid} mid - 中间计量id
         * @param {auditConst.status.checked|auditConst.status.checkNo} checkType - 审批结果
         * @param {Number} times - 第几次审批
         * @returns {Promise<void>}
         */
        async check(mid, checkType, opinion, times = 1) {
            if (checkType !== auditConst.status.checked && checkType !== auditConst.status.checkNo) {
                throw '提交数据错误';
            }

            const transaction = await this.db.beginTransaction();
            try {
                // 整理当前流程审核人状态更新
                const time = new Date();
                const audit = await this.getDataByCondition({mid: mid, times: times, status: auditConst.status.checking});
                if (!audit) {
                    throw '审核数据错误';
                }
                // 更新当前审核流程
                const bills = await this.ctx.service.measureBills.getAllDataByCondition({ where: {mid: mid}});
                const sum = this._sumBills(bills);
                await transaction.update(this.tableName, {
                    id: audit.id,
                    status: checkType,
                    opinion: opinion,
                    end_time: time,
                    bills: JSON.stringify(bills),
                    deal_sum: sum.deal,
                    qc_sum: sum.qc,
                });
                const measureTable = this.ctx.service.measure.tableName;
                if (checkType === auditConst.status.checked) {
                    const nextAudit = await this.getDataByCondition({mid: mid, times: times, order: audit.order + 1});
                    // 无下一审核人表示，审核结束
                    if (nextAudit) {
                        await transaction.update(this.tableName, {id: nextAudit.id, status: auditConst.status.checking, begin_time: time});
                        await transaction.update(measureTable, {deal_sum: sum.deal, qc_sum: sum.qc,}, {where: {mid: mid}});
                    } else {
                        // 同步标段信息
                        await transaction.update(measureTable, {status: checkType, deal_sum: sum.deal, qc_sum: sum.qc,}, {where: {mid: mid}});
                    }
                } else {
                    // 同步标段信息
                    await transaction.update(measureTable, {times: times+1, status: checkType, deal_sum: sum.deal, qc_sum: sum.qc,}, {where: {mid: mid}});
                    // 拷贝新一次审核流程列表
                    const auditors = await this.getAllDataByCondition({
                        where: {mid: mid, times: times},
                        columns: ['tender_id', 'order', 'audit_id', 'mid']
                    });
                    for (const a of auditors) {
                        a.times = times + 1;
                        a.status = auditConst.status.uncheck;
                    }
                    await transaction.insert(this.tableName, auditors);
                }

                await transaction.commit();
            } catch (err) {
                await transaction.rollback();
                throw err;
            }
        }

        /**
         * 获取审核人需要审核的标段列表
         *
         * @param auditorId
         * @returns {Promise<*>}
         */
        async getAuditTender(auditorId) {
            const sql = 'SELECT ma.`audit_id`, ma.`times`, ma.`order`, ma.`begin_time`, t.`id`, t.`name`, t.`project_id`, t.`type`, t.`user_id` ' +
                'FROM ?? AS ma, ?? AS t ' +
                'WHERE ma.`audit_id` = ? and ma.`status` = ?' +
                '    and ma.`tender_id` = t.`id`';
            const sqlParam = [this.tableName, this.ctx.service.tender.tableName, auditorId, auditConst.status.checking];
            return await this.db.query(sql, sqlParam);
        }
    }

    return MeasureAudit;
};