/**
 * 孵化器任务相关逻辑
 * 作者: lxm
 * 任务相关逻辑 包括任务的增删改查 管理后台的任务列表逻辑
 * 需求说明   1.任务一个月只下一次 不填次月失效
 *            2.任务提交之后不可以修改
 *            3.月度出租率的任务为必填 其他两个可以为空
 *            4.完成的任务将不再列表中显示
 *            5.每月1日0时0分，将任务下发至孵化器表中未被禁用的孵化器中
 * 实现       1.每个月月初系统生成任务列表在task表中 由isSubmit字段控制是否提交
 *            2.任务对应的数据存在各表中 当提交任务时 将draftLock 字段置为true
 *            3.任务相关的id统一使用 /tools/system 中的 getTaskId() 获取
 */

import moment = require("moment");
import { FINANCINGROUNDS, SCOREWAYS, TASKTYPEENUM } from "../../../../config/enum";
import { ERRORENUM } from "../../../../config/errorEnum";
import * as enterpriseData from "../../../../data/enterprise/enterprise";
import * as financingData from "../../../../data/fuHuaQi/monthTask/financing";
import { findAllNotDisabledFuHuaQi, findFuHuaQiByUSCC } from "../../../../data/fuHuaQi/fuhuaqi";
import * as monthTableData from "../../../../data/fuHuaQi/monthTask/monthTable";
import * as taskData from "../../../../data/fuHuaQi/monthTask/task";
import { BizError } from "../../../../util/bizError";
import { logHandle } from "../../../../util/log";
import { getPwdMd5, getThisMonthMs, md5PwdStr } from "../../../../tools/system";
import * as taskTool from "../../../../tools/taskTool";
import * as scoreBiz from "../score";
import { enterpriseLabelEvent } from "../../../label";
import { changeEnumValue } from "../../../../util/verificationEnum";
import { LABELEVENT } from "../../../../config/enum/labelEnum";
import { findCustomTaskByTaskId } from "../../../../data/fuHuaQi/customTask";


/**   
 * 孵化器的任务列表 (待办任务)
 * 小程序端
 * @param uscc 孵化器统一信用
 * @returns [{key:1, title:'', list:[] }]
 */
export async function fuHuaQiTaskList(uscc:string) {
    /**得到这个月的任务map  taskMap格式为{type:{isSubmit}} */
    const TaskId = taskTool.getTaskId(uscc);

    let taskMap = await taskData.findFuHuaQiTaskByTaskId(TaskId);
    
    //任务还没被创建
    if (!taskMap[TASKTYPEENUM.孵化器月度填报]) return {taskList:[]};
    //查询这个任务是否正在进行中
    let customTaskInfo = await findCustomTaskByTaskId(taskMap[TASKTYPEENUM.孵化器月度填报].customTaskId);
    if (customTaskInfo && customTaskInfo.customTaskId) {
        let now = new Date().valueOf();
        if (now < customTaskInfo.startMs || now > customTaskInfo.endMs) {
            return {taskList:[]};
        }
    }

    let result = [];
    for (let key in TASKTYPEENUM) {
        let anyKey:any = key;
        /** 当key是枚举的键的时候 进入到逻辑  */
        if (isNaN(anyKey)) { 
            const ValueStr = TASKTYPEENUM[key];//字符型的枚举值 也就是 "1"或者"2"或者"3"
            const ValueNumber = parseInt(ValueStr);//number型的枚举值 也就是 1或者2或者3
            let onceObj = { 
                key:ValueNumber, 
                title:anyKey, //标题
                month:'',
                list:[] //相关的列表 这里不应该用这个字段名称 当时不能修改前端 沿用了这个字段名称
            };

            /**没有提交任务 则获取本月提交的任务相关信息 */
            if (taskMap[ValueStr] && !taskMap[ValueStr].isSubmit) {
                let dataList = [];
                // onceObj.month = taskMap[ValueStr].month + '月'
                let quarterItem = Math.ceil(taskMap[ValueStr].month / 3);
                onceObj.month = `${quarterItem}季度`;
                switch(ValueNumber) {
                    case TASKTYPEENUM.孵化器月度填报: 
                        /** 这里加限制  在月度任务中 isUpdate=true代表已经修改  isUpdate=false表示没有这个任务 详细说明看./month.ts注释*/
                        dataList = await monthTableData.findmonthTableListByTaskId(TaskId); 
                    break;
                    case TASKTYPEENUM.新注册或迁入企业登记:
                        /**限制 draftLock = false 即草稿数据 这里可以不用这个限制 */
                        dataList = await enterpriseData.findEnterpriseListByTaskId(TaskId, false);
                        dataList.forEach(item => {
                            item.uscc = item.draftId;//这里转换一下，为了不改前端代码 使用uscc这个名称，但是实际是draftId
                        });
                    break;
                    case TASKTYPEENUM.融资企业填报:
                        /**限制 draftLock = false 即草稿数据 这里可以不用这个限制 */
                        dataList = await financingData.findFinancingListByTaskId(TaskId, false); 
                    break;
                }
            
                dataList.forEach(info => {
                    let addInfo:any = {name:info.name, id:info.uscc, isCreate:info.isCreate || false};
                    onceObj.list.push(addInfo);
                });
                result.push(onceObj);
            }
        } 
    }
   
    return {taskList:result};
}


/**
 * 孵化器 已办任务列表
 * 小程序端  2.0
 * 只显示selectTime月分的 已经办理的任务
 * @param uscc 孵化器统一信用
 * @returns [{type:1, title:'', list:[] }]
 */
export async function fuHuaQiCompletedList(uscc:string, selectTime:number) {
    /**得到查询月的任务map  taskMap格式为{type:{isSubmit}} */
    const TaskId = taskTool.getMonthTaskIdByTime(uscc, selectTime);
    let editable = taskTool.getTaskId(uscc) == TaskId;//如果是本月，就是可以编辑的

    let taskMap = await taskData.findFuHuaQiTaskByTaskId(TaskId);
    
    let result = [];
    for (let key in TASKTYPEENUM) {
        let anyKey:any = key;
        /** 当key是枚举的键的时候 进入到逻辑  */
        if (isNaN(anyKey)) { 
            const ValueStr = TASKTYPEENUM[key];//字符型的枚举值 也就是 "1"或者"2"或者"3"
            const ValueNumber = parseInt(ValueStr);//number型的枚举值 也就是 1或者2或者3
            let onceObj:any = { 
                key:ValueNumber, 
                title:anyKey, //标题
                editable,
                list:[] //相关的列表 这里不应该用这个字段名称 当时不能修改前端 沿用了这个字段名称
            };

             /**当选中了系统上线时间前的时间 任务不存在 就是空列表 */
             if (!taskMap[ValueStr]) continue;

            /**获取提交的任务 */
            if ( taskMap[ValueStr].isSubmit ) {
                onceObj.month = taskMap[ValueStr].month + '月';
                let dataList = [];

                switch(ValueNumber) {
                    case TASKTYPEENUM.孵化器月度填报: 
                        /** 这里加限制  在月度任务中 isUpdate=true代表已经修改  isUpdate=false表示没有这个任务 详细说明看./month.ts注释*/
                        dataList = await monthTableData.findmonthTableListByTaskId(TaskId); 
                    break;
                    case TASKTYPEENUM.新注册或迁入企业登记:
                        /**限制 draftLock = false 即草稿数据 这里可以不用这个限制 */
                        dataList = await enterpriseData.findEnterpriseListByTaskId(TaskId, true);
                        dataList.forEach(item => {
                            item.uscc = item.draftId;//这里转换一下，为了不改前端代码 使用uscc这个名称，但是实际是draftId
                        });
                    break;
                    case TASKTYPEENUM.融资企业填报:
                        /**限制 draftLock = false 即草稿数据 这里可以不用这个限制 */
                        dataList = await financingData.findFinancingListByTaskId(TaskId, true); 
                    break;
                }
            
                dataList.forEach(info => {
                    let addInfo:any = {name:info.name, id:info.uscc, editable,  isCreate:info.isCreate || false};
                    onceObj.list.push(addInfo);
                });
                result.push(onceObj);
            }
        } 
    }

    return {taskList:result};
}


/**
 * 孵化器 过期任务列表
 * 小程序端 2.0
 * 只显示selectTime月份的 过期任务
 * @param uscc 孵化器统一信用
 * @returns [{type:1, title:'', list:[] }]
 */
export async function fuHuaQiPastdueList(uscc:string, selectTime:number) {
    /**得到查询月的任务map  taskMap格式为{type:{isSubmit}} */
    const TaskId = taskTool.getMonthTaskIdByTime(uscc, selectTime);
    if (selectTime >= getThisMonthMs() ) return {taskList:[]};
    let taskMap = await taskData.findFuHuaQiTaskByTaskId(TaskId);
    
    let result = [];
    for (let key in TASKTYPEENUM) {
        let anyKey:any = key;
        /** 当key是枚举的键的时候 进入到逻辑  */
        if (isNaN(anyKey)) { 
            const ValueStr = TASKTYPEENUM[key];//字符型的枚举值 也就是 "1"或者"2"或者"3"
            const ValueNumber = parseInt(ValueStr);//number型的枚举值 也就是 1或者2或者3
            let onceObj:any = { 
                key:ValueNumber, 
                title:anyKey, //标题
                list:[] //相关的列表 这里不应该用这个字段名称 当时不能修改前端 沿用了这个字段名称
            };

            /**当选中了系统上线时间前的时间 任务不存在 就是空列表 */
            if (!taskMap[ValueStr]) continue;

            /**未提交的数据 */
            if (!taskMap[ValueStr].isSubmit) {
                onceObj.month = taskMap[ValueStr].month + '月';
                result.push(onceObj);
            }
        } 
    }

    return {taskList:result};
}


/**
 * 提交任务
 * 小程序端
 * @param uscc 孵化器统一信用代码
 * @param taskType 任务类型
 * @returns {isSuccess:true/false}
 */
export async function checkTask(uscc:string, taskType:number) {
    const TaskId = taskTool.getTaskId(uscc);
    let taskInfo = await taskData.findEnterpriseByTaskIdAndType(TaskId, taskType);

    let fuHuaQiInfo = await findFuHuaQiByUSCC(uscc);
    
    /**提交限制 */
    if (!taskInfo) throw new BizError(ERRORENUM.任务不存在, uscc, TaskId);
    if ( taskInfo.isSubmit ) throw new BizError(ERRORENUM.不能重复提交任务, uscc, taskType);

    let submitCount = 0;
    switch (taskType) {
        case TASKTYPEENUM.孵化器月度填报:
            /**月度报表每个月初和任务数据一起初始化 所以只需要修改状态  */
            let monthTableInfo = await monthTableData.findMonthTableByTaskId(TaskId);
            if (!monthTableInfo.isUpdate) throw new BizError(ERRORENUM.该报表需要填写本月内容后提交, uscc, taskType);
            if ( monthTableInfo.draftLock ) throw new BizError(ERRORENUM.不能重复提交任务, uscc, taskType, '月度表lock = true');
            
            monthTableInfo.draftLock = true;
            await monthTableInfo.save();

            /**更新分数 */
            await scoreBiz.updateScore(uscc, SCOREWAYS.任务得分, true, TASKTYPEENUM.孵化器月度填报);
        break;
        case TASKTYPEENUM.新注册或迁入企业登记:
            /**将录入的企业数据 draftLock 改为 true 表示不再是草稿状态  */
            await enterpriseData.updateEnterpriseDraftLock(TaskId);
            submitCount = await enterpriseData.findEnterpriseCount({taskId:TaskId});
            /**更新分数 */
            await scoreBiz.updateScore(uscc, SCOREWAYS.任务得分, true, TASKTYPEENUM.新注册或迁入企业登记);
            /**校验更新标签 */
            let enterpriseList = await enterpriseData.findEnterpriseList({taskId:TaskId});
            for (let i in enterpriseList) {
                let enterpriseInfo = await enterpriseData.findEnterpriseByUscc(enterpriseList[i].uscc);
                if (enterpriseInfo) {
                    await enterpriseLabelEvent(enterpriseInfo, LABELEVENT.入孵, fuHuaQiInfo.operationName);
                    await enterpriseInfo.save();
                }
               
            }

        break;
        case TASKTYPEENUM.融资企业填报:
            /**将录入的融资数据 draftLock 改为 true 表示不再是草稿状态  */
            await financingData.updateFinancingDraftLock(TaskId);
            submitCount = await financingData.findFinancingCount({taskId:TaskId});
            /**更新分数 */
            await scoreBiz.updateScore(uscc, SCOREWAYS.任务得分, true, TASKTYPEENUM.融资企业填报);
            /**更新标签 */
            let finacingDataList = await financingData.findFinancingListByTaskId(TaskId, true);
            for (let i= 0; i < finacingDataList.length; i++) {
                let itemEnterpriseInfo = await enterpriseData.findEnterpriseByUscc(finacingDataList[i].uscc);
                let financingRoundsStr = changeEnumValue(FINANCINGROUNDS, finacingDataList[i].financingRounds);
                await enterpriseLabelEvent(itemEnterpriseInfo, LABELEVENT.融资, financingRoundsStr, finacingDataList[i].financingAmount);
                await itemEnterpriseInfo.save();
            }

        break;
    }

    /** 修改任务状态标识 和相关信息 */
    taskInfo.isSubmit = true;
    taskInfo.submitTime = new Date().valueOf();
    taskInfo.submitCount = submitCount;
    
    await taskInfo.save();

    return {isSuccess:true};
}


/**
 * 发放任务
 * 系统自发  6.0改成管理后台手动触发 此方法弃用
 * 下发任务的同时初始化月度报表数据
 */
export async function provideMonthTask() {
    const TimeKey = taskTool.getTimeKey();
    let taskCount = await taskData.findTaskCountByParamCount({key:TimeKey});
    if (taskCount) {
        new BizError(ERRORENUM.系统错误, '重复创建了任务');
        return;
    }

    let addList = [];//任务列表
    let monthList = [];//月度填报列表
    
    const MonthNumber = moment().subtract(1, 'months').month() + 1;//数据填报月份
    const YearNumber =moment().subtract(1, 'months').year();//数据填报年份
    const MonthTableName = `${MonthNumber}月孵化器月度填报`;

    let fuHuaQiList = await findAllNotDisabledFuHuaQi();
    fuHuaQiList.forEach(info => {
        let { uscc } = info;
        let taskId = taskTool.generateMonthTaskId(uscc);
        addList.push( { key:TimeKey, type:TASKTYPEENUM.孵化器月度填报, month:MonthNumber, taskId, fuHuaQiUscc:uscc, isSubmit:false, year:YearNumber},
            { key:TimeKey, type:TASKTYPEENUM.新注册或迁入企业登记, month:MonthNumber, taskId, fuHuaQiUscc:uscc, isSubmit:false , year:YearNumber},
            { key:TimeKey, type:TASKTYPEENUM.融资企业填报, taskId, month:MonthNumber, fuHuaQiUscc:uscc, isSubmit:false, year:YearNumber});
        /**任务报表的初始状态为 草稿(draftLock=fals) 未被编辑(isUpdate=false)  */
        monthList.push({ taskId, name:MonthTableName, fuHuaQiUscc:uscc, month:MonthNumber, year:YearNumber, draftLock:false, isUpdate:false });
    });

    try {
        /**初始化 任务 */
        await taskData.createTaskToList(addList);
        logHandle(`添加了${addList.length} 任务`);
         /**初始化 月度填报表 */
        await monthTableData.createMonthTableToList(monthList);
        logHandle(`添加了${monthList.length} 月度任务`);
    } catch (err) {
        new BizError(ERRORENUM.系统错误, '添加任务和月度报表的时候 出现了异常 请检查数据库  ', err);
    }

}


/**
 * 回收任务 计算分数  给账号加上密码
 */
export async function retrieveMonthTask() {
    /**获取上个月 时间key */
    let TimeKey = taskTool.getLastMonthTimeKey();
    let notSubmitList = await taskData.findTaskListByParam({key:TimeKey, isSubmit:false});

    for (let i = 0; i < notSubmitList.length; i++) {
        let uscc = "";
        try {
            let { fuHuaQiUscc, type } = notSubmitList[i];
            uscc = fuHuaQiUscc;
            await scoreBiz.updateScore(fuHuaQiUscc, SCOREWAYS.任务得分, false, type);
        } catch (err) {
            new BizError(ERRORENUM.系统错误, `回收任务时出现错误  uscc:${uscc}   TimeKey:${TimeKey}`, err);
        }
    }

    logHandle(`${TimeKey} 任务回收成功=> 分数更新成功(${notSubmitList.length})条`);

    /**初始化企业密码 */
    let notPwdEnterpriseList = await enterpriseData.findEnterpriseList({pwd:null});
    for (let i = 0; i < notPwdEnterpriseList.length; i++) {
        let dataItem = notPwdEnterpriseList[i];
        let info = await enterpriseData.findEnterpriseByUscc(dataItem.uscc);
        info.pwd = getPwdMd5(info.uscc, md5PwdStr(dataItem.uscc.slice(dataItem.uscc.length-6)));

        await info.save();
    }
    logHandle(`${TimeKey} 成功初始化了(${notPwdEnterpriseList.length})个企业密码`);


}