/**
 * 小程序端 孵化器入口  孵化器分数相关逻辑
 * 作者：lxm
 * 
 */

import moment = require("moment");
import { CHANGEMODE, SCOREWAYS, TASKTYPEENUM } from "../../../config/enum";
import { FuHuaQiMyDataScoreConfig, ScoreConfig, FuHuaQiBaseDataScoreConfig, EnterpriseScoreConfig, StarConfig } from "../../../config/scoreConfig";
import { findEnterpriseList } from "../../../data/enterprise/enterprise";
import { findAllFuHuaQiOperationNameMap, findFuHuaQiByUSCC } from "../../../data/fuHuaQi/fuhuaqi";
import * as scoreData from "../../../data/fuHuaQi/score";
import  * as scoreLogData from "../../../data/fuHuaQi/scoreLog";


/**
 * 获取 孵化器 分数
 * @param uscc 孵化器统一信用代码
 */
export async function getFuHuaQiScore(uscc:string) {
    /**计算总分是否和展示分一样 */
    /**得分信息 */
    let scoreInfo = await scoreData.findFuHuaQiScoreInfo(uscc);

    let { startScore, myDataScore, baseDataScore, myEnterpriseScore, taskScore, lastScore } = scoreInfo;
    let count = Math.ceil(startScore +myDataScore +baseDataScore +myEnterpriseScore +taskScore);

    let oldStar = starCount(lastScore);
    let newStar = starCount(count);

    let scoreChange = (count - lastScore) > 0 ? count - lastScore : 0;
    let starUp = newStar > oldStar;

    scoreInfo.lastScore = count;

    await scoreInfo.save();

    let url = `/images/${newStar}.png`;
    return {scoreChange, score:count, starUp, star:newStar, url};
}


/**
 * 根据分数算星数
 * @param socre 分数
 * @returns 星数
 */
export function starCount(socre:number) {
    let star = 1;
    for (let i = 0; i < StarConfig.length; i++) {
        let {name, value, starNum} = StarConfig[i];
        if ( socre <= value ) {
            star = starNum;
            break;
        }
    }
    return star;
}


/**
 * 更新孵化器得分
 * @param uscc 孵化器统一信用代码
 * @param type 类别
 * @param subType 子类别
 * @param isSubmitTask 是否是填报任务  提交任务调用时这里是true 其他都是false
 * 由于不提交任务要扣分，并且分值不一样，所以这里要考虑传入触发状态
 */
export async function updateScore(uscc:string, type:number, isSubmitTask:boolean, subType?) {
    /**得分信息 */
    let scoreInfo = await scoreData.findFuHuaQiScoreInfo(uscc);
    let fuHuaQiInfo = await findFuHuaQiByUSCC(uscc);
    let newScore = 0;//新分数
    let oldScore = 0;//老分数
    let countScore = scoreInfo.startScore +scoreInfo.myDataScore +scoreInfo.baseDataScore +scoreInfo.myEnterpriseScore +scoreInfo.taskScore;
    switch (type) {
        case SCOREWAYS.任务得分:
            /**单个任务得分 */
            let createMonth = !fuHuaQiInfo.createTime ? 0 : new Date(fuHuaQiInfo.createTime).getMonth();

            if (isSubmitTask) newScore = getOnceTaskScore(createMonth);
            else newScore = getOnceTaskDeductScore(createMonth);
            /**赋值新的分数 */
            scoreInfo.taskScore = scoreInfo.taskScore + newScore
        break;
        case SCOREWAYS.我的信息:
        case SCOREWAYS.我的数据:
            let scoreParamKeyConfig = {};
            let scoreConfigNumber=0;
            if (type == SCOREWAYS.我的数据) {
                scoreParamKeyConfig = FuHuaQiMyDataScoreConfig;
                scoreConfigNumber = ScoreConfig["我的数据"];
                oldScore = scoreInfo.myDataScore;
            }else {
                scoreParamKeyConfig = FuHuaQiBaseDataScoreConfig;
                scoreConfigNumber = ScoreConfig["孵化器基础数据"];
                oldScore = scoreInfo.baseDataScore;
            }
            let isValueCount = 0;
            for (let key in scoreParamKeyConfig) {
                let keyType = scoreParamKeyConfig[key];
                if (keyType == '[Object]' || keyType == '[Number]') {
                    if (fuHuaQiInfo[key] && fuHuaQiInfo[key].length) isValueCount += 1;
                } else if (fuHuaQiInfo[key]) isValueCount += 1;
            }
            let valueCount = Object.keys(scoreParamKeyConfig).length;
            newScore = scoreConfigNumber * (isValueCount / valueCount);
            /**赋值新的分数 */
            type == SCOREWAYS.我的数据 ? scoreInfo.myDataScore = newScore : scoreInfo.baseDataScore = newScore;
            
        break;
        case SCOREWAYS.我的企业数据:
            newScore = await myEnterpriseScoreCount(uscc);
            oldScore = scoreInfo.myEnterpriseScore;
            /**赋值新的分数 */
            scoreInfo.myEnterpriseScore = newScore;
        break;
    };
    
    /**分数没有变化 */
    if (oldScore == newScore) return;

    let changeMode = oldScore > newScore ? CHANGEMODE.减少 : CHANGEMODE.增加;
    let newCountScore = countScore - oldScore + newScore;

    if (SCOREWAYS.任务得分 == type) {
        newScore = -1 * newScore;
        await scoreLogData.addLog(uscc, type, changeMode, newCountScore, newScore, subType);
    } else {
        await scoreLogData.addLog(uscc, type, changeMode, newCountScore, newScore);
    }
    
    scoreInfo.updateTime = new Date().valueOf();
    await scoreInfo.save();
}


/**
 * 算单个任务得分
 * @param month 入住月份  如果是去年 就是0   范围是0-11
 * @returns 
 */
function getOnceTaskScore(month:number) {
    let thisMonthTaskCount = 3; //后续接入任务可编辑要改这里
    return (ScoreConfig["任务常量_加分"]/(12-month)) * (1/thisMonthTaskCount);
}


/**
 * 算单个任务扣分
 * @param month 入住月份  如果是去年 就是0   范围是0-11
 * @returns 
 */
function getOnceTaskDeductScore(month:number) {
    let thisMonthTaskCount = 3; //后续接入任务可编辑要改这里
    return -((ScoreConfig["任务常量_扣分"]/(12-month)) * (1/thisMonthTaskCount));
}


/**
 * 我的企业分数
 * @param uscc 孵化器统一信用代码
 * @returns 我的企业得分
 */
async function myEnterpriseScoreCount(uscc:string) {
    let enterpriseList = await findEnterpriseList({fuHuaQiUscc:uscc, draftLock:true});
    let isValueCount = 0;
    let valueCount = 0;

    enterpriseList.forEach(info => {
        for (let key in EnterpriseScoreConfig) {
            let type = EnterpriseScoreConfig[key];
            if (type == '[Object]' || type == '[Number]') {
                if (info[key] && info[key].length) isValueCount += 1;
            } else if (type == 'Boolean') {
                isValueCount += 1;
            } else if (info[key]) isValueCount += 1;
        }
        valueCount += Object.keys(EnterpriseScoreConfig).length;
    });

    if (!valueCount) return ScoreConfig["企业基础数据"];
    return ScoreConfig["企业基础数据"] * (isValueCount / valueCount);
}



/**
 * 分值明细
 * @param uscc 孵化器统一信用代码 
 * @param year 年度时间戳
 */
export async function fuHuaQiScoreLog(uscc:string, year:number) {

    let startTime = year;
    let endTimeStr = `${new Date(startTime).getFullYear()}-12-31 23:59:59`;
    let endTime = new Date(endTimeStr).valueOf();

    let logList = await scoreLogData.getLog(uscc, startTime, endTime);
    logList.sort( (a, b) => {return a.timeMs - b.timeMs });

    let distinctMap = {};
    logList.forEach(info => {
        let timeKey = moment(info.timeMs).format("YYYY-MM");
        if ( !distinctMap[timeKey] ) distinctMap[timeKey] = [];
        let itemWaysStr = waysStr(info.ways, info.taskType, info.changeMode);
        
        itemWaysStr += `${Math.ceil(info.addScore)}分`;

        distinctMap[timeKey].push({
            score:Math.ceil(info.score),
            waysStr:itemWaysStr,
            timeMs:info.timeMs
        });
    });

    let dataList = [];
    for (let key in distinctMap) {
        let count = distinctMap[key].length;
        dataList.push({
            key,
            count,
            list:distinctMap[key]
        });
    }
    return {dataList};
}

function waysStr(ways:number, type:number, changeMode) {
    let str = "";
    if (ways == SCOREWAYS.任务得分) {
        if ( CHANGEMODE.增加 == changeMode) {
            str = "完成";
        } else {
            str = "未提交";
        }
        if (type == TASKTYPEENUM.孵化器月度填报) str += "月度填报";
        else if (type == TASKTYPEENUM.新注册或迁入企业登记) str += "企业录入填报";
        else str += "融资企业填报";
    }
    if (ways == SCOREWAYS.我的企业数据) {
        str += "我的信息更新"
    }
    if (ways == SCOREWAYS.我的企业数据) {
        str += "我的企业更新"
    } 
    if (ways == SCOREWAYS.我的数据) {
        str += "我的数据更新"
    }
    if (CHANGEMODE.增加 == changeMode) str += " 上涨";
    else str += " 下降";
    return str;
}



/**
 * 排行榜
 * @param uscc 孵化器统一信用代码
 */
export async function rankList(uscc:string) {
    let dataList = await scoreData.findScoreDataByParam({});
    let nameMap = await findAllFuHuaQiOperationNameMap();

    let rankList = [];
   
    dataList.forEach(info => {
        rankList.push({
            name:nameMap[info.uscc],
            score: Math.ceil(info.startScore +info.myDataScore +info.baseDataScore +info.myEnterpriseScore +info.taskScore)
        })
    });

    rankList.sort( (a, b) => {return b.score - a.score});
    let thisName = nameMap[uscc];
    let thisFuHuaQiIndex = -1;
    rankList.forEach((info, index) => {
        if (info.name == thisName) thisFuHuaQiIndex = index;
    });

    return {rankList, thisFuHuaQiIndex};
}