'use strict';

/**
 * 期计量 - 部位明细计量
 *
 * @author Mai
 * @date 2018/12/8
 * @version
 */
const calcFields = ['contract_qty', 'qc_qty'];
const auditConst = require('../const/audit');

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

        /**
         * 查询期计量最后审核人数据
         * @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`) As `times`, MAX(`order`) As `order`, `lid` From ' + this.tableName +
                        '      GROUP BY `lid`' +
                        '  ) As MaxFilter ' +
                        '  ON Bills.times = MaxFilter.times And Bills.order = MaxFilter.order And Bills.lid = MaxFilter.lid' +
                        '  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);
            }
        }

        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`) As `times`, MAX(`order`) As `order`, `lid` From ' + this.tableName +
                '      WHERE `times` <= ? AND `order` <= ?' +
                '      GROUP BY `lid`' +
                '  ) As MaxFilter ' +
                '  ON Bills.times = MaxFilter.times And Bills.order = MaxFilter.order And Bills.lid = MaxFilter.lid' +
                '  WHERE Bills.tid = ? And Bills.sid = ?' + lidSql;
            const sqlParam = [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);
            }
        }

        async getStageBills(tid, sid, lid) {
            const sql = 'SELECT Stage.*, Ledger.unit_price FROM ?? As Stage, ?? As Ledger ' +
                        '  Where Stage.tid = ?, Stage.sid = ?, Stage.lid = ?, Stage.lid = Ledger.id ' +
                        '  Order Stage.time DESC, Stage.order DESC ';
            const sqlParam = [this.tableName, this.ctx.service.ledger.tableName];
            sqlParam.push(this.db.escape(tid));
            sqlParam.push(this.db.escape(sid));
            sqlParam.push(this.db.escape(lid));
            return await this.db.queryOne(sql, sqlParam);
        }

        async _insertStageBillsData(transaction, insertData, ledgerData) {
            const d = {
                tid: this.ctx.tender.id,
                lid: ledgerData.id,
                sid: this.ctx.stage.id,
                times: this.ctx.stage.times,
                order: this.ctx.stage.curAuditor ? this.ctx.stage.curAuditor.order : 0,
                said: this.ctx.session.sessionUser.accountId,
            };

            const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, ledgerData.unit);
            if (insertData.contract_qty) {
                d.contract_qty = this.round(insertData.contract_qty, precision.value);
                d.contract_tp = d.contract_qty * ledgerData.unit_price;
            }
            if (insertData.qc_qty) {
                d.qc_qty = this.round(insertData.qc_qty, precision.value);
                d.qc_tp = d.qc_qty * ledgerData.unit_price;
            }
            if (insertData.postil) {
                d.postil = insertData.postil;
            }
            await transaction.insert(this.tableName, d);
        }

        /**
         * 前端提交数据
         * @param {Object|Array} data - 提交的数据
         * @returns {Promise<void>}
         */
        async updateStageData(data) {
            const datas = data instanceof Array ? data : [data];
            const transaction = await this.db.beginTransaction();
            try {
                for (const d of datas) {
                    const stageBills = await this.getLastestStageData(this.ctx.tender.id, this.ctx.stage.id, d.lid);
                    const ledgerBills = await this.ctx.service.ledger.getDataById(d.lid);
                    const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, ledgerBills.unit);
                    if (d.contract_qty !== undefined) {
                        d.contract_qty = this.round(d.contract_qty, precision.value);
                        d.contract_tp = d.contract_qty * ledgerBills.unit_price;
                    }
                    if (d.qc_qty !== undefined) {
                        d.qc_qty = this.round(d.qc_qty, precision.value);
                        d.qc_tp = d.qc_qty * ledgerBills.unit_price;
                    }
                    if (!stageBills) {
                        d.tid = this.ctx.tender.id;
                        d.sid = this.ctx.stage.id;
                        d.said = this.ctx.session.sessionUser.accountId;
                        d.times = this.ctx.stage.times;
                        d.order = this.ctx.stage.curAuditor ? this.ctx.stage.curAuditor.order : 0;
                        await transaction.insert(this.tableName, d);
                    } else {
                        d.id = stageBills.id;
                        await transaction.update(this.tableName, d);
                    }
                }
                await transaction.commit();
            } catch (err) {
                await transaction.rollback();
                throw err;
            }
            return await this.getLastestStageData(this.ctx.tender.id, this.ctx.stage.id, this._.map(datas, 'lid'));
        }

        /**
         *
         * @param {Number} tid - 标段id
         * @param {Number} id - 需要计算的节点的id
         * @param {Object} transaction - 操作所属事务，没有则创建
         * @returns {Promise<void>}
         */
        async calc(tid, sid, lid, transaction) {
            const stageBills = await this.getLastestStageData(tid, sid, lid);
            const ledgerBills = await this.ctx.service.ledger.getDataById(lid);
            if (!ledgerBills) {
                throw '提交数据错误';
            }
            const posGather = await this.ctx.service.stagePos.getPosGather(tid, sid, lid, transaction);
            if (!posGather) { return; }

            const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, ledgerBills.unit);
            // 计算
            if (posGather.contract_qty !== undefined) {
                posGather.contract_qty = this.round(posGather.contract_qty, precision.value);
                posGather.contract_tp = this.round(posGather.contract_qty * ledgerBills.unit_price);
            }
            if (posGather.qc_qty !== undefined) {
                posGather.qc_qty = this.round(posGather.qc_qty, precision.value);
                posGather.qc_tp = this.round(posGather.qc_qty * ledgerBills.unit_price);
            }
            if (stageBills) {
                if (stageBills.contract_qty === posGather.contract_qty && stageBills.qc_qty === posGather.qc_qty) {
                    return;
                } else {
                    const curOrder = this.ctx.stage.curAuditor ? this.ctx.stage.curAuditor.order : 0;
                    if (stageBills.times === this.ctx.stage.times && stageBills.order === curOrder) {
                        posGather.id = stageBills.id;
                        await transaction.update(this.tableName, posGather);
                    } else {
                        await this._insertStageBillsData(transaction, posGather, ledgerBills);
                    }
                }
            } else {
                await this._insertStageBillsData(transaction, posGather, ledgerBills);
            }
        }
    }

    return StageBills;
};

