'use strict';

/**
 * 台账审批流程表
 *
 * @author Mai
 * @date 2018/5/25
 * @version
 */

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

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

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

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

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

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

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

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

            return data;
        }

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

        /**
         * 开始审批
         *
         * @param {Number} tenderId - 标段id
         * @param {Number} times - 第几次审批
         * @returns {Promise<boolean>}
         */
        async start(tenderId, times = 1) {
            const audit = await this.getDataByCondition({tender_id: tenderId, times: times, audit_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.tender.tableName, {id: tenderId, ledger_status: auditConst.status.checking});
                await transaction.commit();
            } catch(err) {
                await transaction.rollback();
                throw err;
            }
            return true;
        }

        /**
         * 拷贝一份台账备份(每一次审批结束时)
         * @param {Number} tenderId - 标段Id
         * @param transaction - 事务
         * @param {Number} times - 次数
         * @returns {Promise<void>}
         * @private
         */
        async _copyHisytoryLedger(tenderId, transaction, times = 1) {
            const sql = 'Insert Into ?? ' +
                'Select *, ? As times From ?? ' +
                'Where ?? = ?';
            const sqlParam = [this.tableName + '_copy', times, this.ctx.service.ledger.tableName, 'tender_id', tenderId];
            return await transaction.query(sql, sqlParam);
        }

        /**
         * 审批
         * @param {Number} tenderId - 标段id
         * @param {auditConst.status.checked|auditConst.status.checkNo} checkType - 审批结果
         * @param {Number} times - 第几次审批
         * @returns {Promise<void>}
         */
        async check(tenderId, 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({tender_id: tenderId, 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({tender_id: tenderId, times: times, audit_order: audit.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.tender.tableName, {id: tenderId, ledger_status: checkType});
                        // 拷贝备份台账数据
                        await this._copyHisytoryLedger(tenderId, times);
                    }
                } else {
                    // 同步标段信息
                    await transaction.update(this.ctx.service.tender.tableName, {id: tenderId, ledger_times: times+1, ledger_status: checkType});
                    // 拷贝新一次审核流程列表
                    const auditors = await this.getAllDataByCondition({
                        where: {tender_id: tenderId, times: times},
                        columns: ['tender_id', 'audit_order', 'audit_id']
                    });
                    for (const a of auditors) {
                        a.times = times + 1;
                        a.status = auditConst.status.uncheck;
                    }
                    await transaction.insert(this.tableName, auditors);
                    // 拷贝备份台账数据
                    await this._copyHisytoryLedger(tenderId, times);
                }

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

        /**
         * 获取审核人需要审核的标段列表
         *
         * @param auditorId
         * @returns {Promise<*>}
         */
        async getAuditTender(auditorId) {
            const sql = 'SELECT la.`audit_id`, la.`times`, la.`audit_order`, la.`begin_time`, t.`id`, t.`name`, t.`project_id`, t.`type`, t.`user_id` ' +
                'FROM ?? AS la, ?? AS t ' +
                'WHERE la.`audit_id` = ? and la.`status` = ?' +
                '    and la.`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 LedgerAudit;
};