/**
 * Created by chen on 2017/7/12.
 */


let mongoose = require('mongoose');
let _=require("lodash");
let ration_glj = mongoose.model('ration_glj');
let ration = mongoose.model('ration');
let ration_coe = mongoose.model('ration_coe');
let std_ration_lib_ration_items = mongoose.model('std_ration_lib_ration_items');
let std_glj_lib_gljList_model = mongoose.model('std_glj_lib_gljList');
let project_model = mongoose.model('projects');
let glj_type_util = require('../../../public/cache/std_glj_type_util');
const scMathUtil = require('../../../public/scMathUtil').getUtil();
let decimal_facade = require('../../main/facade/decimal_facade');
let gljUtil = require('../../../public/gljUtil');

module.exports={
    calculateQuantity:calculateQuantity,
    getGLJTypeByID:getGLJTypeByID
}
//辅助定额调整、替换工料机、标准附注条件调整、添加工料机、自定义消耗量(包括删除工料机)、自定义乘系数、面积增加、市场单价调整
let stateSeq ={
    ass:1,
    replace:2,
    coe:3,
    add:4,
    cusQuantity:5,
    cusCoe:6,
    area:7,
    adjMak:8
};
//自定义乘系数与定额工料机类型映射表
let coeTypeMap = {
    "人工":1,
    "材料":2,
    "机械":3,
    "施工机具":3,
    "主材":4,
    "设备":5
};

let areaIncreaseMap = {
    1:"labour",
    2:"material",
    3:"machine"
};

async function calculateQuantity(query,noNeedCal,refreshRationName = false,areaIncreaseFee,areaSetting){
    try {
         let  result ={
             glj_result:[],
             rationID:query.rationID
         };
         let impactRation = await ration.findOne({ID:query.rationID});
         let gljList = await ration_glj.find(query);//{projectID:query.projectID,rationID:query.rationID}
         let coeList = await ration_coe.find({rationID:query.rationID}).sort('seq').exec();
         let assList=[];
         let assRation = null;
         let adjustState=[];
         if(!impactRation){//如果定额不存在或者已删除，返回空
             return null;
         }
        if(areaIncreaseFee !== null && areaIncreaseFee !== undefined) impactRation.areaIncreaseFee = areaIncreaseFee;
        if(impactRation.areaIncreaseFee == true && !areaSetting){
            let project =  await project_model.findOne({ID:impactRation.projectID},'property.areaSetting');
            areaSetting = project.property.areaSetting;
        }
         if(impactRation._doc.hasOwnProperty("rationAssList")&&impactRation.rationAssList.length>0){
             prepareAss(impactRation.rationAssList);
             let temTimes = [];
             let thirdRationCodes=[];
             for(let i=0;i<impactRation.rationAssList.length;i++){
                 let times = calculateTimes(impactRation.rationAssList[i]);
                 if(times!=0){
                     let thirdRationCode = impactRation.rationAssList[i].thirdRationCode;
                     if(thirdRationCode && thirdRationCode !=''){
                         temTimes.push(times);
                         thirdRationCodes.push(thirdRationCode)
                     }
                     assRation = await  std_ration_lib_ration_items.findOne({rationRepId:impactRation.libID,code:impactRation.rationAssList[i].assistCode});
                     assList.push({times:times,assRation:assRation});
                     adjustState.push({index:stateSeq.ass,content:impactRation.rationAssList[i].name+" "+impactRation.rationAssList[i].actualValue+" : +"+impactRation.rationAssList[i].assistCode+"x"+times});
                 }
             }
             if(temTimes.length == 2 &&thirdRationCodes[0] == thirdRationCodes[1] ){ //说明有第三定额
                 let times_t = temTimes[0] * temTimes[1];
                 let tration =  await  std_ration_lib_ration_items.findOne({rationRepId:impactRation.libID,code:thirdRationCodes[0]});
                 if(tration){
                     assList.push({times:times_t,assRation:tration});
                     adjustState.push({index:stateSeq.ass,content:"+"+thirdRationCodes[0]+"x"+times_t});
                 }
             }
         }
         gljList = sortRationGLJ(gljList);
         for(let i =0;i<gljList.length;i++ ){
             let r = await calculateQuantityPerGLJ(gljList[i],gljList,coeList,assList,adjustState,noNeedCal,impactRation.areaIncreaseFee,areaSetting);
             if(quantityUpdateCheck(gljList[i],r) == true) result.glj_result.push(r);
         }

         if(noNeedCal==null && result.glj_result.length > 0){
            await ration_glj.bulkWrite(generateUpdateTasks(result.glj_result));
         }
         if(impactRation.areaIncreaseFee == true) await setAreaAdjustState(impactRation.projectID,adjustState,areaSetting);

         adjustState= _.sortByOrder(adjustState, ['index'], ['asc']);
         adjustState=_.map(adjustState, _.property('content'));
         let adjustStateString = adjustState.join(';');
         let setData = {adjustState:adjustStateString};
         if(refreshRationName == true){//需要更新定额名称
             let newName = generateRationName(impactRation,gljList);
             setData.name = newName;
             result.rationName = newName;
         }
         //如果uareaIncreaseFee有值说明是从其它更新定额的地方进来的，后面会一起更新
         if(areaIncreaseFee === null || areaIncreaseFee === undefined) await ration.update({ID:query.rationID},setData);
         result.adjustState=adjustStateString;
         return result;
    }catch (err){
        console.log(err);
        throw err;
    }
}

async function setAreaAdjustState(projectID,adjustState,areaSetting){
    if(areaSetting){
        let stringArr = [];
        let labour = getStr(areaSetting.labour);
        let material = getStr(areaSetting.material);
        let machine  = getStr(areaSetting.machine);
        if(labour !="") stringArr.push(`人工*${labour}`);
        if(material !="") stringArr.push(`材料*${material}`);
        if(machine !="") stringArr.push(`机械*${machine}`);
        if(stringArr.length > 0){
            adjustState.push({index:stateSeq.area,content:`面积：${stringArr.join(',')}`});//面积：人工*1.1,材料*1.015”。
        }
    }

    function getStr(num) {
        if(num != 0) return 1 + num/100;
        return "";
    }

}

function quantityUpdateCheck(glj,r) {//检查，有改变的才更新
    for(let key in r.doc){
        if(glj._doc[key] != r.doc[key]) return true
    }
    return false
}


function generateRationName(ration,gljList) {
    let caption = ration.caption ? ration.caption:ration.name;
    let replaceList = [];
    if(ration.rationAssList && ration.rationAssList.length > 0){//这里要处理第三定额和多辅助定额的情况
        let isThird = ration.rationAssList.length == 2 && ration.rationAssList[0].thirdRationCode&&ration.rationAssList[0].thirdRationCode!='';//说明有第三定额的情况
        let adjustMatch = "",notAdjust="";
        for(let ass of ration.rationAssList){
            let tem = "";
            if( ass.isAdjust == 1 && ass.actualValue != null && ass.actualValue != undefined ){
                tem = ass.actualValue;
                adjustMatch = tem;
            }else {
                tem = ass.stdValue;
                notAdjust = tem;
            }
            if(isThird) replaceList.push(tem);
        }
        if(replaceList.length == 0){
            adjustMatch!=""?replaceList.push(adjustMatch):replaceList.push(notAdjust);
        }
        for(let r of replaceList){
            caption =  caption.replace('%s',r);
        }
    }
    let reNameList = [];
    for(let g of gljList){
        //glj._doc.createType=='replace'&&glj.rcode!=glj.code
        if(g.createType=='replace'&&g.rcode!=g.code){ //是替换工料机
            let reName = g.name;
            if(!_.isEmpty(g.specs)) reName = reName + ' '+g.specs;
            reNameList.push(reName);
        }
    }
    if(reNameList.length > 0){
        let reNameString = reNameList.join(" ");
        caption = caption + " 换为【"+ reNameString + "】";
    }
    return caption;
}

function generateUpdateTasks(result) {
    let tasks = [];
    for(let i =0;i<result.length;i++){
        let task= {
            updateOne: {
                filter: result[i].query,
                update: result[i].doc
            }
        }
        tasks.push(task);
    }
    return tasks;
}

function sortRationGLJ(list) {
    list = _.sortByAll(list, [function (item) {
        return _.indexOf(gljUtil.getGljTypeSeq(),item.type);
    }, "code"])
    return list;
}

async function calculateQuantityPerGLJ(glj,gljList,coeList,assList,adjustState,noNeedCal,areaIncreaseFee,areaSetting) {
    let decimalObject =await decimal_facade.getProjectDecimal(glj.projectID);
    let decimal = (decimalObject&&decimalObject.glj&&decimalObject.glj.quantity)?decimalObject.glj.quantity:3;
    let quantity =  scMathUtil.roundTo(parseFloat(glj.quantity),-decimal);
    let result={
        query:{
            ID:glj.ID,
            projectID:glj.projectID
        },
        doc:{
            quantity: quantity
        }
    };
    try {
        if(noNeedCal==null){
            if(!glj._doc.hasOwnProperty('customQuantity')||glj.customQuantity==null||glj.customQuantity==""){
                quantity =scMathUtil.roundTo(parseFloat(glj.rationItemQuantity),-decimal);
                quantity =scMathUtil.roundTo(await calculateAss(quantity,assList,glj),-decimal);
                quantity = calculateQuantityByCoes(quantity,coeList,glj,gljList,decimal);
            }else {
                quantity = glj.customQuantity;
                result.doc.customQuantity = glj.customQuantity;
            }
            let customerCoe = _.last(coeList);
            if(customerCoe&&customerCoe.isAdjust==1){
                quantity = scMathUtil.roundToString(quantity,decimal);
                quantity = calculateQuantityByCustomerCoes(quantity,customerCoe,glj,decimal);
            }
            //计算面积增加费
            if(areaIncreaseFee == true) quantity = calclateAreaIncrease(quantity,glj,areaSetting,decimal);

            result.doc.quantity =scMathUtil.roundToString(quantity,decimal);
            //2019-01-03 需求修改中间过程的价格不参与计算
            //glj.quantity = quantity;//这里保存中间过程计算出来的消耗量，后面处理“+*”操作符时要用到
        }
        generateAdjustState(glj,coeList,adjustState,gljList,result.doc.quantity);
        return result;
    }catch (err){
        throw err;
    }
}

function calclateAreaIncrease(quantity,glj,areaSetting,decimal){
    if(areaSetting){
        let atype = areaIncreaseMap[getRootGLJType(glj.type).ID];
        if(atype && areaSetting[atype]){
            quantity =  scMathUtil.roundForObj(quantity,decimal);
            quantity = scMathUtil.roundToString(quantity * (1 + areaSetting[atype]/100 ),decimal)
        }
    }
    return quantity
}



async function calculateAss(quantity,assList,glj) {
    for(let i=0;i<assList.length;i++){
        if(assList[i].assRation){
            let assglj = null;
            for(let aglj of assList[i].assRation.rationGljList){
                if(glj.createType == 'replace'){//如果工料机是替换过的，要用原始的编码来匹配
                    let std_glj = await std_glj_lib_gljList_model.findOne({'ID':aglj.gljId});
                    if(glj.rcode == std_glj.code){
                        assglj = aglj;
                        break;
                    }
                }else if(aglj.gljId == glj.GLJID){
                    assglj = aglj;
                    break;
                }
            }
            if(assglj){
                let calQuantity = assglj.consumeAmt*assList[i].times;
                quantity += calQuantity
            }
        }
    }
    return scMathUtil.roundTo(quantity,-6);
}

function generateAdjustState(glj,coeList,adjustState,gljList,quantity) {
   //替换工料机 and 添加工料机
    if(glj._doc.createType=='replace'&&glj.rcode!=glj.code){
        adjustState.push({index:stateSeq.replace,content:glj.rcode+'换'+glj.code});
    }else if(glj._doc.createType=='add'){
        let displayQuantity = quantity;
        if(glj._doc.hasOwnProperty('customQuantity')&&(glj.customQuantity != null||glj.customQuantity != '')){
            displayQuantity = glj.customQuantity;
        }
        displayQuantity = displayQuantity&&displayQuantity!=""?parseFloat(displayQuantity):0;
        adjustState.push({index:stateSeq.add,content:'添'+glj.code+'量'+ displayQuantity,type:"添"+glj.code});
    }
    // to do

  //标准附注条件调整 + 自定义乘系数
    if(_.last(gljList).ID == glj.ID){//最后一个工料机的时候才生成，生成一次就可以了
        for(let i=0;i<coeList.length;i++){
            if(coeList[i].isAdjust==1){
                if(i==coeList.length-1){
                    let cus_content = getContent(coeList[i].coes);
                    if(cus_content !="") adjustState.push({index:stateSeq.cusCoe,content:cus_content});//自定义乘系数要去掉倍数为1的
                }else {
                    if(coeList[i].select_code && coeList[i].select_code!=""){
                        _.remove(adjustState,{'content':coeList[i].original_code+'换'+coeList[i].select_code});//去掉替换工料机自动生成的调整状态
                        adjustState.push({index:stateSeq.coe,content:"调 : "+coeList[i].original_code+'换'+coeList[i].select_code});
                    }
                    for(let c of coeList[i].coes){
                        if(c.coeType=='单个工料机') _.remove(adjustState,{'type':"添"+c.gljCode});//如果是单个工料机子目换算类型自动添加的，去掉前面手动生成的调整状态
                        if(c.coeType=='替换人材机') _.remove(adjustState,{'content':c.gljCode+'换'+c.replaceCode});//如果是替换人材机子目换算类型自动添加的，去掉前面手动生成的调整状态
                    }
                    if(coeList[i].content) adjustState.push({index:stateSeq.coe,content:"调 : "+coeList[i].content});//coeList[i].content
                }
            }
        }
    }

    //自定义消耗量
    if(glj._doc.createType!='add'&&glj._doc.hasOwnProperty('customQuantity')){
        if(glj.customQuantity!==null&&glj.customQuantity!=""){
            adjustState.push({index:stateSeq.cusQuantity,content:glj.code+'量'+parseFloat(glj.customQuantity)});
        }
    }
    //市场单价调整
    if(glj._doc.hasOwnProperty('marketPriceAdjust')&&glj.marketPriceAdjust&&glj.marketPriceAdjust!=0){
        //0101005价66.00
        adjustState.push({index:stateSeq.adjMak,content:glj.code+'价'+glj.marketPriceAdjust});
    }

    return adjustState;
}

function getContent(coes) {
    let stringList=[];
    let  temAmount = null;
    let theSame = true;
    for(let t of coes){
        if(temAmount == null){
            temAmount = t.amount;
        }else if(temAmount != t.amount){
            theSame = false;
            break;
        }
    }
    for(let c of coes){
        if( c.amount&&c.amount!=1){
            let operator = c.operator;
            if(c.operator =="*"){
                operator = "X";
            }
            if(theSame == true && c.coeType == "定额"){
                stringList.push(c.coeType+operator+c.amount);
                break;
            }else
            if(theSame == false && c.coeType != "定额"){
                stringList.push(c.coeType+operator+c.amount);
            }

        }
    }
    return stringList.join(",");

}

function prepareAss(assList) {//处理辅助定额，支持多个辅助定额的情况
  for(let a of assList){
    if(a.groupList && a.groupList.length > 1){//组里有多个定额的情况
        let newList = _.sortByAll(a.groupList,[function(item){
           return parseFloat(item.param)
        }]);//先按参数排序
        let pre = 0;
        for(let n of newList){
            if(a.actualValue > pre && a.actualValue <= parseFloat(n.param)){//落在中间，则用组里的这条定额
                a._doc.param = n.param;
                a._doc.paramName = n.paramName;
                a._doc.assistCode = n.assistCode;
                break;
            }
            pre = parseFloat(n.param);
        }
    }
  }
}

function calculateTimes(ass){
    if(ass.isAdjust == 0) return 0;//打勾辅助定额才计算
    let times =(ass.actualValue-ass.stdValue)/ass.stepValue;
    let r = false;
    if(times<0){
        r=true;
        times=times*-1;
    }
    if(ass.carryBit=='四舍五入'){
        times = _.round(times,ass.decimal);
    }else if (ass.carryBit=='进一'){
        times =_.ceil(times,ass.decimal);
    }else if(ass.carryBit == '舍一'){
        times = _.floor(times,ass.decimal);
    }
    if(r){
        times=times*-1;
    }
    return scMathUtil.roundTo(times,-6);
}

function calculateQuantityByCoes(quantity,coeList,glj,gljList,decimal){
    let coeQuantity = quantity;
    if(coeList.length>1){
        for(let i=0;i<coeList.length-1;i++){
            coeQuantity = everyCoe(coeQuantity,coeList[i],glj,gljList,decimal);
        }
    }
    return scMathUtil.roundTo(coeQuantity,-6);
}

function everyCoe(quantity,coe,glj,gljList,decimal) {
    let coeQuantity = quantity;
    if(coe.isAdjust==1){
        for(let i=0;i<coe.coes.length;i++){
            if(coe.coes[i].coeType=='单个工料机' &&coe.coes[i].gljCode==glj.code){//if(coe.coes[i].coeType=='单个工料机'&&coe.coes[i].gljCode==glj.code)
                coeQuantity = getCalculateResult(coeQuantity,coe.coes[i],coe,gljList,decimal);
            }else if(coe.coes[i].coeType== "替换人材机" && glj.rcode == coe.coes[i].gljCode && glj.code == coe.coes[i].replaceCode){
                coeQuantity = getCalculateResult(coeQuantity,coe.coes[i],coe,gljList,decimal);
            }else if(coe.coes[i].coeType== "所选人材机" && glj.rcode == coe.original_code && glj.code == coe.select_code ){
                coeQuantity = getCalculateResult(coeQuantity,coe.coes[i],coe,gljList,decimal);
            } else if(coe.coes[i].coeType=='定额'){
                coeQuantity = getCalculateResult(coeQuantity,coe.coes[i],coe,gljList,decimal);
            }else if(coeTypeMap[coe.coes[i].coeType]==getRootGLJType(glj.type).ID){
                coeQuantity = getCalculateResult(coeQuantity,coe.coes[i],coe,gljList,decimal);
            }
        }
    }
    return scMathUtil.roundTo(coeQuantity,-6);
}


function calculateQuantityByCustomerCoes(quantify,coe,glj) {
    let rationAmount = coe.coes[0].amount;
    if(_.every(coe.coes,'amount',rationAmount)){
        return getCalculateResult(quantify, coe.coes[0])
    }else {
        for(let i=1;i<coe.coes.length;i++){
            if(coeTypeMap[coe.coes[i].coeType]==getRootGLJType(glj.type).ID){
                return getCalculateResult(quantify,coe.coes[i])
            }
        }
    }
    return quantify
}

function getCoeSelectedGLJ(gljList,rcode,code) {
    if(gljList&& code && code !=""){
        let o_glj = _.find(gljList,{'rcode':rcode,'code':code});
        return o_glj;
    }
    return null;
}

function getCalculateResult(quantify,c,coe,gljList,decimal) {
    let q = quantify;
    let o_glj = null;
    switch (c.operator){
        case '+' :
            q = q + c.amount;
            break;
        case '-' :
            q = q - c.amount;
            break;
        case '*' :
            q = q * c.amount;
            break;
        case '/' :
            q = q / c.amount;
            break;
        case '+*' :
            o_glj = getCoeSelectedGLJ(gljList,coe.original_code,coe.select_code);
            if(o_glj){
              q = q +  c.amount * scMathUtil.roundForObj(o_glj.rationItemQuantity,decimal);
            }
            break;
        case '-*' :
            o_glj = getCoeSelectedGLJ(gljList,coe.original_code,coe.select_code);
            if(o_glj){
                q = q -  c.amount * scMathUtil.roundForObj(o_glj.rationItemQuantity,decimal);
            }
            break;
        case '=' :
             q = c.amount;
            break;
    }
    return q;
}

function getRootGLJType(id){
    let glj_type_object = glj_type_util.getStdGljTypeCacheObj();
    let topTypeId = glj_type_object.getTopParentIdByItemId(id);
    let type = glj_type_object.getItemById(topTypeId);
    return type;
}

function getGLJTypeByID(id) {
    let type = getRootGLJType(id);
    if(type!=undefined){
        return type.fullName;
    }else {
        return '';
    }
}