/**
 * Created by jimiz on 2017/4/7.
 */
let mongoose = require('mongoose');
var billsData = require('../models/bills');
let ration_model = require('../models/ration');
let ProjectsData = require('../../pm/models/project_model').project;
let logger = require("../../../logs/log_helper").logger;
let quantity_detail = require("../facade/quantity_detail_facade");
let bill_facade = require("../facade/bill_facade");
let raiton_facade = require("../facade/ration_facade");
let stdBillsModel = mongoose.model('std_bills_lib_bills');
let stdBillJobsModel = mongoose.model('std_bills_lib_jobContent');
let stdBillCharacterModel = mongoose.model('std_bills_lib_itemCharacter');
const { fixedFlag, billType, rationType } = require('../../../public/common_constants');
let LZString = require('lz-string');
const uuidV1 = require('uuid/v1');
//上传的09表、广联达表
const uploadType = {lj: 'lj', gld: 'gld'};
// 上传控件
const multiparty = require("multiparty");
const fs = require("fs");
// excel解析
const excel = require("node-xlsx");
//统一回调函数
var callback = function(req, res, err, message, data){
    res.json({error: err, message: message, data: data});
};

module.exports = {
    getData: function(req, res){
        var data = JSON.parse(req.body.data);
        billsData.getData(data.projectId, function(err, message, billsList){
            if (err === 0) {
                callback(req, res, err, message, billsList);
            } else {
                callback(req, res, err, message, null);
            }
        });
    },

    getItemTemplate: function(req, res){
        //var data = JSON.parse(req.body.data);
        billsData.getItemTemplate(function(err, message, billsItem){
            if (billsItem) {
                callback(req, res, err, message, billsItem);
            } else {
                callback(req, res, err, message, null);
            }
        });
    },

    allocIDs: function(req, res){
        billsData.allocIDs(function(err, message, data){
            if (err) {
                callback(req, res, err, message, data);
            } else {
                callback(req, res, err, message, null);
            }
        });
    },
    //zhong 2017-9-1
    updateCharacterContent: function (req, res) {
        let data = JSON.parse(req.body.data);
        let findSet = data.findSet,
            updateObj = data.updateObj,
            txtObj = data.txtObj;
        billsData.updateCharacterContent(findSet, updateObj, txtObj, function (err, message) {
            callback(req, res, err, message, null);
        });
    },
    updateBills: async function (req, res) {
        try{
            let data = JSON.parse(req.body.data);
            await billsData.updateBills(data.updateDatas);
            callback(req, res, 0, 'success', null);
        }
        catch (err){
            callback(req, res, 1, err, null);
        }
    },
    updateBill: async function(request, response) {
        const data = JSON.parse(request.body.data);
        const findSet = data.findSet;
        const updateData = data.updateData;
        let settingData = {};
        // 筛选出要保存在项目属性的设置
        for (const index in updateData) {
            if (updateData[index].field === 'addRule') {
                settingData = updateData[index].value;
                delete updateData[index];
            }
        }
       /* // 更新项目属性
        const propertyUpdateData = {
            property: 'addRule',
            data: settingData
        };*/
        //const projectResult = await ProjectsData.updateProjectProperty(findSet.projectID, propertyUpdateData);

        const result = await billsData.updateBill(findSet, updateData);
        const message = !result ? '修改失败' : '修改成功';
        const err = !result ? 1 : 0;
        callback(request, response, err, message, null);
    },
    singleDelete:async function(req, res){
        let result={
            error:0
        }
        try {
            let data = req.body.data;
            data = JSON.parse(data);
            let tasks = generateSingleDeleteTasks(data);
            let resultData= await billsData.model.bulkWrite(tasks);
            //删除工程量明细
            await quantity_detail.deleteByQuery({projectID: data.projectID, billID: data.ID}) ;
            result.data=resultData;
        }catch (err){
            logger.err(err);
            result.error=1;
            result.message = err.message;
        }
        res.json(result);
    },
    multiDelete:async function(req, res){
        let result={
            error:0
        };
        try {
            let data = req.body.data;
            data = JSON.parse(data);
            result.data=await doBillsOrRationsDelete(data);
        }catch (err){
            logger.err(err);
            result.error=1;
            result.message = err.message;
        }
        res.json(result);
    },
    getSectionInfo:async function(req, res){
        let result={
            error:0
        }
        try {
            let data = req.body.data;
            data = JSON.parse(data);
            let sectionInfo= await bill_facade.getSectionInfo(data);
            result.data=sectionInfo;
        }catch (err){
            logger.err(err);
            result.error=1;
            result.message = err.message;
        }
        res.json(result);
    },
    reorganizeFBFX:async function(req,res){
        let result={
            error:0
        }
        try {
            let data = req.body.data;
            data = JSON.parse(data);
            let reorganizeResult= await bill_facade.reorganizeFBFX(data);
            result.data=reorganizeResult;
        }catch (err){
            logger.err(err);
            result.error=1;
            result.message = err.message;
        }
        res.json(result);
    },
    pasteBlock:async function(req,res){
        let result={
            error:0
        };
        try {
            let data = req.body.data;
            data = JSON.parse(data);
            let pasteResult = await bill_facade.pasteBlock(data,req.session.sessionCompilation);
            result.data = pasteResult;
        }catch (err){
            logger.err(err);
            result.error=1;
            result.message = err.message;
        }
        res.json(result);
    },
    //下载导入清单示例
    downloadExample: function(request, response) {
        try {
            //导入类型（09表、广联达）对应的示例文件名
            const uploadTypeMap = { general: '示例1-分部分项工程项目清单.xlsx', lj: '示例2-分部分项工程项目清单计价表.xlsx', gld: '算量示例-清单汇总表.xlsx' };
            const type = request.query.type;
            const fileName = uploadTypeMap[type];
            const filePath = `./public/static/${fileName}`;
            const stats = fs.statSync(filePath);
            // 下载相关header
            response.set({
                'Content-Type': 'application/octet-stream',
                'Content-Disposition': `attachment; filename=${encodeURI(fileName)}`,
                'Content-Length': stats.size
            });
            fs.createReadStream(filePath).pipe(response);
        } catch (error) {
            response.end(error);
        }

    },
    //导入清单
    import: async function(req, res){
        let responseData = {
            err: 0,
            msg: '',
            data: []
        };
        const form = new multiparty.Form();
        form.parse(req, async function(err, fields, files) {
            try{
                const projectID = fields.projectID !== undefined && fields.projectID.length > 0 ?
                    parseInt(fields.projectID[0]) : 0;
                if (projectID <= 0) {
                    throw '参数错误';
                }
                //导入清单数据
                let compressData = fields.compressData !== undefined && fields.compressData.length > 0 ?
                    fields.compressData[0] : null;
                if(compressData === null){
                    throw 'excel没有对应数据'
                }
                let importData = JSON.parse(LZString.decompressFromUTF16(compressData));
                //匹配的清单库
                const billsLibId = fields.billsLibId !== undefined && fields.billsLibId.length > 0 && fields.billsLibId[0]? parseInt(fields.billsLibId[0]) : null;
                let stdBills = [], stdJobs = [], stdCharacters = [];
                if(billsLibId){
                    stdBills = await stdBillsModel.find({billsLibId: billsLibId, deleted: false}, '-_id code jobs items engineering billsLibId ruleText');
                    stdJobs = await stdBillJobsModel.find({billsLibId: billsLibId, deleted: false});
                    stdCharacters = await stdBillCharacterModel.find({billsLibId: billsLibId, deleted: false});
                }
                let stdData = {stdBills: stdBills, stdJobs: stdJobs, stdCharacters: stdCharacters};
                //导入表
                let importDateA = +new Date();
                for(let position in importData){
                    if(importData[position].length > 0){
                        let updateFrontData = await importSheet(position, importData[position], req.session.sessionUser.id, projectID, stdData);
                        if(updateFrontData){
                            responseData.data.push(updateFrontData);
                        }
                    }
                }
                let importDateB = +new Date();
                console.log(`导入时间: ${importDateB - importDateA}=========================================================================`);
                res.json(responseData);
            }
            catch (error){
                responseData.err = 1;
                console.log(error);
                responseData.msg = typeof error === 'object' ? '上传失败' : error;
                res.json(responseData);
            }

        });
    },
    insertBills: async function (req, res) {
        let data = JSON.parse(req.body.data);
        try {
            await bill_facade.insertBills(data.postData);
            callback(req, res, 0, 'success', null);
        } catch (err) {
            callback(req, res, 1, err, null);
        }
    }
};

async function importSheet(position, excelBills, userID, projectID, stdData){
        //导入位置的有固定行
        let flag = getImportFlag(position);
        if(!flag){
            throw 'excel数据错误';
        }
        let fixedBill = await billsData.model.findOne({projectID: projectID, 'flags.flag': flag, deleteInfo: null});
        let insertFixedBill = null;
        //导入xx措施项目,若不存在此固定清单，则先插入相关固定清单
        if(!fixedBill){
            //分部分项工程(不可删除)应存在
            if(flag === fixedFlag.SUB_ENGINERRING){
                throw '项目不存在分部分项工程'
            }
            //措施项目是否存在
            let csxm = await billsData.model.findOne({projectID: projectID, 'flags.flag': fixedFlag.MEASURE, deleteInfo: null});
            if(!csxm){
                throw '项目不存在措施项目'
            }
            //插入清单固定行(施工技术措施项目、施工组织措施项目可删除)
            insertFixedBill = {projectID: projectID, name: flag === fixedFlag.CONSTRUCTION_TECH ? '施工技术措施项目' : '施工组织措施项目', code: '1',
                ID: uuidV1(), NextSiblingID: -1, ParentID: csxm.ID, flags: [{fieldName: 'fixed', flag: flag}], type: billType.BILL};
            //更新前节点
            let preDatas = await billsData.model.find({projectID: projectID, ParentID: csxm.ID, deleteInfo: null});
            for(let preData of preDatas){
                if(preData.NextSiblingID == -1){
                    await billsData.model.update({ID: preData.ID}, {$set: {NextSiblingID: insertFixedBill.ID}});
                    break;
                }
            }
            await billsData.model.create(insertFixedBill);
            fixedBill = insertFixedBill;
        }
        //将excel清单数据转换成完整清单数据（设置ParentID、匹配标准清单库）
        parseToCompleteBills(excelBills, fixedBill, stdData);
        //删除相关数据
        let deleteDatas = await billsData.deepDeleteBill([fixedBill], userID);
        //新增清单数据
        await billsData.importBills(excelBills);
        // 如果导入招标、控制价文件、每个分项底下自动生成一条空定额
        const rations = [];
        excelBills.forEach(bills => {
            if (bills.type === billType.FX) {
                const emptyRation = {
                    projectID: bills.projectID,
                    ID: uuidV1(),
                    billsItemID: bills.ID,
                    serialNo: 1,
                    type: rationType.ration,
                };
                rations.push(emptyRation);
            }
        });
        if (rations.length) {
            await ration_model.model.insertMany(rations);
        }
        //返回数据以更新前端
        if(insertFixedBill){
            excelBills.push(insertFixedBill);
        }
        return {fixedBill: fixedBill, insert: {bill: excelBills, ration: rations}, remove: {bill: deleteDatas.bill, ration: deleteDatas.ration}};
}


function getImportFlag(position){
    const fixedItem = {'fbfx': fixedFlag.SUB_ENGINERRING, 'jscsxm': fixedFlag.CONSTRUCTION_TECH, 'zzcsxm': fixedFlag.CONSTRUCTION_ORGANIZATION};
    return fixedItem[position] ? fixedItem[position] : null;
}
function isDef(data){
    return typeof data !== 'undefined' && data !== null && data !== '';
}
//将前端解析生成的清单节点数据完善（ParentID、匹配标准清单）
function parseToCompleteBills(excelBills, fixedBills, stdData){
    //设置清单ParentID
    let rootID = fixedBills ? fixedBills.ID: -1;
    for(let bills of excelBills){
        if(bills.nodeType === 'root'){
            rootID = bills.ID;
            bills.ParentID = fixedBills.ID;
        }
        else {
            bills.ParentID = rootID;
        }
        delete bills.nodeType;
        matchStdBill(bills, stdData);
    }

    //excel数据与标准库数据匹配，根据清单前九位编码匹配，匹配成功则获取标准清单对应的工程专业、特征及内容
    function matchStdBill(excelBill, stdData){
        let isMatch = false;
        let regExp = /^\d{12}$/g;
        if(excelBill.code.length >8){
            let nineCode = excelBill.code.substr(0, 9);
            for(let stdBill of stdData.stdBills){
                //set programID
                if(nineCode == stdBill.code){
                    isMatch = true;
                    excelBill.programID = stdBill.engineering ? stdBill.engineering : null;
                    excelBill.billsLibId = stdBill.billsLibId ? stdBill.billsLibId : null;
                    excelBill.ruleText = stdBill.ruleText ? stdBill.ruleText : '';
                    //set jobContent and itemCharacter
                    let tempJob = [], tempCharacter = [];
                    for(let billJob of stdBill.jobs){
                        for(let stdJob of stdData.stdJobs) {
                            if (billJob.id == stdJob.id) {
                                tempJob.push({isChecked: false, serialNo: billJob.serialNo, content: stdJob.content});
                            }
                        }
                    }
                    for(let billCharacter of stdBill.items){
                        for(let stdCharacter of stdData.stdCharacters){
                            if(billCharacter.id == stdCharacter.id){
                                let eigenvalue = [];
                                for(let eValue of stdCharacter.itemValue){
                                    eigenvalue.push({isSelected: false, value: eValue.value});
                                }
                                tempCharacter.push({isChecked: false, serialNo: billCharacter.serialNo, character: stdCharacter.content, eigenvalue: eigenvalue});
                            }
                        }
                    }
                    excelBill.jobContent = tempJob;
                    excelBill.itemCharacter = tempCharacter;
                }
            }
        }
        if(!isMatch && excelBill.type === billType.FX){//分项不为空，同时在标准清单中不匹配，则识别为补项
            excelBill.type = billType.BX;
        }
    }
}

async function doBillsOrRationsDelete(data) {
    let billTask = [];
    let deleteBillIDs = [];
    let rationTask=[];
    let deleteRationIDs=[];
    let qd_query=null;
    let sub_query=null;
    if(data['bills']){
        billTask = generateUpdateTasks(data['bills'],data.projectID,data.user_id);
        for(let b_key in data['bills']){
            if(data['bills'][b_key]===true){
                deleteBillIDs.push(b_key+'');
            }
        }
        if(deleteBillIDs.length>0){
            qd_query={projectID: data.projectID, billID: {"$in": deleteBillIDs}};
        }
    }
    if(data['ration']){
        rationTask = generateUpdateTasks(data['ration'],data.projectID,data.user_id);
        for(let r_key in data['ration']){
            if(data['ration'][r_key]===true){
                deleteRationIDs.push(r_key+'');
            }
        }
        if(deleteRationIDs.length>0){
            if(qd_query==null){//说明没删除清单
                qd_query={projectID: data.projectID, rationID: {"$in": deleteRationIDs}};
            }else {
                qd_query={
                    "$or":[
                        {projectID: data.projectID, billID: {"$in": deleteBillIDs}},
                        {projectID: data.projectID, rationID: {"$in": deleteRationIDs}}
                    ]
                }
            }
            sub_query={projectID: data.projectID, rationID: {"$in": deleteRationIDs}};
        }
    }
    //先删除工程量明细
    if(qd_query!=null){
        await quantity_detail.deleteByQuery(qd_query) ;
    }
    if(sub_query!=null){
        await raiton_facade.deleteSubListByQuery(sub_query);
    }
    if(rationTask.length>0){
        await ration_model.model.bulkWrite(rationTask);//删除定额
    }
    if(billTask.length>0){
        await billsData.model.bulkWrite(billTask);//删除清单
    }
    return 'success';
}



function  generateSingleDeleteTasks(data) {
    let updateData = data.updateData;
    updateData[data.ID]=true;
    let tasks = generateUpdateTasks(updateData,data.projectID,data.user_id);
    return tasks;
}

function  generateUpdateTasks(data,projectID,user_id) {
    let tasks=[];
    let updateData = data;
    let deleteInfo={deleted: true, deleteDateTime: new Date(), deleteBy: user_id};
    for(let key in updateData){
        let task={
            updateOne:{
                filter:{
                    ID:key,
                    projectID:projectID
                }
            }
        };
        if(updateData[key]===true){
            //原先是假删除，现在改成真删除
            task = {
                deleteOne:{
                    filter:{
                        ID:key,
                        projectID:projectID
                    }
                }
            }
           /* task.updateOne.update={
                deleteInfo:deleteInfo
            };*/
        }else {
            task.updateOne.update=updateData[key];
        }
        tasks.push(task);
    }
    return tasks;
}