/**
 * Created by Zhong on 2017/12/21.
 */
const mongoose = require('mongoose');
const compleRationSectionTreeModel = mongoose.model('complementary_ration_section_tree');
const compleRationModel = mongoose.model('complementary_ration_items');
const installSectionModel = mongoose.model("std_ration_lib_installationSection");
const installFeeItemModel = mongoose.model("std_ration_lib_installation");
const complementaryGljModel = mongoose.model('complementary_glj_lib');
const stdGljModel = mongoose.model('std_glj_lib_gljList');
const stdgljutil = require('../../../public/cache/std_glj_type_util');
const installFacade = require('../facades/compleInstallFacade');
import async from 'async';
let stdRationModel = require ('../../ration_repository/models/ration_item').Model;
import SectionTreeDao from '../models/sectionTreeModel';
const sectionTreeDao = new SectionTreeDao();
import GljDao from "../../complementary_glj_lib/models/gljModel";
const gljDao = new GljDao();
let counter = require('../../../public/counter/counter');
const scMathUtil = require('../../../public/scMathUtil').getUtil();
let gljUtil = require('../../../public/gljUtil');

class CompleRatoinDao {
    async updateRation(userID, compilationId, updateData, callback){
        try{
            for(let i = 0, len = updateData.length; i < len; i++){
                let updateObj = updateData[i];
                if(updateObj.updateType === 'new'){
                    updateObj.updateData.userID = userID;
                    updateObj.updateData.compilationId = compilationId;
                    await compleRationModel.create(updateObj.updateData);
                }
                else if(updateObj.updateType === 'update'){
                    await compleRationModel.update({userID: userID, rationRepId: updateObj.updateData.rationRepId}, updateObj.updateData);
                }
            }
            callback(0, '');
        }
        catch(err){
            callback(err, null);
        }
    }

    async getRationItems(sectionId, callback){
        try{
            let compleRations = await compleRationModel.find({sectionId: sectionId, deleteInfo: null});
            callback(0, compleRations);
        }
        catch(err){
            callback(err, null);
        }
    }

    async getRationsCodes(userID, rationRepId, callback){
        try{
            let stdRationCodes = await stdRationModel.find({rationRepId: rationRepId, $or: [{isDeleted: null}, {isDeleted: false}]}, '-_id code');
            let compleRationCodes = await compleRationModel.find({userId: userID, rationRepId: rationRepId, deleteInfo: null}, '-_id code');
            let rstCodes = [];
            stdRationCodes.concat(compleRationCodes).forEach(function (rationItem) {
                rstCodes.push(rationItem.code);
            });
            callback(0, rstCodes);
        }
        catch(err){
            callback(err, null);
        }
    }

    async getGljItems(gljLibId, callback){
        try{
            let stdGljs = await stdGljModel.find({repositoryId: gljLibId, $or: [{deleted: null}, {deleted: false}]});
            callback(0, stdGljs);
        }
        catch(err){
            callback(err, null);
        }
    }

    async getGljItemsOccupied(gljLibId, occupation, callback){
        try{
            let stdGls = await stdGljModel.find({repositoryId: gljLibId, $or: [{deleted: null}, {deleted: false}]}, occupation);
            callback(0, stdGls);
        }
        catch (err){
            callback(err, null);
        }
    }


    async getGljItemsByIds(userID, ids, callback){
        try{
            let rst = [];
            for(let i = 0, len = ids.length; i < len; i++){
                if(ids[i].type === 'std'){
                    let stdGlj = await stdGljModel.find({ID: ids[i].id, deleteInfo: null});
                    if(stdGlj.length > 0){
                        stdGlj[0]._doc.type = 'std';
                        rst.push(stdGlj[0]);
                    }
                }
                else if(ids[i].type === 'complementary'){
                    let compleGlj = await complementaryGljModel.find({userId: userID, ID: ids[i].id, deleteInfo: null});
                    if(compleGlj.length > 0){
                        compleGlj[0]._doc.type = 'complementary';
                        rst.push(compleGlj[0]);
                    }
                }
            }
            callback(0, rst);
        }
        catch(err){
            callback(err, null);
        }
    }

    async getGljItemsByCodes(userID, compilationId, rationRepId, codes, callback){
        try{
            let rst = [];
            for(let i = 0, len = codes.length; i < len; i++){
                let stdGlj = await stdGljModel.find({repositoryId: rationRepId, code: codes[i]});
                if(stdGlj.length > 0){
                    stdGlj[0]._doc.type = 'std';
                    rst.push(stdGlj[0]);
                }
                else {
                    let compleGlj = await complementaryGljModel.find({userId: userID, compilationId: compilationId, code: codes[i]});
                    if(compleGlj.length > 0){
                        compleGlj[0]._doc.type = 'complementary';
                        rst.push(compleGlj[0]);
                    }
                }
            }
            callback(0, rst);
        }
        catch(err){
            callback(err, null);
        }
    }

    //根据章节树获取补充定额
    async getCompleRationBySection(userId, sectionId,gUtil) {
        const deleteQuery = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
        let compleRations = await compleRationModel.find({sectionId: sectionId, $or: deleteQuery});
        for(let ration of compleRations){
            ration._doc.type = 'complementary';
            let hintsArr = [];
            let stdGljIds = [],
                comGljIds = [],
                stdGljs = [],
                comGljs = [];
            let gljAmtMapping = {};
            for(let rationGlj of ration.rationGljList){
                gljAmtMapping[rationGlj.gljId] = rationGlj.consumeAmt;
                if(!isDef(rationGlj.type) || rationGlj.type === 'std'){
                    stdGljIds.push(rationGlj.gljId);
                }
                else {
                    comGljIds.push(rationGlj.gljId);
                }
            }
            if(stdGljIds.length > 0) {
                stdGljs = await stdGljModel.find({ID: {$in: stdGljIds}}).lean();
            }
            if(comGljIds.length > 0) {
                comGljs = await complementaryGljModel.find({userId: userId, ID: {$in: comGljIds}});
            }
            if(!gUtil) gUtil = gljUtil;
            let gljDatas = gUtil.sortRationGLJ(stdGljs.concat(comGljs), true);
            if(ration.jobContent && ration.jobContent.toString().trim() !== ''){
                hintsArr.push(`工作内容:`);
                hintsArr = hintsArr.concat(ration.jobContent.split('\n'));
                hintsArr.push("");
            }
            for(let glj of gljDatas){
                hintsArr.push(` ${glj.code} ${glj.name}${glj.specs ? '&nbsp;&nbsp;&nbsp;' + glj.specs : ''}&nbsp;&nbsp&nbsp;${glj.unit}&nbsp;&nbsp;&nbsp;${gljAmtMapping[glj.ID]}`)
            }
            hintsArr.push(`基价 元 ${ration.basePrice}`);
            if(ration.annotation && ration.annotation.toString().trim() !== ''){
                hintsArr.push(`附注:`);
                hintsArr = hintsArr.concat(ration.annotation.split('\n'));
            }
            ration._doc.hint = hintsArr.join('<br>');
        }
        return compleRations;
    }

    //造价书定额库 根据章节树过去标准定额
    async getRationGljItemsBySection(sectionId,gUtil){
        let stdRations = await stdRationModel.find({sectionId: sectionId});
        for(let ration of stdRations){
            ration._doc.type = 'std';
        }
        function sortByCode(arr) {
            function recurCompare(a, b, index){
                if (a[index] && !b[index]) {
                    return 1;
                } else if (!a[index] && b[index]) {
                    return -1;
                } else if (a[index] && b[index]) {
                    let aV = a[index],
                        bV = b[index];
                    if (!isNaN(aV) && !isNaN(bV)) {
                        aV = parseFloat(a[index]);
                        bV = parseFloat(b[index]);
                    }
                    if (aV > bV) {
                        return 1;
                    } else if (aV < bV) {
                        return -1;
                    } else {
                        return recurCompare(a, b, index + 1);
                    }
                }
                return 0;
            }
            arr.sort(function (a, b) {
                let aArr = a.code.split('-'),
                    bArr = b.code.split('-');
                return recurCompare(aArr, bArr, 0);
            });
        }
        sortByCode(stdRations);
        for(let ration of stdRations){
            let hintsArr = [];
            let stdGljIds = [],
                stdGljs = [];
            let gljAmtMapping = {};
            for(let rationGlj of ration.rationGljList){
                gljAmtMapping[rationGlj.gljId] = rationGlj.consumeAmt;
                stdGljIds.push(rationGlj.gljId);
            }
            if(stdGljIds.length > 0) {
                stdGljs = await stdGljModel.find({ID: {$in: stdGljIds}}).lean();
            }
            if(!gUtil) gUtil = gljUtil;
            let gljDatas =  gUtil.sortRationGLJ(stdGljs, true);
            if(ration.jobContent && ration.jobContent.toString().trim() !== ''){
                hintsArr.push(`工作内容:`);
                hintsArr = hintsArr.concat(ration.jobContent.split('\n'));
                hintsArr.push("");
            }
            for(let glj of gljDatas){
                hintsArr.push(` ${glj.code} ${glj.name}${glj.specs ? '&nbsp;&nbsp;&nbsp;' + glj.specs : ''}&nbsp;&nbsp&nbsp;${glj.unit}&nbsp;&nbsp;&nbsp;${gljAmtMapping[glj.ID]}`)
            }
            hintsArr.push(`基价 元 ${ration.basePrice}`);
            if(ration.annotation && ration.annotation.toString().trim() !== ''){
                hintsArr.push(`附注:`);
                hintsArr = hintsArr.concat(ration.annotation.split('\n'));
            }
            ration._doc.hint = hintsArr.join('<br>');
        }
        return stdRations;
    }

    updateRationBasePrc(userID, basePrcArr, callback){
        let me  = this;
        async.each(basePrcArr, function (basePrcObj, finalCb) {
            let adjGljId = basePrcObj.gljId, adjBasePrice = basePrcObj.basePrice, adjGljType = basePrcObj.gljType;
            async.waterfall([
                function (cb) {
                    if(typeof basePrcObj.delete !== 'undefined' && basePrcObj.delete === 1){
                        //补充定额
                        compleRationModel.find({'rationGljList.gljId': adjGljId},{ID: 1, rationGljList: 1}, function (err, compleRst) {
                            if(err){
                                cb(err);
                            }
                            else {
                                compleRationModel.update({'rationGljList.gljId': adjGljId}, {$pull: {rationGljList: {gljId: adjGljId}}}, {multi: true}, function (err) {
                                    if(err){
                                        cb(err);
                                    }
                                    else {
                                        cb(null, compleRst);
                                    }
                                });
                            }
                        });

                    }
                    else{
                        compleRationModel.find({'rationGljList.gljId': adjGljId}, function (err, compleRst) {
                            if(err){
                                cb(err);
                            }
                            else {
                                cb(null, compleRst);
                            }
                        });
                    }
                },
                function (result, cb) {
                    async.each(result, function (rationItem, ecb) {
                        let rationGljList = rationItem.rationGljList,
                            gljIds = [];
                        rationGljList.forEach(function (rationGlj) {
                            let idObj = Object.create(null);
                            idObj.id = rationGlj.gljId;
                            idObj.type = rationGlj.type;
                            gljIds.push(idObj);
                        });
                        me.getGljItemsByIds(userID, gljIds, function(err, gljItems){
                            if(err){
                                ecb(err);
                            }
                            else{
                                let gljArr = [];
                                for(let i=0; i<gljItems.length; i++){
                                    if(gljItems[i].ID === adjGljId){
                                        gljArr.push({gljId: gljItems[i].ID, basePrice: adjBasePrice});
                                    } else {
                                        gljArr.push({gljId: gljItems[i].ID, basePrice: parseFloat(gljItems[i].basePrice)});
                                    }
                                }
                                gljArr.forEach(function (gljItem) {
                                    rationGljList.forEach(function (rationGlj) {
                                        if(gljItem.gljId === rationGlj.gljId){
                                            gljItem.consumeAmt = parseFloat(rationGlj.consumeAmt);
                                        }
                                    })
                                });
                                //recalculate the price of ration
                                let basePrice = 0;
                                gljArr.forEach(function (gljItem) {
                                    basePrice += gljItem.basePrice * gljItem.consumeAmt;
                                });
                                basePrice = scMathUtil.roundTo(basePrice, 0);
                                //updateDataBase
                                compleRationModel.update({ID: rationItem.ID}, {$set: {basePrice: basePrice.toString()}},
                                    function (err, result) {
                                        if(err){
                                            ecb(err);
                                        }
                                        else {
                                            ecb(null);
                                        }
                                    });
                            }
                        });
                    }, function(err){
                        if(err){
                            cb(err);
                        }
                        else {
                            cb(null);
                        }
                    });
                },
            ], function (err) {
                if(err){
                    finalCb(err);
                }
                else{
                    finalCb(null);
                }
            });
        }, function (err) {
            if(err){
                callback(err, 'Error');
            }
            else{
                callback(0, '');
            }
        });
    }

    mixUpdateRationItems (userID, compilationId, rationLibId, sectionId, updateItems, addItems, rIds, callback){
        let me = this;
        if (updateItems.length == 0 && rIds.length == 0) {
            me.addRationItems(userID, compilationId, rationLibId, sectionId, addItems, callback);
        } else {
            me.removeRationItems(rationLibId, rIds, function(err, message, docs) {
                if (err) {
                    callback(true, false);
                } else {
                    me.updateRationItems(userID, rationLibId, sectionId, updateItems, function(err, results){
                        if (err) {
                            callback(true, false);
                        } else {
                            if (addItems && addItems.length > 0) {
                                me.addRationItems(rationLibId, sectionId, addItems, callback);
                            } else {
                                callback(0, results);
                            }
                        }
                    });
                }
            })
        }
    }

     removeRationItems(rationRepId, rIds,callback){
        if (rIds.length > 0) {
            compleRationModel.remove({rationRepId: rationRepId, ID: {$in: rIds}}, function(err, docs){
                if (err) {
                    callback(true, false);
                } else {
                    callback(0, docs);
                }
            })
        } else {
            callback(0,  null);
        }
    }


     addRationItems(userID, compilationId, rationLibId, sectionId, items,callback){
        if (items && items.length > 0) {
            counter.counterDAO.getIDAfterCount(counter.moduleName.rations, items.length, function(err, result){
                let maxId = result.sequence_value;
                let arr = [];
                for (let i = 0; i < items.length; i++) {
                    let obj = new compleRationModel(items[i]);
                    obj.ID = (maxId - (items.length - 1) + i);
                    obj.sectionId = sectionId;
                    obj.rationRepId = rationLibId;
                    obj.userId = userID;
                    obj.compilationId = compilationId;
                    arr.push(obj);
                }
                compleRationModel.collection.insert(arr, null, function(err, docs){
                    if (err) {
                        callback(true, false);
                    } else {
                        callback(0, docs);
                    }
                })
            });
        } else {
            callback(true, "Source error!", false);
        }
    }

     updateRationItems(userID, rationLibId, sectionId, items,callback){
        let functions = [];
        for (let i=0; i < items.length; i++) {
            functions.push((function(doc) {
                return function(cb) {
                    var filter = {};
                    if (doc.ID) {
                        filter.ID = doc.ID;
                    } else {
                        filter.sectionId = sectionId;
                        filter.userId = userID;
                        if (rationLibId) filter.rationRepId = rationLibId;
                        filter.code = doc.code;
                    }
                    compleRationModel.update(filter, doc, cb);
                };
            })(items[i]));
        }
        async.parallel(functions, function(err, results) {
            if(!err){
                err = 0;
            }
            callback(err, results);
        });
    }

    async getCodes (userId, compilationId) {
        const compleRations = await compleRationModel.find({userId, compilationId}, '-_id code').lean();
        const codes = [];
        compleRations.forEach(item => codes.push(item.code));
        return codes;
    }

    async prepareInitData (userId, compilationId, gljLibId) {
        const rationsCodes = await this.getCodes(userId, compilationId);
        const gljDistTypeCache = stdgljutil.getStdGljTypeCacheObj().toArray();
        const installationData = await installFacade.getInstallation(userId, compilationId);
        const rationTreeData = await sectionTreeDao.getComplementaryTree(userId, compilationId);
        const mixedTreeData = await gljDao.getMixedTree(gljLibId, userId, compilationId);
        const mixedGLJData = await gljDao.getGLJDataSync(gljLibId, userId, compilationId);
        return {
            rationsCodes,
            gljDistTypeCache,
            installationData,
            rationTreeData,
            mixedTreeData,
            mixedGLJData
        }
    }
}

function isDef(v){
    return v !== undefined && v !== null;
}

export default CompleRatoinDao;