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

import moment = require("moment");
import { SCOREWAYS, TASKTYPEENUM } from "../../../config/enum";
import { ERRORENUM } from "../../../config/errorEnum";
import { findEnterpriseListByTaskId, updateEnterpriseDraftLock } from "../../../data/enterprise/enterprise";
import { findFinancingListByTaskId, updateFinancingDraftLock } from "../../../data/enterprise/financing";
import { findAllNotDisabledFuHuaQi } from "../../../data/fuHuaQi/fuhuaqi";
import * as monthTableData from "../../../data/fuHuaQi/monthTable";
import * as taskData from "../../../data/fuHuaQi/task";
import { BizError } from "../../../util/bizError";
import { logHandle } from "../../../util/log";
import { getLastMonthTimeKey, getTaskId, getTaskIdByTime, getTimeKey } from "../../../tools/system";
import * as scoreBiz from "../fuHuaQi/score";


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

    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 = { 
                key:ValueNumber, 
                title:anyKey, //标题
                month:'',
                enterpriseList:[] //相关的列表 这里不应该用这个字段名称 当时不能修改前端 沿用了这个字段名称
            };

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

    return {taskList:result};
}


/**
 * 孵化器 已办任务列表
 * 小程序端  2.0
 * 只显示selectTime月分的 已经办理的任务
 * @param uscc 孵化器统一信用
 * @returns [{type:1, title:'', enterpriseList:[] }]
 */
export async function fuHuaQiCompletedList(uscc:string, selectTime:number) {
    /**得到查询月的任务map  taskMap格式为{type:{isSubmit}} */
    const TaskId = getTaskIdByTime(uscc, selectTime);
    let editable = 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, //标题
                enterpriseList:[] //相关的列表 这里不应该用这个字段名称 当时不能修改前端 沿用了这个字段名称
            };

             /**当选中了系统上线时间前的时间 任务不存在 就是空列表 */
             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 findEnterpriseListByTaskId(TaskId);
                        dataList.forEach(item => {
                            item.uscc = item.draftId;//这里转换一下，为了不改前端代码 使用uscc这个名称，但是实际是draftId
                        });
                    break;
                    case TASKTYPEENUM.融资企业填报:
                        /**限制 draftLock = false 即草稿数据 这里可以不用这个限制 */
                        dataList = await findFinancingListByTaskId(TaskId); 
                    break;
                }
            
                dataList.forEach(info => {
                    let addInfo:any = {name:info.name, id:info.uscc, editable,  isCreate:info.isCreate || false};
                    onceObj.enterpriseList.push(addInfo);
                });
                result.push(onceObj);
            }
        } 
    }

    return {taskList:result};
}


/**
 * 孵化器 过期任务列表
 * 小程序端 2.0
 * 只显示selectTime月份的 过期任务
 * @param uscc 孵化器统一信用
 * @returns [{type:1, title:'', enterpriseList:[] }]
 */
export async function fuHuaQiPastdueList(uscc:string, selectTime:number) {
    /**得到查询月的任务map  taskMap格式为{type:{isSubmit}} */
    const TaskId = getTaskIdByTime(uscc, selectTime);

    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, //标题
                enterpriseList:[] //相关的列表 这里不应该用这个字段名称 当时不能修改前端 沿用了这个字段名称
            };

            /**当选中了系统上线时间前的时间 任务不存在 就是空列表 */
            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 findEnterpriseListByTaskId(TaskId);
                        dataList.forEach(item => {
                            item.uscc = item.draftId;//这里转换一下，为了不改前端代码 使用uscc这个名称，但是实际是draftId
                        });
                    break;
                    case TASKTYPEENUM.融资企业填报:
                        /**限制 draftLock = false 即草稿数据 这里可以不用这个限制 */
                        dataList = await findFinancingListByTaskId(TaskId); 
                    break;
                }
            
                dataList.forEach(info => {
                    let addInfo:any = { name:info.name };
                    onceObj.enterpriseList.push(addInfo);
                });
                result.push(onceObj);
            }
        } 
    }

    return {taskList:result};
}


/**
 * 提交任务
 * 小程序端
 * @param uscc 孵化器统一信用代码
 * @param taskType 任务类型
 * @returns {isSuccess:true/false}
 */
export async function checkTask(uscc:string, taskType:number) {
    const TaskId = getTaskId(uscc);
    let taskInfo = await taskData.findEnterpriseByTaskIdAndType(TaskId, taskType);
    
    /**提交限制 */
    if (!taskInfo) throw new BizError(ERRORENUM.任务不存在, uscc, TaskId);
    if ( taskInfo.isSubmit ) throw new BizError(ERRORENUM.不能重复提交任务, uscc, taskType);

    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 updateEnterpriseDraftLock(TaskId);
            /**更新分数 */
            await scoreBiz.updateScore(uscc, SCOREWAYS.任务得分, true, TASKTYPEENUM.新注册或迁入企业登记);
        break;
        case TASKTYPEENUM.融资企业填报:
            /**将录入的融资数据 draftLock 改为 true 表示不再是草稿状态  */
            await updateFinancingDraftLock(TaskId);
            /**更新分数 */
            await scoreBiz.updateScore(uscc, SCOREWAYS.任务得分, true, TASKTYPEENUM.融资企业填报);
        break;
    }

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

    return {isSuccess:true};
}


/**
 * 发放任务
 * 系统自发
 * 下发任务的同时初始化月度报表数据
 */
export async function provideTask() {
    const TimeKey = getTimeKey();
    let taskCount = await taskData.findTaskCountByKey(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 = getTaskId(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 retrieveTask() {
    /**获取上个月 时间key */
    let TimeKey = 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})条`);
}