package com.zcxk.evaluation.job;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zcxk.client.UserCenterClient;
import com.zcxk.evaluation.dao.*;
import com.zcxk.evaluation.entity.*;
import com.zcxk.evaluation.enums.EvaluationCycleEnums;
import com.zcxk.evaluation.enums.EvaluationItemEnums;
import com.zcxk.evaluation.vo.EvaluationItemValueVo;
import com.zcxk.evaluation.vo.EvaluationItemVo;
import com.zcxk.exception.ServiceException;
import com.zcxk.order.dao.WorkOrderManageMapper;
import com.zcxk.order.dto.WorkOrderManageDto;
import com.zcxk.task.entity.UserEntity;
import com.zcxk.util.DatesUtil;
import com.zcxk.utils.EvaluationUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;

/**
 * 生成绩效考评数据，每天启动一次脚本
 * 1.检查考评日期是否是当天
 * 2.季度数据需要在1月、4月、7月、10月生成对应的季度数据：
 *   1月对应10、11、12
 *   4月对应1、2、3
 *   7月对应4、5、6
 *   10月对应7、8、9
 * 3.年度数据在1月生成去年整年数据
 * 4.按照上面指定的月、季度、年度得出具体时间并查询运维人员的工单情况，计算出工单/任务的一个完成情况，根据设置的考评项目得出对应的分数
 * @Author lihui
 * @Date 2021/5/7
 * @Version V1.0
 **/
@Component
@Slf4j
@EnableScheduling
public class EvaluationResultJob {

    @Autowired
    private WorkOrderManageMapper workOrderManageMapper;

    @Autowired
    private UserCenterClient userCenterClient;

    @Autowired
    private EvaluationCycleMapper evaluationCycleMapper;

    @Autowired
    private EvaluationResultDetailsMapper evaluationResultDetailsMapper;

    @Autowired
    private EvaluationResultMapper evaluationResultMapper;

    @Autowired
    private EvaluationResultTaskMapper evaluationResultTaskMapper;

    @Autowired
    private EvaluationItemMapper evaluationItemMapper;

    private static boolean lock = false;


    /**
     * 运维类型
     */
    private static final int OPERATION_TYPE = 3;

    /**
     * 保存考评项目设置
     */
    static Map<String, List<EvaluationItemVo>> itemMap = new HashMap<>();

    /**
     * 保存用户ID
     */
    static Map<String,  List<UserEntity>> userInfoMap = new HashMap<>();


    /***
     * @Scheduled(cron = "0/5 * * * * ?")
     *
     *  异步启动定时任务,每天凌晨4点
     * @Author lihui
     * @Date 18:26 2021/5/17
     * @return void
     **/
    @Scheduled(cron = "0 0 4 * * ?")
    @Async
    public void run(){
        if (lock){
            return;
        }
        lock = true;
        log.info("============绩效考评数据生成begin=====================");
        String startTime = null;
        String endTime   = null;
        int today = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
        EvaluationCycleEntity queryEntity = new EvaluationCycleEntity();
        queryEntity.setEvaluationDay(today);
        // 首先查询当天哪些公司设置了绩效考评
        List<EvaluationCycleEntity> evaluationCycleEntities =  evaluationCycleMapper.findList(queryEntity);
        try {
            for (EvaluationCycleEntity evaluationCycleEntity : evaluationCycleEntities) {
                // 如果是年度，需要检查当前日期是否是在1月份
                if (evaluationCycleEntity.getType() == EvaluationCycleEnums.YEAR.getType() &&
                        !EvaluationUtil.sameMonth(1)) {
                    continue;
                }
                // 根据类型(0月度 1季度 2年度)得到当前的开始时间和结束时间，如果是按季度，当月必须是1，4，7，10
                startTime = EvaluationUtil.getStartTime(evaluationCycleEntity.getType(), today);
                endTime   = EvaluationUtil.getEndTime(evaluationCycleEntity.getType(), today);
                if (startTime == null || endTime == null) {
                    continue;
                }
                userTask(evaluationCycleEntity,  startTime,  endTime);
            }
        } catch (Exception e) {
            log.error("绩效考评定时任务出错->", e);
        } finally {
            // 用完直接clear
            itemMap.clear();
            userInfoMap.clear();
            lock = false;
        }
        log.info("============绩效考评数据生成end=====================");
    }

    /***
     * 用户任务分解 ..
     * @author lihui
     * @date 11:12 2021/5/20
     * @param evaluationCycleEntity : 参数
     * @param startTime :  开始时间
     * @param endTime :   结束时间
     * @return void
     **/
    public void userTask(EvaluationCycleEntity evaluationCycleEntity, String startTime, String endTime){
        List<EvaluationItemVo> itemEntityList = null;
        Integer cycle = evaluationCycleEntity.getType();
        // 查询该租户公司下的所有用户
        List<UserEntity> userEntityList = getUserInfo(evaluationCycleEntity.getTenantId(), evaluationCycleEntity.getCompanyOrgId());
        if (userEntityList == null) {
            return;
        }
        for (UserEntity userEntity : userEntityList) {
            // 1.获取部门考评项设置，如果未设置直接过滤
            // 2.判断部门考评项目设置里面有没有设置对应的考评周期，没有就直接过滤
            itemEntityList = findItem(userEntity);
            if (CollectionUtil.isEmpty(itemEntityList) || !EvaluationUtil.containsType(itemEntityList, cycle)) {
                continue;
            }
            try {
                // 保存用户考评结果
                saveEvaluationResultInfo(userEntity, itemEntityList , startTime, endTime ,cycle);
            } catch (Exception e) {
                log.error("保存用户考评信息出错->", e);
            }
        }
    }

    /***
     * 获取该租户公司下的用户
     * @author lihui
     * @date 10:49 2021/5/19
     * @param tenantId :  租户ID
     * @param companyOrgId :  公司id
     * @return java.util.List<java.lang.Integer>
     **/
    private List<UserEntity> getUserInfo(String tenantId, Integer companyOrgId){
        String key = tenantId + "_" + companyOrgId;
        List<UserEntity> result = userInfoMap.get(key);
        if (result == null){
            result = userCenterClient.findAllUserList(companyOrgId, tenantId, OPERATION_TYPE);
            userInfoMap.put(key, result);
        }
        return result;
    }


    /***
     * 1.计算用户完成任务情况
     * 2.组装考评结果数据
     * 3.保存考评结果
     * 4.计算得分范围，保存考评结果详情
     * @author lihui
     * @date 15:38 2021/5/21
     * @param userEntity :
     * @param itemEntityList :
     * @param startTime :
     * @param endTime :
     * @param cycle :
     * @return void
     **/
    @Transactional(rollbackFor = Exception.class)
    public void saveEvaluationResultInfo(UserEntity userEntity, List<EvaluationItemVo> itemEntityList, String startTime, String endTime, Integer cycle){
        // 条件值
        BigDecimal evaluationValue = null;
        // 计算用户完成任务情况
        EvaluationResultTaskEntity taskDetailsVo = calculationTaskInfo(userEntity.getId().intValue(), userEntity.getTenantId(),
                startTime, endTime, getValueCondition(itemEntityList));
        EvaluationResultEntity resultEntity = packagesEvaluationResultEntity(userEntity, cycle, startTime, endTime);
        if (evaluationResultMapper.insertEvaluationResult(resultEntity) != 1) {
            throw new ServiceException(500, "保存考评结果出错，退出。");
        }
        Integer resultId = resultEntity.getId().intValue();
        taskDetailsVo.setEvaluationResultId(resultId);
        // 保存考评结果任务详情
        evaluationResultTaskMapper.insertEvaluationResultTask(taskDetailsVo);
        BigDecimal completeCount   = new BigDecimal(taskDetailsVo.getCompleteCount()) ;
        // 按时完成率
        BigDecimal completionRate  = EvaluationUtil.onTimeCompletionRate(taskDetailsVo.getCompleteCount(),
                taskDetailsVo.getDelayCompleteCount(), taskDetailsVo.getTotalCount());
        // 保存考评分数
        for (EvaluationItemVo item : itemEntityList) {
            // 不是当前季度的，过滤
            if (item.getCycle().indexOf(cycle.toString()) == -1 || item.getType() == null) {
                continue;
            }
            evaluationValue = item.getType() == EvaluationItemEnums.COMPLETE_COUNT.getType() ? completeCount : completionRate;
            EvaluationResultDetailsEntity detailsEntity = new EvaluationResultDetailsEntity();
            detailsEntity.setEvaluationResultId(resultId);
            detailsEntity.setEvaluationItemId(item.getItemId());
            detailsEntity.setValue(getScore(item, evaluationValue));
            detailsEntity.setDateCreate(new Date());
            detailsEntity.setDateUpdate(new Date());
            detailsEntity.setTenantId(userEntity.getTenantId());
            detailsEntity.setStatus(1);
            evaluationResultDetailsMapper.insertEvaluationResultDetails(detailsEntity);
        }
    }

    /***
     * 计算用户完成任务情况
     * @author lihui
     * @date 15:51 2021/5/21
     * @param userId :     用户ID
     * @param tenantId :   租户ID
     * @param startTime :  开始时间
     * @param endTime :    结束时间
     * @param valueCondition :  条件值
     * @return com.zcxk.evaluation.entity.EvaluationResultTaskEntity
     **/
    private EvaluationResultTaskEntity calculationTaskInfo(Integer userId, String tenantId, String startTime, String endTime, BigDecimal valueCondition) {
        int page = 1;
        boolean completedBoolean = false;
        IPage<WorkOrderManageDto> iPage = null;
        int conditionInt = valueCondition == null ? 0 : valueCondition.intValue();
        EvaluationResultTaskEntity taskEntity = new EvaluationResultTaskEntity();
        while (true) {
            iPage = new Page<>(page, 200);
            // 查询该用户的工单和任务
            Page<WorkOrderManageDto> pageList = workOrderManageMapper.selectByTime(iPage,  userId, tenantId, startTime, endTime);
            if (pageList == null || CollectionUtil.isEmpty(pageList.getRecords())) {
                break;
            }
            for (WorkOrderManageDto dto : pageList.getRecords()) {
                completedBoolean = EvaluationUtil.completed(dto.getOrderStatus());
                taskEntity.setTotalCount(taskEntity.getTotalCount() + 1);
                taskEntity.setCompleteCount(taskEntity.getCompleteCount() + (completedBoolean ? 1 : 0));
                taskEntity.setNoCompleteCount(taskEntity.getNoCompleteCount() + (!completedBoolean ? 1 : 0));
                // 计算完成的是否属于延期完成
                if (completedBoolean && isDelay(dto, EvaluationUtil.minute(dto.getDateLimit())  + conditionInt)) {
                    taskEntity.setDelayCompleteCount(taskEntity.getDelayCompleteCount() + 1);
                }
            }
            page ++;
        }
        // 计算完成率和延期率
        taskEntity.setCompletionRate(EvaluationUtil.divide(taskEntity.getCompleteCount(),taskEntity.getTotalCount(), 4));
        taskEntity.setDelayRate(EvaluationUtil.divide(taskEntity.getDelayCompleteCount(),taskEntity.getTotalCount(), 4));
        taskEntity.setTenantId(tenantId);
        taskEntity.setStatus(1);
        taskEntity.setDateCreate(new Date());
        return taskEntity;
    }

    /***
     * 是否过期
     * 任务：
     *    开始时间：date_create
     *    计划完成时间：plan_end_date  + " 23:59:59"
     *    完成时间：finish_date
     * 工单：
     *    开始时间： date_create
     *    计划完成时间： send_time + date_limit分钟
     *    完成时间：finish_date
     * @author lihui
     * @date 10:56 2021/5/20
     * @param dto : 请求参数
     * @param addMinute : 增加的分钟数
     * @return boolean
     **/
    private boolean isDelay(WorkOrderManageDto dto, int addMinute){
        // 工单时间
        Date planFinishDate = dto.getSendTime();
        // 任务时间
        if (!EvaluationUtil.isWork(dto.getOrderTypeId())) {
            if (dto.getPlanFinishDate() == null) {
                return false;
            }
            planFinishDate = DatesUtil.parseDate(DatesUtil.formatDate(dto.getPlanFinishDate(), "yyyy-MM-dd") + " 23:59:59",
                    "yyyy-MM-dd HH:mm:ss");
        }
        return EvaluationUtil.isDelay(dto.getFinishDate(), planFinishDate, addMinute);
    }

    /**
     * @Author lihui
     * @Description 获取部门考评项
     * @Date 17:36 2021/5/10
     * @Param [userEntity]
     * @return java.util.List<com.zcxk.evaluation.entity.EvaluationItemEntity>
     **/
    private List<EvaluationItemVo> findItem(UserEntity userEntity){
        Integer companyOrgId = EvaluationUtil.toInteger(userEntity.getCompanyOrgId());
        Integer deptOrgId    = EvaluationUtil.toInteger(userEntity.getDeptOrgId());
        String  tenantId = userEntity.getTenantId();
        String key = tenantId + "_" + companyOrgId + "_" + deptOrgId;
        List<EvaluationItemVo> itemVos = itemMap.get(key);
        if (itemVos != null) {
            return  itemVos;
        }
        EvaluationItemEntity queryItem = new EvaluationItemEntity();
        queryItem.setCompanyOrgId(companyOrgId);
        queryItem.setDeptOrgId(deptOrgId);
        queryItem.setTenantId(tenantId);
        itemVos = evaluationItemMapper.findListItem(queryItem);
        itemMap.put(key, itemVos);
        return itemVos;
    }


    /***
     * 组装考评结果数据
     * @author lihui
     * @date 11:47 2021/5/11
     * @param userEntity : 用户信息
     * @param cycle :      月度、季度、年度
     * @param startTime :  开始时间
     * @param endTime :    结束时间
     * @return com.zcxk.evaluation.entity.EvaluationResultEntity
     **/
    private EvaluationResultEntity packagesEvaluationResultEntity(UserEntity userEntity, Integer cycle, String startTime, String endTime){
        LocalDate localDate = EvaluationUtil.getLocalDateByCycle(startTime, endTime, cycle);
        EvaluationResultEntity resultEntity = new EvaluationResultEntity();
        resultEntity.setYear(localDate.getYear());
        resultEntity.setMonth(localDate.getMonthValue());
        resultEntity.setEvaluationBe(userEntity.getUsername());
        resultEntity.setEvaluationBeUserId(userEntity.getId());
        resultEntity.setCycle(cycle);
        resultEntity.setState(0);
        resultEntity.setDateStart(DatesUtil.parseDate(startTime, "yyyy-MM-dd HH:mm:ss"));
        resultEntity.setDateEnd(DatesUtil.parseDate(endTime, "yyyy-MM-dd HH:mm:ss"));
        resultEntity.setTenantId(userEntity.getTenantId());
        resultEntity.setCompanyOrgId(EvaluationUtil.toInteger(userEntity.getCompanyOrgId()));
        resultEntity.setDeptOrgId(EvaluationUtil.toInteger(userEntity.getDeptOrgId()));
        resultEntity.setDateCreate(new Date());
        resultEntity.setStatus(1);
        return resultEntity;
    }

    /***
     * 获取对应的分数
     * @author lihui
     * @Date 10:32 2021/5/19
     * @param item  : 考评项目设置内容
     * @param evaluationValue  : 统计到的分值
     * @return java.math.BigDecimal 分数
     **/
    private BigDecimal getScore (EvaluationItemVo item, BigDecimal evaluationValue){
        // 如果是自定义直接返回默认分数
        if (item.getType() == EvaluationItemEnums.CUSTOM.getType()) {
            return item.getValue();
        }
        Integer itemType     = null;
        BigDecimal itemValue = null;
        BigDecimal valueOne  = null;
        BigDecimal valueTwo  = null;
        for (EvaluationItemValueVo evaluationItemValueVo: item.getEvaluationItemValueVoList()) {
            itemType  = evaluationItemValueVo.getItemType();
            itemValue = evaluationItemValueVo.getItemValue();
            valueOne  = evaluationItemValueVo.getValueOne();
            valueTwo  = evaluationItemValueVo.getValueTwo();
            // 大于等于 0大于等于 2小于 1介于
            if (itemType == 0 && evaluationValue.compareTo(valueOne) > -1) {
                return itemValue;
            }
            // 小于
            if (itemType == 2 &&  evaluationValue.compareTo(valueOne) == -1) {
                return itemValue;
            }
            // 介于 ： 比如取8-10，就是≥8，＜10
            if (itemType == 1 && evaluationValue.compareTo(valueOne) > -1  && evaluationValue.compareTo(valueTwo) == -1) {
                return itemValue;
            }
        }
        return new BigDecimal("0");
    }

    /**
     * @Author lihui
     * @Description 获取任务按时完成率设定的条件值
     * @Date 9:40 2021/5/11
     * @Param [itemEntityList]
     * @return java.math.BigDecimal
     **/
    private BigDecimal getValueCondition(List<EvaluationItemVo> itemEntityList){
        for (EvaluationItemVo evaluationItemVo: itemEntityList) {
            if (evaluationItemVo.getType() == EvaluationItemEnums.COMPLETION_RATE.getType()) {
                return evaluationItemVo.getValueCondition();
            }
        }
        return null;
    }


    public static void main(String[] args) {
        System.out.println(String.format("%02d",3));
    }


}
