/**
 * Created by chen on 2017/6/29.
 */

let mongoose = require('mongoose');
const uuidV1 = require('uuid/v1')
let consts = require('../../main/models/project_consts')
let commonConsts = consts.commonConst;
let _=require("lodash");
let ration_glj = mongoose.model('ration_glj');
import GLJListModel from '../../glj/models/glj_list_model';
//let std_ration_lib_glj_list_model = require('../../ration_repository/models/glj_repository');
let std_ration_lib_glj_list_model = mongoose.model('std_ration_lib_glj_list');
let async_n = require("async");
let ration = mongoose.model('ration');
let ration_coe_facade = require('./ration_coe_facade');
let ration_coe = mongoose.model('ration_coe');
let std_ration_lib_ration_items = mongoose.model('std_ration_lib_ration_items');
let glj_calculate_facade = require('./glj_calculate_facade');


module.exports={
    save:save,
    getData:getData,
    deleteByRation:deleteByRation,
    getQuantityByProjectGLJ:getQuantityByProjectGLJ
}

let operationMap={
    'ut_create':create_ration_glj,
    'ut_update':update_ration_glj,
    'ut_delete':delete_ration_glj
};
let updateFunctionMap = {
    'normalUpdate':normalUpdate,
    'marketPriceAdjustUpdate':marketPriceAdjustUpdate,
    'customQuantityUpdate':customQuantityUpdate
};




/**
 * 根据项目工料机ID和项目ID取消耗量
 *
 * @param {object} condition
 * @return Array
 */
async function getQuantityByProjectGLJ(condition) {
    let query ={
        $and:[
            {'projectID':condition.projectID},
            {'projectGLJID':{$in:condition.projectGLJIDList}}
        ]
    }


    let results = await   ration_glj.find(query,['projectGLJID','quantity']);
    return combineQuantity(results);
}

function combineQuantity(results) {
    var resultMap = {};
    _.forEach(results,function (data) {
        if(resultMap.hasOwnProperty(data.projectGLJID)){
            resultMap[data.projectGLJID] += data.quantity;
        }else {
            resultMap[data.projectGLJID] = data.quantity;
        }
    })

    var resultList =[];
    for(let key in resultMap){
       let newObject = {
            'projectGLJID':key,
            'quantity':resultMap[key]
        }
        resultList.push(newObject)
    }
    return resultList;
}


function get_lib_glj_info(ration_glj) {
    return function (cb) {
        std_ration_lib_glj_list_model.findOne({'ID':ration_glj.GLJID,'repositoryId':ration_glj.glj_repository_id},(err,glj)=>{
            if(err){
                cb(err,'')
            }else if(glj){
                ration_glj.name = glj.name;
                ration_glj.code = glj.code;
                ration_glj.unit = glj.unit;
                ration_glj.specs = glj.specs;
                ration_glj.basePrice = glj.basePrice;
                ration_glj.gljDistType = glj.gljDistType;
                ration_glj.type = glj.gljType;
                getInfoFromProjectGLJ(ration_glj).then(function (result) {
                    if(result){
                        cb(null,result);
                    }else {
                        cb(new Error('get project glj error'),null);
                    }
                });
            }else {
                cb(null,null);
            }
        })
    }
}

async function getInfoFromProjectGLJ(ration_glj) {
     let data = {
         glj_repository_id: ration_glj.glj_repository_id,
         project_id: ration_glj.projectID,
         code: ration_glj.code,
         name: ration_glj.name,
         specs: ration_glj.specs,
         unit: ration_glj.unit,
         type: ration_glj.type,
         type_of_work: ration_glj.type,
         base_price: ration_glj.basePrice,
         market_price: ration_glj.basePrice
     };
     try {
         let projectGljModel = new GLJListModel();
         let result = await projectGljModel.addList(data);
         ration_glj.marketPrice=result.unit_price.market_price;
         ration_glj.adjustPrice=result.adjust_price;
         ration_glj.projectGLJID=result.id;
         ration_glj.isEstimate=result.is_evaluate;
         return ration_glj;
     } catch (err) {
         console.log(err);
         return null;
     }

 }

function create_ration_glj(user_id,datas) {
    return function (callback) {
        let ration_glj_list=datas.ration_glj_list;
        var tasks=[];
        for(let i =0;i<ration_glj_list.length;i++){
            ration_glj_list[i].ID = uuidV1();
            tasks.push(get_lib_glj_info(ration_glj_list[i]))
        }
        async_n.parallel(tasks,(err,results)=>{
            if(err){
                callback(err,results)
            }else {
                ration_glj.insertMany(results,(err,doc)=>{
                    if(err){
                        callback(err,null);
                    }else {
                        let returndata ={
                            updateTpye:commonConsts.UT_CREATE,
                            moduleName:'ration_glj',
                            data:results
                        }
                        callback(null,returndata)
                    }
                });
            }
        })
    }

}

function update_ration_glj(user_id,datas) {
    if(datas.updateFunction){
        return updateFunctionMap[datas.updateFunction](user_id,datas);
    }else {
        return normalUpdate(user_id,datas);
    }
}

function normalUpdate(user_id,datas){
    return function(callback) {
        ration_glj.update(datas.query,datas.doc,(err,result)=>{
            if(err){
                callback(err,'');
            }else {
                let returndata ={
                    moduleName:'ration_glj',
                    data:{
                        updateTpye:commonConsts.UT_UPDATE,
                        query:datas.query,
                        doc:datas.doc
                    }
                }
                callback(null,returndata)
            }
        })
    }
}

function customQuantityUpdate(user_id,datas){
    return function(callback) {
        doCustomQuantityUpdate(datas).then((result)=>{
            if(result.err){
                callback(result.err,'');
            }else {
                let ration_glj_data ={
                    moduleName:'ration_glj',
                    data:{
                        updateTpye:commonConsts.UT_UPDATE,
                        quantityRefresh:true,
                        glj_result:result.cal_result.glj_result
                    }
                };
                let ration_data ={
                    moduleName:'ration',
                    data:{
                        updateTpye:commonConsts.UT_UPDATE,
                        stateRefresh:true,
                        rationID:result.cal_result.rationID,
                        adjustState:result.cal_result.adjustState
                    }
                };
                callback(null,[ration_glj_data,ration_data]);
            }
        })
    }
}

async function doCustomQuantityUpdate(datas){
    let result = {
        err:null
    }
    try{
        await ration_glj.update(datas.query,datas.doc);
        let cal_result = await glj_calculate_facade.calculateQuantity({projectID:datas.query.projectID,rationID:datas.query.rationID});
        result.cal_result =cal_result;
        console.log(result);
        return result;
    }catch (err){
        result.err = err;
        console.log(err);
        return result;
    }
}


function marketPriceAdjustUpdate(user_id,datas) {
    return function (callback) {
        updateprojectGljAndRationGLJ(datas.query,datas.doc).then((result)=>{
            if(result.err){
                callback(result.err,'');
            }else {
                let returndata ={
                    moduleName:'ration_glj',
                    data:{
                        updateTpye:commonConsts.UT_UPDATE,
                        query:datas.query,
                        doc:result.doc
                    }
                };
                let ration_data ={
                    moduleName:'ration',
                    data:{
                        updateTpye:commonConsts.UT_UPDATE,
                        stateRefresh:true,
                        rationID:datas.query.rationID,
                        adjustState:result.adjustState
                    }
                }
                callback(null,[returndata,ration_data]);
            }
        })

    }
}

async function updateprojectGljAndRationGLJ(query,doc) {
    let returnresult={};
    try {
        let gljListModel = new GLJListModel();
        let result = await gljListModel.modifyMarketPrice(doc);
        let updateDoc ={
            marketPrice:result.unit_price.market_price,
            marketPriceAdjust:doc.market_price,
            projectGLJID:result.id,
            isEstimate:result.is_evaluate,
            name : result.name,
            code:result.code
        };
        let updateresult = await ration_glj.findOneAndUpdate(query, updateDoc);
        let stateResult =  await glj_calculate_facade.calculateQuantity({projectID:query.projectID,rationID:query.rationID},true);

         returnresult ={
            err:null,
            doc :updateDoc,
            adjustState:stateResult.adjustState
        }
        return returnresult;

        } catch (error) {
           returnresult.err = error;
            console.log(error);
            return returnresult
         }
}


function delete_ration_glj(user_id,datas) {
    return function (callback) {
        if(datas.deleteType=="RATION"){
            deleteByRation(datas,callback);
        }else if(datas.deleteType=="BILL"){
            deleteByBill(user_id,datas,callback);
        } else{
            deleteByID(datas,callback);
        }
    }
}

function deleteByRation(datas,callback) {
    let data = datas.updateData;
    let tasks=[];
    tasks.push(deleteGLJList(data));
    tasks.push(ration_coe_facade.delete_ration_coe(data))
    async_n.parallel(tasks,function (err,result) {
        commonCallback(callback,result,err)
    })
}

function  deleteGLJList(data) {
    return function (callback) {
        ration_glj.deleteMany({projectID: data.projectID, rationID: data.ID},(err,result)=>{
            commonCallback(callback,result,err)
        });
    }
}


function deleteByBill(user_id,datas,callback) {
    let tasks = [];
    tasks.push(startingTask("deleteByBill"));
    tasks.push(getRationsByBill(datas));
    tasks.push(deleteRationsbyBill(user_id,datas));
    tasks.push(deleteByMultiRations(datas));
    async_n.waterfall(tasks,function (err,results) {
        if(err){
            callback(err,'');
        }else {
            callback(null,results);
        }
    })
}


function  deleteByID(datas,callback){
    ration_glj.deleteOne(datas.query,(err,result)=>{
        if(err){
            callback(err,'');
        }else {
            let returndata ={
                moduleName:'ration_glj',
                data:{
                    updateTpye:commonConsts.UT_DELETE,
                    query:datas.query,
                }
            }
            callback(null,returndata)
        }
    })
}

function startingTask(processName){
    return function(asyncCallBack){
        var result = {
            processName : processName
        };
        asyncCallBack(null, result);
    };
}

function  getRationsByBill(datas) {
    return function (results,callback) {
        ration.find({projectID:datas.updateData.projectID,billsItemID:datas.updateData.ID},function (err,rations) {
            if(err){
                callback(err,'')
            }else {
                results.rations=rations;
                callback(null,results)
            }
        })
    }
}

function deleteRationsbyBill (user_id,datas){
    return function (results,callback) {
       let deleteInfo ={
            deleteInfo :{deleted: true, deleteDateTime: new Date(), deleteBy: user_id}
        };
        ration.update({projectID: datas.updateData.projectID, billsItemID:datas.updateData.ID},deleteInfo,{multi: true},(err,deleteresults)=>{
            if(err){
                callback(err,'');
            }else {
                callback(null,results);
            }
        });
    }
}


function deleteByMultiRations(datas) {
    return function (results,deleteCallBack) {
        var delete_tasks = [];
        var deleteOne=function (ration) {
            return function (callback) {
                ration_glj.deleteMany({projectID: ration.projectID, rationID: ration.ID},function (err,result) {
                    commonCallback(callback,result,err)
                });
            }
        }
        let rations = results.rations;
        for(let i=0;i<rations.length;i++){
            delete_tasks.push(deleteOne(rations[i]._doc));
            delete_tasks.push(ration_coe_facade.delete_ration_coe(rations[i]._doc));
        }
        async_n.parallel(delete_tasks,(err,results)=>{
            if (err){
                deleteCallBack(err,'')
            }else {
                deleteCallBack(null,results)
            }
        })
    }
}


/*
function  deleteByRation(doc) {
    return function (callback){
        ration_glj.deleteMany({projectID: doc.updateData.projectID, rationID: doc.updateData.ID},callback);
    }
}
*/

function save (user_id, datas, callback) {
    let operations=[];
    if(_.isArray(datas)){
        for(let i=0;i<datas.length;i++){
            operations.push(operationMap[datas[i].updateType](user_id,datas[i]));
        }
    }else {
        operations.push(operationMap[datas.updateType](user_id,datas));
    }
    async_n.parallel(operations,function (err,results) {
        if(err){
            callback(err,'');
        }else {
            if(results.length==1){
                callback(null,results[0])
            }else {
                callback(null,results)
            }
        }
    })
}

function getData(projectID, callback) {
    ration_glj.find({'projectID':projectID},(err,datas)=>{
        if(err){
            callback(1, '', null);
        }else {
            callback(0, consts.projectConst.RATION_GLJ, datas);
        }
    })
}

function commonCallback(callback,result,err) {
    if(err){
        callback(err,'');
    }else {
        callback(null,result);
    }
}