'use strict';

/**
 *
 *
 * @author Mai
 * @date 2019/2/27
 * @version
 */

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

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

        /**
         * 获取 审核人信息
         *
         * @param {Number} stageId - 期id
         * @param {Number} auditorId - 审核人id
         * @param {Number} times - 第几次审批
         * @returns {Promise<*>}
         */
        async getAuditor(stageId, auditorId, times = 1) {
            const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
                'FROM ?? AS la, ?? AS pa ' +
                'WHERE la.`sid` = ? and la.`aid` = ? and la.`times` = ?' +
                '    and la.`aid` = pa.`id`';
            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditorId, times];
            return await this.db.queryOne(sql, sqlParam);
        }

        /**
         * 获取 审核列表信息
         *
         * @param {Number} stageId - 期id
         * @param {Number} times - 第几次审批
         * @returns {Promise<*>}
         */
        async getAuditors(stageId, times = 1) {
            const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
                'FROM ?? AS la, ?? AS pa ' +
                'WHERE la.`sid` = ? and la.`times` = ? and la.`aid` = pa.`id`';
            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, times];
            return await this.db.query(sql, sqlParam);
        }

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

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

        /**
         * 新增审核人
         *
         * @param {Number} stageId - 期id
         * @param {Number} auditorId - 审核人id
         * @param {Number} times - 第几次审批
         * @returns {Promise<number>}
         */
        async addAuditor(stageId, auditorId, times = 1) {
            const newOrder = await this.getNewOrder(stageId, times);
            const data = {
                tid: this.ctx.tender.id,
                sid: stageId,
                aid: 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 {Number} stageId - 标段id
         * @param {Number} auditorId - 审核人id
         * @param {Number} times - 第几次审批
         * @returns {Promise<*>}
         * @private
         */
        async _syncOrderByDelete(transaction, stageId, order, times) {
            this.initSqlBuilder();
            this.sqlBuilder.setAndWhere('sid', {
                value: stageId,
                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 {Number} stageId - 期id
         * @param {Number} auditorId - 审核人id
         * @param {Number} times - 第几次审批
         * @returns {Promise<boolean>}
         */
        async deleteAuditor(stageId, auditorId, times = 1) {
            console.log('delete-1');
            const transaction = await this.db.beginTransaction();
            try {
                const condition = {sid: stageId, aid: auditorId, times: times};
                const auditor = await this.getDataByCondition(condition);
                if (!auditor) {
                    throw '该审核人不存在';
                }
                await this._syncOrderByDelete(transaction, stageId, auditor.order, times);
                await transaction.delete(this.tableName, condition);
                await transaction.commit();
            } catch(err) {
                await transaction.rollback();
                throw err;
            }
            return true;
        }

        /**
         * 开始审批
         *
         * @param {Number} stageId - 期id
         * @param {Number} times - 第几次审批
         * @returns {Promise<boolean>}
         */
        async start(stageId, times = 1) {
            const audit = await this.getDataByCondition({sid: stageId, times: times, order: 1});
            if (!audit) {
                throw '审核人信息错误';
            }

            const transaction = await this.db.beginTransaction();
            try {
                await transaction.update(this.tableName, {id: audit.id, status: auditConst.status.checking, begin_time: new Date()});
                await transaction.update(this.ctx.service.stage.tableName, {id: stageId, status: auditConst.status.checking});
                // todo 更新标段stage状态
                //await transaction.update(this.ctx.service.stage.tableName, {id: stageId, status: auditConst.status.checking});
                await transaction.commit();
            } catch(err) {
                await transaction.rollback();
                throw err;
            }
            return true;
        }

        /**
         * 审批
         * @param {Number} stageId - 标段id
         * @param {auditConst.status.checked|auditConst.status.checkNo} checkType - 审批结果
         * @param {Number} times - 第几次审批
         * @returns {Promise<void>}
         */
        async check(stageId, 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({sid: stageId, times: times, status: auditConst.status.checking});
                if (!audit) {
                    throw '审核数据错误';
                }
                // 更新当前审核流程
                await transaction.update(this.tableName, {id: audit.id, status: checkType, opinion: opinion, end_time: time});
                if (checkType === auditConst.status.checked) {
                    const nextAudit = await this.getDataByCondition({sid: stageId, times: times, order: audit.order + 1});
                    // 无下一审核人表示，审核结束
                    if (nextAudit) {
                        await transaction.update(this.tableName, {id: nextAudit.id, status: auditConst.status.checking, begin_time: time});
                    } else {
                        // 同步 期信息
                        await transaction.update(this.ctx.service.stage.tableName, {id: stageId, status: checkType});
                    }
                } else {
                    // 同步 期信息
                    await transaction.update(this.ctx.service.stage.tableName, {id: stageId, times: times+1, status: checkType});
                    // 拷贝新一次审核流程列表
                    const auditors = await this.getAllDataByCondition({
                        where: {sid: stageId, times: times},
                        columns: ['tid', 'sid', 'aid', 'order']
                    });
                    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 getAuditStage(auditorId) {
            const sql = 'SELECT la.`aid`, la.`times`, la.`order`, la.`begin_time`, la.`tid`, la.`sid`, s.`order`, t.`name`, t.`project_id`, t.`type`, t.`user_id` ' +
                'FROM ?? AS la, ?? AS s, ?? As t ' +
                'WHERE la.`aid` = ? and la.`status` = ?' +
                '    and la.`sid` = s.`id` and la.`tid` = t.`id`';
            const sqlParam = [this.tableName, this.ctx.service.stage.tableName, this.ctx.service.tender.tableName, auditorId, auditConst.status.checking];
            return await this.db.query(sql, sqlParam);
        }
    }

    return StageAudit;
};