'use strict';

/**
 * 期计量 中间计量 详细数据
 *
 * @author Mai
 * @date 2019/2/13
 * @version
 */
const timesLen = require('../const/audit').stage.timesLen;

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

        /**
         * 查询最后审核人数据
         * @param {Number} tid - 标段id
         * @param {Number} sid - 期id
         * @param {Number|Array} lid - 台账节点id（可以为空）
         * @returns {Promise<*>}
         */
        async getLastestStageData(tid, sid, lid) {
            const lidSql = lid ? ' And Bills.lid in (?)' : '';
            const sql = 'SELECT * FROM ' + this.tableName + ' As Bills ' +
                '  INNER JOIN ( ' +
                '    SELECT MAX(`times` * ' + timesLen + ' + `order`) As `flow`, `lid`, `uuid` From ' + this.tableName +
                '      GROUP BY `lid`, `uuid`' +
                '  ) As MaxFilter ' +
                '  ON (Bills.times * ' + timesLen + ' + Bills.order) = MaxFilter.flow And Bills.lid = MaxFilter.lid And Bills.uuid = MaxFilter.uuid' +
                '  WHERE Bills.tid = ? And Bills.sid = ?' + lidSql;
            const sqlParam = [tid, sid];
            if (!lid) {
                return await this.db.query(sql, sqlParam);
            } else if (lid instanceof Array) {
                sqlParam.push(lid.join(', '));
                return await this.db.query(sql, sqlParam);
            } else {
                sqlParam.push(lid);
                return await this.db.queryOne(sql, sqlParam);
            }
        }

        /**
         * 查询 某期 某轮审批 某人数据
         * @param {Number} tid - 标段id
         * @param {Number} sid - 期id
         * @param {Number} times - 第几轮
         * @param {Number} order - 流程
         * @param {Number|Array} lid - 台账节点id（可以为空）
         * @returns {Promise<*>}
         */
        async getAuditorStageData(tid, sid, times, order, lid) {
            const lidSql = lid ? ' And Bills.lid in (?)' : '';
            const sql = 'SELECT * FROM ' + this.tableName + ' As Bills ' +
                '  INNER JOIN ( ' +
                '    SELECT MAX(`times` * ' + timesLen + ' + `order`) As `flow`, `lid`, `uuid` From ' + this.tableName +
                '      WHERE `tid` = ? And `sid` = ? And (`times` < ? OR (`times` = ? And `order` <= ?))' + lidSql +
                '      GROUP BY `lid`, `uuid`' +
                '  ) As MaxFilter ' +
                '  ON (Bills.times * ' + timesLen + ' + Bills.order) = MaxFilter.flow And Bills.lid = MaxFilter.lid And Bills.uuid = MaxFilter.uuid' +
                '  WHERE Bills.tid = ? And Bills.sid = ?' + lidSql;
            const sqlParam = [tid, sid, times, times, order, tid, sid];
            if (!lid) {
                return await this.db.query(sql, sqlParam);
            } else if (lid instanceof Array) {
                sqlParam.push(lid.join(', '));
                return await this.db.query(sql, sqlParam);
            } else {
                sqlParam.push(lid);
                return await this.db.queryOne(sql, sqlParam);
            }
        }

        /**
         * 获取 中间计量 用户最新输入数据
         * @param {Number} tid - 标段id
         * @param {Number} sid - 期id
         * @param {Number} lid - 关联的台账节点id
         * @param {String|Array[String]} uuid - 中间计量单 唯一id
         * @returns {Promise<*>}
         */
        async getLastestImStageData(tid, sid, lid, uuid) {
            if (uuid instanceof Array) {
                if (uuid.length === 0) { return []; }
                let uuidSql = '';
                for (const u of uuid) {
                    uuidSql = uuidSql === '' ? this.db.escape(u) : uuidSql + ',' + this.db.escape(u);
                }
                const sql = 'SELECT * FROM ' + this.tableName + ' As Bills ' +
                    '  INNER JOIN ( ' +
                    '    SELECT MAX(`times` * ' + timesLen + ' + `order`) As `flow`, `lid`, `uuid` From ' + this.tableName +
                    '      WHERE lid = ? And uuid In (' + uuidSql + ')' +
                    '      GROUP BY `lid`, `uuid`' +
                    '  ) As MaxFilter ' +
                    '  ON (Bills.times * ' + timesLen + ' + Bills.order) = MaxFilter.flow And Bills.lid = MaxFilter.lid And Bills.uuid = MaxFilter.uuid' +
                    '  WHERE Bills.tid = ? And Bills.sid = ?';
                const sqlParam = [lid, tid, sid];
                return await this.db.query(sql, sqlParam);
            } else {
                const sql = 'SELECT Bills.* FROM ' + this.tableName + ' As Bills ' +
                    '  INNER JOIN ( ' +
                    '    SELECT MAX(`times` * ' + timesLen + ' + `order`) As `flow`, `lid`, `uuid` From ' + this.tableName +
                    '      WHERE lid = ? And uuid = ?' +
                    '      GROUP BY `lid`, `uuid`' +
                    '  ) As MaxFilter ' +
                    '  ON (Bills.times * ' + timesLen + ' + Bills.order) = MaxFilter.flow And Bills.lid = MaxFilter.lid And Bills.uuid = MaxFilter.uuid' +
                    '  WHERE Bills.tid = ? And Bills.sid = ?';
                const sqlParam = [lid, uuid, tid, sid];
                return await this.db.queryOne(sql, sqlParam);
            }
        }

        /**
         *
         * @param data
         * @returns {Promise<void>}
         */
        async saveDetailData(data) {
            if (data.uuid) {
                const org = await this.getLastestImStageData(this.ctx.tender.id, this.ctx.stage.id, data.lid, data.uuid);
                const order = this.ctx.stage.curAuditor ? this.ctx.stage.curAuditor.order : 0;
                if (org.times === this.ctx.stage.times && org.order === order) {
                    delete org.flow;
                    const newData = this._.assign(org, data);
                    await this.db.update(this.tableName, newData);
                    return newData;
                } else {
                    data.uuid = org.uuid;
                    data.tid = this.ctx.tender.id;
                    data.sid = this.ctx.stage.id;
                    data.times = this.ctx.stage.times;
                    data.order = order;
                    await this.db.insert(this.tableName, data);
                    return data;
                }
            } else {
                data.uuid = this.uuid.v4();
                data.tid = this.ctx.tender.id;
                data.sid = this.ctx.stage.id;
                data.times = this.ctx.stage.times;
                data.order = this.ctx.stage.curAuditor ? this.ctx.stage.curAuditor.order : 0;
                await this.db.insert(this.tableName, data);
                return data;
            }
        }

        async saveDetailDatas(data) {
            if (!data instanceof Array) {
                throw '数据错误';
            }
            const transaction = await this.db.beginTransaction();
            const result = [];
            try {
                for (const d of data) {
                    if (d.uuid) {
                        const od = await this.getLastestImStageData(this.ctx.tender.id, this.ctx.stage.id, d.lid, d.uuid);
                        delete od.flow;
                        if (od.times === this.ctx.stage.curTimes && od.order === this.ctx.stage.curOrder) {
                            d.id = od.id;
                            await transaction.update(this.tableName, d);
                            result.push(d);
                        } else {
                            const nd = this._.assign(od, data);
                            nd.times = this.ctx.stage.curTimes;
                            nd.order = this.ctx.stage.curOrder;
                            await transaction.insert(this.tableName, nd);
                            result.push(nd);
                        }
                    } else {
                        d.uuid = this.uuid.v4();
                        d.tid = this.ctx.tender.id;
                        d.sid = this.ctx.stage.id;
                        d.times = this.ctx.stage.curTimes;
                        d.order = this.ctx.stage.curOrder;
                        await transaction.insert(this.tableName, d);
                        result.push(d);
                    }
                }
                await transaction.commit();
                return result;
            } catch (err) {
                await transaction.rollback();
                throw err;
            }
        }
    }

    return StageDetail;
};
