package cn.wise.sc.cement.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.wise.sc.cement.business.entity.*;
import cn.wise.sc.cement.business.mapper.NormProductionMapper;
import cn.wise.sc.cement.business.model.BaseResponse;
import cn.wise.sc.cement.business.model.PageQuery;
import cn.wise.sc.cement.business.model.vo.NormProductionVo;
import cn.wise.sc.cement.business.model.vo.ProductionVo;
import cn.wise.sc.cement.business.model.vo.WorkloadStatisticsVo;
import cn.wise.sc.cement.business.service.*;
import cn.wise.sc.cement.business.util.ExcelUtil;
import cn.wise.sc.cement.business.util.RedisUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author ztw
 * @since 2020-09-23
 */
@Service
public class NormProductionServiceImpl extends ServiceImpl<NormProductionMapper, NormProduction> implements INormProductionService {

    /**
     * 标准产值配置信息  缓存
     */
    final public Map<String, NormProduction> normProductionCache = new HashMap<>();
    /**
     *
     */
    final String CALCULATE_HANDLE = "CALCULATE_HANDLE";
    final String CALCULATE_DISTRIBUTION = "CALCULATE_DISTRIBUTION";

    final
    ISampleDistributionService iSampleDistributionService;
    final
    ISampleHandleService iSampleHandleService;
    final
    ISysUserService iSysUserService;
    final
    ISysGroupService iSysGroupService;
    final
    ISampleCheckTeamService iSampleCheckTeamService;
    final
    ITeamGroupService iTeamGroupService;
    final
    IHandleService iHandleService;
    final
    ISysPostService iSysPostService;
    final
    INonStandardValueService iNonStandardValueService;
    final
    INonStandardApplyService iNonStandardApplyService;
    final
    RedisUtil redisUtil;

    public NormProductionServiceImpl(ISampleDistributionService iSampleDistributionService,
                                     ISampleHandleService iSampleHandleService,
                                     ISysUserService iSysUserService,
                                     ISysGroupService iSysGroupService,
                                     ISampleCheckTeamService iSampleCheckTeamService,
                                     ITeamGroupService iTeamGroupService, IHandleService iHandleService,
                                     ISysPostService iSysPostService,
                                     INonStandardValueService iNonStandardValueService,
                                     INonStandardApplyService iNonStandardApplyService, RedisUtil redisUtil) {
        this.iSampleDistributionService = iSampleDistributionService;
        this.iSampleHandleService = iSampleHandleService;
        this.iSysUserService = iSysUserService;
        this.iSysGroupService = iSysGroupService;
        this.iSampleCheckTeamService = iSampleCheckTeamService;
        this.iTeamGroupService = iTeamGroupService;
        this.iHandleService = iHandleService;
        this.iSysPostService = iSysPostService;
        this.iNonStandardValueService = iNonStandardValueService;
        this.iNonStandardApplyService = iNonStandardApplyService;
        this.redisUtil = redisUtil;
    }

    @Override
    public BaseResponse<NormProduction> addObj(NormProduction normProduction) {

        //判断配置项目是否已存在
        QueryWrapper<NormProduction> qw = new QueryWrapper<>();
        qw.eq("assess_id", normProduction.getAssessId());
        qw.eq("type", normProduction.getType());
        qw.eq("status", 1);
        int count = this.count(qw);
        if (count != 0) {
            return BaseResponse.errorMsg("当前标准产值已存在!");
        }
        //判断比例是否为总值100%
        if (normProduction.getAnalyseRate()
                + normProduction.getAssessRate()
                + normProduction.getSeparateRate()
                + normProduction.getReportedResultRate() != 1) {
            return BaseResponse.errorMsg("百分比总和不等于1");
        }

        //状态为1
        normProduction.setStatus(1);
        boolean save = this.save(normProduction);
        if (save) {
            return BaseResponse.okData(normProduction);
        } else {
            return BaseResponse.errorMsg("失败!除检测组id之外其他字段必填!");
        }
    }

    @Override
    public BaseResponse<IPage<NormProductionVo>> getPage(PageQuery pageQuery) {

        IPage<NormProduction> page = new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize());
        IPage<NormProduction> productionIPage = this.page(page);
        //关联名字
        List<NormProduction> normProductions = productionIPage.getRecords();
        List<Integer> npTeamGroupIds = new ArrayList<>(normProductions.size());
        List<Integer> npHandleIds = new ArrayList<>(normProductions.size());
        normProductions.forEach(arg -> {
            if (arg.getType() == 1) {
                npTeamGroupIds.add(arg.getAssessId());
            } else {
                npHandleIds.add(arg.getAssessId());
            }
        });
        if (npTeamGroupIds.size() == 0 && npHandleIds.size() == 0) {
            return BaseResponse.errorMsg("没找着相关数据!关联检测组失败!");
        }
        List<Handle> handles = new ArrayList<>();
        if (npHandleIds.size() != 0) {
            handles = iHandleService.listByIds(npHandleIds);
        }
        List<TeamGroup> teamGroups = new ArrayList<>();
        if (npTeamGroupIds.size() != 0) {
            teamGroups = iTeamGroupService.listByIds(npTeamGroupIds);
        }
        IPage<NormProductionVo> rts = new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize());
        List<NormProductionVo> records = new ArrayList<>(pageQuery.getPageSize());
        rts.setTotal(productionIPage.getTotal());
        rts.setCurrent(productionIPage.getCurrent());
        rts.setPages(productionIPage.getPages());
        rts.setSize(productionIPage.getSize());
        List<TeamGroup> finalTeamGroups = teamGroups;
        List<Handle> finalHandles = handles;
        normProductions.forEach(arg -> {
            NormProductionVo normProductionVo = new NormProductionVo();
            BeanUtil.copyProperties(arg, normProductionVo);
            normProductionVo.setAssessName("/");
            if (arg.getType() == 1) {
                finalTeamGroups.stream()
                        .filter(opt -> opt.getId().intValue() == arg.getAssessId())
                        .findFirst()
                        .ifPresent(opt -> normProductionVo.setAssessName(opt.getName()));
            } else {
                finalHandles.stream()
                        .filter(opt -> opt.getId().intValue() == arg.getAssessId())
                        .findFirst()
                        .ifPresent(opt -> normProductionVo.setAssessName(opt.getName()));
            }
            if (arg.getType() == 1) {
                normProductionVo.setType("检测项");
            } else {
                normProductionVo.setType("处理项");
            }
            records.add(normProductionVo);
        });
        rts.setRecords(records);
        return BaseResponse.okData(rts);
    }

    @Override
    public BaseResponse<Boolean> edit(NormProduction production) {

        if (production.getId() == null || production.getId() <= 0) {
            return BaseResponse.errorMsg("编号id是必须的!");
        }

        //判断比例是否为总值100%
        if (production.getAnalyseRate()
                + production.getAssessRate()
                + production.getSeparateRate()
                + production.getReportedResultRate() != 1) {
            return BaseResponse.errorMsg("百分比总和不等于1");
        }

        //判断配置项目是否已存在
        QueryWrapper<NormProduction> qw = new QueryWrapper<>();
        qw.eq("assess_id", production.getAssessId());
        qw.eq("type", production.getType());
        qw.eq("status", 1);
        NormProduction one = this.getOne(qw);
        if (one != null && one.getId().intValue() != production.getId()) {
            return BaseResponse.errorMsg("当前标准产值已存在!");
        }

        boolean b = this.updateById(production);
        if (b) {
            return BaseResponse.okData(true);
        } else {
            return BaseResponse.errorMsg("修改失败!");
        }

    }

    @Override
    public BaseResponse<Integer> activeOrForbidden(Integer id) {

        NormProduction normProduction = this.getById(id);
        Integer status = normProduction.getStatus();
        if (status == 1) {
            normProduction.setStatus(0);
            this.updateById(normProduction);
            return BaseResponse.okData(0);
        } else {
            normProduction.setStatus(1);
            this.updateById(normProduction);
            return BaseResponse.okData(1);
        }

    }

    @Override
    public BaseResponse<List<NormProductionStatistics>> normProductionStatistics(Long start, Long end, String name, Integer groupId) {

        //统计分样处理的详情
        List<NormProduction.NormProductionDetail> normProductionDetails =
                normProductionDetails(null, start, end);

        if (normProductionDetails.size() == 0) {
            BaseResponse<List<NormProductionStatistics>> rts = BaseResponse.okData(null);
            rts.setData(new ArrayList<>());
            return rts;
        }

        Map<Integer, BigDecimal> coefficientMap = new HashMap<>(normProductionDetails.size());
        normProductionDetails
                .forEach(arg -> {
                    Integer userId = arg.getUserId();
                    //不存在 添加
                    if (!coefficientMap.containsKey(userId)) {
                        coefficientMap.put(userId, arg.getWorkTimeCoefficient());
                    } else {
                        BigDecimal bigDecimal = coefficientMap.get(userId);
                        BigDecimal newWorkTime = arg.getWorkTimeCoefficient().add(bigDecimal);
                        coefficientMap.put(userId, newWorkTime);
                    }
                });
        List<NormProductionStatistics> rts = new ArrayList<>();
        Set<Integer> userIds = coefficientMap.keySet();
        QueryWrapper<SysUser> qw = new QueryWrapper<>();
        qw.in("id", userIds);
        List<SysUser> users = iSysUserService.list(qw);
        List<SysPost> sysPosts = iSysPostService.list();
        List<SysGroup> sysGroups = iSysGroupService.list();
        for (Integer userId : coefficientMap.keySet()) {
            SysUser sysUser = users.stream()
                    .filter(arg -> arg.getId().intValue() == userId)
                    .findFirst().orElse(null);
            SysGroup sysGroup = sysGroups.stream().filter(arg -> arg.getId().intValue() == userId)
                    .findFirst().orElse(null);
            if (sysUser == null) {
                continue;
            }
            if (sysGroup == null) {
                log.debug("用户分组未设置!关联用户部门失败!");
                continue;
            }
            NormProductionStatistics productionStatistics = new NormProductionStatistics();
            productionStatistics.setAccount(sysUser.getUsername());
            productionStatistics.setCoefficient(coefficientMap.get(userId).doubleValue());
            productionStatistics.setTime("/");
            productionStatistics.setCount(normProductionDetails.stream()
                    .filter(arg -> arg.getUserId().intValue() == sysUser.getId())
                    .count());
            productionStatistics.setPosition(sysUser.getQualifications());
            if (start != null && end != null) {
                DateTime startTime = DateUtil.date(start);
                DateTime endTime = DateUtil.date(end);
                productionStatistics.setTime(startTime.toDateStr() + "-" + endTime.toDateStr());
            }
            productionStatistics.setSex(sysUser.getSex() == 0 ? "女" : "男");
            productionStatistics.setUserId(sysUser.getId() + "");
            productionStatistics.setUserName(sysUser.getName());
            productionStatistics.setGroupId(sysUser.getGroupId());
            productionStatistics.setGroupName(sysGroup.getName());

            SysPost sysPost = sysPosts.stream()
                    .filter(arg -> arg.getId().intValue() == sysUser.getPostId()).
                            findFirst().orElse(null);

            productionStatistics.setPosition(sysPost == null ? "职务一" : sysPost.getName());
            productionStatistics.setGroupName(sysGroup.getName());
            rts.add(productionStatistics);
        }

        //过滤名字
        if (StrUtil.isNotBlank(name)) {
            List<NormProductionStatistics> collect = rts.stream().filter(arg -> arg.getUserName().contains(name)).collect(Collectors.toList());
            return BaseResponse.okData(collect);
        }

        //过滤部门id
        if (groupId != null) {
            List<NormProductionStatistics> collect = rts.stream().filter(arg -> arg.getGroupId().equals(groupId)).collect(Collectors.toList());
            return BaseResponse.okData(collect);
        }

        return BaseResponse.okData(rts);
    }

    @Override
    public List<NormProduction.NormProductionDetail> normProductionDetails(
            Integer userId, Long start, Long end) {
        /*
         * 计算的地方:  分样派发和分样处理表
         *   userId == null,计算所有人数据。
         *   userId != null,计算单人时间线的数据。
         *   当start==0&&end==0时计算历史所有数据
         *
         * 过程:
         *   1.获取分样派发表数据,然后获取标准产值配置,它的检测组相同。
         *   3.每条记录*标准产值计算出来的结果。==>得出详情信息。
         * 处理项目:
         *   1.获取处理派发表数据,获取标准产值配置,查询处理项。
         * */
        //获取标准产值数据
        Map<String, Object> params = new HashMap<>(2);
        if (userId != null && userId > 0) {
            params.put("user_id", userId);
        }
        if (start != null && end != null) {
            DateTime startTime = DateUtil.date(start);
            DateTime endTime = DateUtil.date(end);
            params.put("start_time", DateUtil.format(startTime, "yyyy-MM-dd"));
            params.put("end_time", DateUtil.format(endTime, "yyyy-MM-dd"));
        }
        //计算分析任务单产值
        List<NormProduction.NormProductionDetail> sampleDistributionDetail = calculateSampleDistributionOptimize(params);
        //计算处理任务单产值
        List<NormProduction.NormProductionDetail> sampleHandleDetail = calculateSampleHandleOptimize(params);

        //todo 计算校核任务单产值
//        List<NormProduction.NormProductionDetail> sampleCheckTeamDetail = calculateSampleCheck(qwCT);
        //todo 计算报出结果产值
        List<NormProduction.NormProductionDetail> rts = new ArrayList<>(
                sampleDistributionDetail.size()
                        + sampleHandleDetail.size());
        rts.addAll(sampleDistributionDetail);
        rts.addAll(sampleHandleDetail);

        //关联用户名字
        List<Integer> userIds = rts.stream()
                .map(NormProduction.NormProductionDetail::getUserId)
                .collect(Collectors.toList());

        if (userIds.size() == 0) {
            return new ArrayList<>();
        }
        List<SysUser> users = iSysUserService.listByIds(userIds);
        rts.forEach(arg -> users.stream()
                .filter(opt -> opt.getId().intValue() == arg.getUserId())
                .findFirst()
                .ifPresent(sysUser -> arg.setUserName(sysUser.getName())));

        return rts;
    }

    @Override
    public List<ProductionVo> production(String name, Long start, Long end, Integer groupId) {


        Date startDate = null;
        Date endDate = new Date();
        if (start != null && start != 0) {
            startDate = DateUtil.date(start);
        }
        if (end != null && end != 0) {
            endDate = DateUtil.date(end);
        }

        //非标准产值
        List<NonStandardValue> nonStandardValues = iNonStandardValueService.nonValue(startDate, endDate, groupId,name).getData();
        //标准产值
        List<NormProductionStatistics> productionStatistics = this.normProductionStatistics(start, end, name, groupId).getData();

        //以userId找关系
        Set<String> userIds = new HashSet<>();
        nonStandardValues.forEach(arg -> userIds.add(arg.getUserId() + ""));
        productionStatistics.forEach(arg -> userIds.add(arg.getUserId()));
        List<ProductionVo> rts = new ArrayList<>(userIds.size());
        userIds.forEach(arg -> {
            ProductionVo productionVo = new ProductionVo();
            productionVo.setUserId(arg);
            //找到标准准产值里面的数据
            productionStatistics.forEach(opt -> {
                if (opt.getUserId().equals(arg)) {
                    productionVo.setProductionValue(opt.getCoefficient());
                    productionVo.setUserName(opt.getUserName());
                    productionVo.setPosition(opt.getPosition());
                    productionVo.setAccount(opt.getAccount());
                    productionVo.setGroupId(opt.getGroupId());
                    productionVo.setGroupName(opt.getGroupName());
                }
            });
            //找到标准产值里面的数据
            nonStandardValues.forEach(opt -> {
                if (arg.equals(opt.getUserId() + "")) {
                    productionVo.setNonProductionValue(opt.getFinalValue());
                }
            });
            rts.add(productionVo);
        });
        //处理非标准产值没有用名职位信息
        QueryWrapper<SysUser> qw = new QueryWrapper<>();
        qw.in("id", userIds);
        if (CollectionUtil.isEmpty(userIds)) {
            return null;
        }
        List<SysUser> users = iSysUserService.list(qw);
        List<SysPost> sysPosts = iSysPostService.list();
        List<SysGroup> sysGroups = iSysGroupService.list();
        Date finalStartDate = startDate;
        Date finalEndDate = endDate;
        rts.forEach(arg -> {
            arg.setTime(finalStartDate == null ? "/" : DateUtil.format(finalStartDate, "yyyy-MM-dd") + "--" + DateUtil.format(finalEndDate, "yyyy-MM-dd"));
            if (StrUtil.isBlank(arg.getUserName())) {
                //关联用户信息
                users.stream().filter(opt -> arg.getUserId().equals(opt.getId() + "")).findFirst()
                        .ifPresent(opt -> {
                            arg.setUserName(opt.getName());
                            arg.setAccount(opt.getUsername());
                            arg.setPositionId(opt.getPostId());
                            arg.setGroupId(opt.getGroupId());
                        });
                //关联职务
                sysPosts.stream().filter(opt -> arg.getPositionId().intValue() == opt.getId())
                        .findFirst()
                        .ifPresent(opt -> arg.setPosition(opt.getName()));

                sysGroups.stream().filter(opt -> arg.getGroupId().intValue() == opt.getId())
                        .findFirst()
                        .ifPresent(opt -> arg.setGroupName(opt.getName()));
            }
            arg.setProductionTotalValue(arg.getNonProductionValue() + arg.getProductionValue());
        });
        //过滤名字
        if (StrUtil.isNotBlank(name)) {
            return rts.stream().filter(arg -> arg.getUserName().contains(name))
                    .collect(Collectors.toList());
        }

        //过滤部门id
        if (groupId != null) {
            return rts.stream().filter(arg -> arg.getGroupId().equals(groupId))
                    .collect(Collectors.toList());
        }

        return rts;
    }


    @Override
    public void exportNormProductionStatistics(Long start, Long end, String name, Integer groupId, HttpServletResponse response) {
        BaseResponse<List<NormProductionStatistics>> listBaseResponse = normProductionStatistics(start, end, name, groupId);
        if (listBaseResponse.getCode() == 200) {
            List<NormProductionStatistics> data = listBaseResponse.getData();
            if (CollectionUtil.isNotEmpty(data)) {
                String[] headers = new String[10];
                headers[0] = "用户编号";
                headers[1] = "用户名";
                headers[2] = "账号";
                headers[3] = "性别";
                headers[4] = "职务";
                headers[5] = "统计时间";
                headers[6] = "检测项目数";
                headers[7] = "产值绩效";
                headers[8] = "部门id";
                headers[9] = "部门名";

                List<Object[]> exportData = new ArrayList<>(data.size());
                for (NormProductionStatistics productionStatistics : data) {
                    Object[] objs = new Object[10];
                    objs[0] = productionStatistics.getUserId();
                    objs[1] = productionStatistics.getUserName();
                    objs[2] = productionStatistics.getAccount();
                    objs[3] = productionStatistics.getSex();
                    objs[4] = productionStatistics.getPosition();
                    objs[5] = productionStatistics.getTime();
                    objs[6] = productionStatistics.getCount();
                    objs[7] = productionStatistics.getCoefficient();
                    objs[8] = productionStatistics.getGroupId();
                    objs[9] = productionStatistics.getGroupName();
                    exportData.add(objs);
                }
                ExcelUtil.excelExport(
                        "标准产值统计", headers,
                        exportData, response);
            }
        }
    }

    @Override
    public void exportNormProductionDetail(Integer userId, Long startTime, Long endTime, HttpServletResponse response) {
        List<NormProduction.NormProductionDetail> normProductionDetails = normProductionDetails(userId, startTime, endTime);
        if (CollectionUtil.isNotEmpty(normProductionDetails)) {
            String[] headers = new String[13];
            headers[0] = "序号";
            headers[1] = "名字";
            headers[2] = "检测项目";
            headers[3] = "所属项目";
            headers[4] = "项目编号";
            headers[5] = "检测时间";
            headers[6] = "分析占比";
            headers[7] = "分样占比";
            headers[8] = "校核占比";
            headers[9] = "报结果占比";
            headers[10] = "合计";
            List<Object[]> exportData = new ArrayList<>(normProductionDetails.size());
            int count = 0;
            DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 hh:mm:ss");
            for (NormProduction.NormProductionDetail target : normProductionDetails) {
                Object[] objs = new Object[13];
                objs[0] = count++;
                objs[1] = target.getUserName();
                objs[2] = target.getGroupTeamName();
                objs[3] = target.getProjectName();
                objs[4] = target.getEntrustCode();
                objs[5] = target.getCheckTime() == null ? "/" : target.getCheckTime().format(timeFormatter);
                objs[6] = target.getAnalyseRate();
                objs[7] = target.getSeparateRate();
                objs[8] = target.getAssessRate();
                objs[9] = target.getReportedResultRate();
                objs[10] = target.getWorkTimeCoefficient();
                exportData.add(objs);
            }
            ExcelUtil.excelExport("标准产值详情—" + normProductionDetails.get(0).getUserName(), headers, exportData, response);
        }
    }

    @Override
    public void exportProduction(String name, Long startTime, Long endTime, Integer groupId, HttpServletResponse response) {
        List<ProductionVo> data = production(name, startTime, endTime, groupId);
        if (CollectionUtil.isNotEmpty(data)) {
            String[] headers = new String[10];
            headers[0] = "序号";
            headers[1] = "姓名";
            headers[2] = "账户";
            headers[3] = "职务";
            headers[4] = "统计时间";
            headers[5] = "标准产值";
            headers[6] = "非标准产值";
            headers[7] = "产值统计";
            headers[8] = "部门id";
            headers[9] = "部门名";
            List<Object[]> exportData = new ArrayList<>(data.size());
            int count = 0;
            for (ProductionVo target : data) {
                Object[] objs = new Object[10];
                objs[0] = count++;
                objs[1] = target.getUserName();
                objs[2] = target.getAccount();
                objs[3] = target.getPosition();
                objs[4] = target.getTime();
                objs[5] = target.getProductionValue();
                objs[6] = target.getNonProductionValue();
                objs[7] = target.getProductionTotalValue();
                objs[8] = target.getGroupId();
                objs[9] = target.getGroupName();
                exportData.add(objs);
            }
            ExcelUtil.excelExport("产值统计", headers, exportData, response);
        }
    }

    @Override
    public List<WorkloadStatisticsVo> workloadStatistics(Date startTime, Date endTime, Integer userId) {

        long start = getDefaultStart(startTime == null ? 0 : startTime.getTime());
        long end = getDefaultEnd(endTime.getTime());
        Map<String, Integer> map1 = initMonthMoneyMap(start, end);
        Map<String, Integer> map2 = initMonthMoneyMap(start, end);

        QueryWrapper<SampleDistribution> qw = new QueryWrapper<>();
        if (startTime != null) {
            qw.ge("finish_time", DateUtil.format(DateUtil.date(start), "yyyy-MM-dd"));
        }
        if (userId != null && userId != 0) {
            qw.eq("user_id", userId);
        }
        qw.le("finish_time", DateUtil.format(DateUtil.date(end), "yyyy-MM-dd"));
        qw.eq("status", 2);
        List<SampleDistribution> sampleDistributions = iSampleDistributionService.list(qw);

        QueryWrapper<NonStandardApply> qwA = new QueryWrapper<>();
        if (startTime != null) {
            qwA.ge("start_time", DateUtil.format(DateUtil.date(start), "yyyy-MM-dd"));
        }
        if (userId != null && userId != 0) {
            qwA.eq("user_id", userId);
        }
        qwA.le("start_time", DateUtil.format(DateUtil.date(end), "yyyy-MM-dd"));
        qwA.eq("status", 2);
        List<NonStandardApply> nonStandardApplies = iNonStandardApplyService.list(qwA);

        for (SampleDistribution sampleDistribution : sampleDistributions) {
            addCount(sampleDistribution.getFinishTime(), map1);
        }
        for (NonStandardApply nonStandardApply : nonStandardApplies) {
            addCount(nonStandardApply.getStartTime(), map2);
        }

        WorkloadStatisticsVo workloadStatisticsVo = new WorkloadStatisticsVo();
        workloadStatisticsVo.setType(0);
        workloadStatisticsVo.setMap(map1);
        WorkloadStatisticsVo workloadStatisticsVo2 = new WorkloadStatisticsVo();
        workloadStatisticsVo2.setType(1);
        workloadStatisticsVo2.setMap(map2);
        List<WorkloadStatisticsVo> rts = new ArrayList<>(2);
        rts.add(workloadStatisticsVo);
        rts.add(workloadStatisticsVo2);

        return rts;
    }

    private void addCount(LocalDateTime date, Map<String, Integer> map) {
        Date nextDate = DateUtil.endOfMonth(asDate(date));
        map.put(nextDate.getMonth() + 1 + "", map.get(nextDate.getMonth() + 1 + "") + 1);
    }

    private void addCount(LocalDate date, Map<String, Integer> map) {
        Date nextDate = DateUtil.endOfMonth(asDate(date));
        map.put(nextDate.getMonth() + 1 + "", map.get(nextDate.getMonth() + 1 + "") + 1);
    }

    private static Date asDate(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    private static Date asDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    private Map<String, Integer> initMonthMoneyMap(long start, long end) {

        Map<String, Integer> map = new LinkedHashMap();
        for (long i = start; i <= end; i = DateUtil.offsetMonth(DateUtil.date(i), 1).getTime()) {
            map.put(DateUtil.endOfMonth(DateUtil.date(i)).getMonth() + 1 + "", 0);
        }

        return map;
    }

    private static long getDefaultStart(long start) {
        //如果没传时间进来   默认开始时间是今天开始时间
        if (start == 0) {
            start = System.currentTimeMillis();
            start = DateUtil.beginOfYear(DateUtil.date(start)).getTime();
        }

        return start;
    }

    private static long getDefaultEnd(long end) {
        //如果没传时间进来   默认开始时间是今天开始时间
        if (end == 0) {
            end = System.currentTimeMillis();
            end = DateUtil.endOfYear(DateUtil.date(end)).getTime();
        }
        return end;
    }

    /**
     * 计算处理派发单每条数据的标准产值
     * （已有替代方法）
     *
     * @param qwHan 统计条件
     * @return 处理任务详情
     * @Deprecated 已废弃
     * @see NormProductionServiceImpl#calculateSampleHandleOptimize(Map)
     */
    @Deprecated
    private List<NormProduction.NormProductionDetail> calculateSampleHandle(QueryWrapper<SampleHandle> qwHan) {
        //计算处理的绩效
        List<SampleHandle> sampleHandles = iSampleHandleService.list(qwHan);
        List<EntrustSample> entrustSamples = iSampleHandleService.getEntrustSample();
        List<NormProduction.NormProductionDetail> rts = new ArrayList<>(sampleHandles.size());
        List<Integer> handleIds = new ArrayList<>();
        //处理项id
        sampleHandles.forEach(arg -> {
            try {
                handleIds.add(arg.getHandleId());
            } catch (NumberFormatException ex) {
                throw new RuntimeException("处理项目的id传的有问题呀!");
            }
        });
        if (handleIds.size() == 0) {
            return new ArrayList<>();
        }
        List<Handle> handles = iHandleService.listByIds(handleIds);
        //获取每一次派发单的数据
        for (SampleHandle sampleHandle : sampleHandles) {
            //判断是否已经配置了
            EntrustSample entrustSample = entrustSamples.stream()
                    .filter(arg -> arg.getDistributionId().intValue() == sampleHandle.getId())
                    .findFirst().orElse(null);
            if (entrustSample == null) {
                continue;
            }
            //处理项是多个处理ids  、分割
            List<Integer> ids = new ArrayList<>();
            try {
              ids.add(sampleHandle.getHandleId());
            } catch (NumberFormatException ex) {
                throw new RuntimeException("处理项目的id传的有问题呀!");
            }
            for (Integer handleId : ids) {
                String key = handleId + ":" + "0";
                //判断缓存是否存在
                if (!normProductionCache.containsKey(key)) {
                    //初始化
                    initNormProductionCache();
                }
                NormProduction normProduction = normProductionCache.get(key);
                Handle handle = handles.stream()
                        .filter(arg -> arg.getId().intValue() == handleId)
                        .findFirst().orElse(null);
                if (normProduction == null || handle == null) {
                    //如果没有配置 标准产值设置  跳过不计算
                    continue;
                }
                NormProduction.NormProductionDetail productionDetail =
                        initNormProductionDetail(entrustSample, normProduction, normProduction.getAnalyseRate());
                productionDetail.setUserId(sampleHandle.getUserId());
                productionDetail.setCheckTime(sampleHandle.getAcceptTime());
                productionDetail.setDistributionId(sampleHandle.getId());
                productionDetail.setAssessId(handleId);
                productionDetail.setGroupTeamName(handle.getName());
                rts.add(productionDetail);
            }

        }
        return rts;
    }


    /**
     * 计算处理派发单每条数据的标准产值
     *
     * @param params 统计条件
     * @return 处理任务详情
     */
    private List<NormProduction.NormProductionDetail> calculateSampleHandleOptimize(final Map<String, Object> params) {

        if (!redisUtil.existsKey(CALCULATE_HANDLE)) {
            //计算处理的绩效
            List<EntrustSample> entrustSamples = iSampleHandleService.getEntrustSampleOptimize(params);
            List<NormProduction.NormProductionDetail> rts = new ArrayList<>(entrustSamples.size());
            List<Integer> handleIds = new ArrayList<>();
            //处理项id
            entrustSamples.forEach(arg -> {
                String idsStr = arg.getContent();
                String[] split = idsStr.split("、");
                try {
                    for (String idStr : split) {
                        handleIds.add(Integer.parseInt(idStr));
                    }
                } catch (NumberFormatException ex) {
                    throw new RuntimeException("处理项目的id传的有问题呀!");
                }
            });
            if (handleIds.size() == 0) {
                return new ArrayList<>();
            }

            List<Handle> handles = iHandleService.listByIds(handleIds);

            for (EntrustSample entrustSample : entrustSamples) {
                String content = entrustSample.getContent();
                String[] split = content.split("、");
                List<Integer> ids = new ArrayList<>(split.length);
                try {
                    for (String idStr : split) {
                        ids.add(Integer.parseInt(idStr));
                    }
                } catch (NumberFormatException ex) {
                    throw new RuntimeException("处理项目的id传的有问题呀!");
                }
                for (Integer handleId : ids) {
                    String key = handleId + ":" + "0";
                    //判断缓存是否存在
                    if (!normProductionCache.containsKey(key)) {
                        //初始化
                        initNormProductionCache();
                    }
                    NormProduction normProduction = normProductionCache.get(key);
                    Handle handle = handles.stream()
                            .filter(arg -> arg.getId().intValue() == handleId)
                            .findFirst().orElse(null);
                    if (normProduction == null || handle == null) {
                        //如果没有配置 标准产值设置  跳过不计算
                        continue;
                    }
                    NormProduction.NormProductionDetail productionDetail =
                            initNormProductionDetail(entrustSample, normProduction, normProduction.getAnalyseRate());
                    productionDetail.setUserId(entrustSample.getUserId());
                    productionDetail.setCheckTime(entrustSample.getFinishTime());
                    productionDetail.setDistributionId(entrustSample.getDistributionId());
                    productionDetail.setAssessId(handleId);
                    productionDetail.setGroupTeamName(handle.getName());
                    rts.add(productionDetail);
                }
            }
            redisUtil.setListAll(CALCULATE_HANDLE, JSON.toJSONString(rts), 6000);
        }

        return JSON.parseArray(redisUtil.getString(CALCULATE_HANDLE) + "", NormProduction.NormProductionDetail.class);
    }

    /**
     * 计算分析派发单每条数据的标准产值
     * 优化版本
     *
     * @param param 统计条件
     * @return 分析任务详情
     */
    private List<NormProduction.NormProductionDetail> calculateSampleDistributionOptimize
    (Map<String, Object> param) {


        if (!redisUtil.existsKey(CALCULATE_DISTRIBUTION)) {

            List<EntrustSample> entrustSamples = iSampleDistributionService.getSampleDistribution(param);

            List<NormProduction.NormProductionDetail> rts = new ArrayList<>(entrustSamples.size());
            List<Integer> groupTeamIds = entrustSamples.stream().map(EntrustSample::getTeamGroupId).collect(Collectors.toList());
            if (groupTeamIds.size() == 0) {
                return new ArrayList<>();
            }
            List<TeamGroup> teamGroups = iTeamGroupService.listByIds(groupTeamIds);

            for (EntrustSample entrustSample : entrustSamples) {
                TeamGroup teamGroup = teamGroups.stream()
                        .filter(arg -> arg.getId().intValue() == entrustSample.getTeamGroupId())
                        .findFirst().orElse(null);
                if (entrustSample == null || teamGroup == null) {
                    continue;
                }
                String key = entrustSample.getTeamGroupId() + ":" + "1";
                //判断缓存是否存在
                if (!normProductionCache.containsKey(key)) {
                    //初始化
                    initNormProductionCache();
                }
                NormProduction normProduction = normProductionCache.get(key);
                if (normProduction == null) {
                    //如果没有配置 标准产值设置  跳过不计算
                    continue;
                }
                NormProduction.NormProductionDetail productionDetail =
                        initNormProductionDetail(entrustSample, normProduction, normProduction.getAnalyseRate());
                productionDetail.setUserId(entrustSample.getUserId());
                productionDetail.setCheckTime(entrustSample.getFinishTime());
                productionDetail.setDistributionId(entrustSample.getDistributionId());
                productionDetail.setAssessId(entrustSample.getTeamGroupId());
                productionDetail.setGroupTeamName(teamGroup.getName());
                rts.add(productionDetail);
            }
            redisUtil.setListAll(CALCULATE_DISTRIBUTION, JSON.toJSONString(rts), 6000);

        }
        return JSON.parseArray(redisUtil.getString(CALCULATE_DISTRIBUTION) + "", NormProduction.NormProductionDetail.class);

    }

    /**
     * 计算分析派发单每条数据的标准产值
     *
     * @param qwDis 统计条件
     * @return 分析任务详情
     * @Deprecated 已废弃, 有替代方法
     * @see NormProductionServiceImpl#calculateSampleDistributionOptimize
     */
    @Deprecated
    private List<NormProduction.NormProductionDetail> calculateSampleDistribution
    (QueryWrapper<SampleDistribution> qwDis) {
        List<SampleDistribution> distributions = iSampleDistributionService.list(qwDis);
        List<EntrustSample> entrustSamples = iSampleDistributionService.getEntrustSample();
        List<NormProduction.NormProductionDetail> rts = new ArrayList<>(distributions.size());
        List<Integer> groupTeamIds = distributions.stream().map(SampleDistribution::getTeamGroupId).collect(Collectors.toList());
        if (groupTeamIds.size() == 0) {
            return new ArrayList<>();
        }
        List<TeamGroup> teamGroups = iTeamGroupService.listByIds(groupTeamIds);
        //获取每一次派发单的数据
        for (SampleDistribution distribution : distributions) {
            //判断是否已经配置了
            EntrustSample entrustSample = entrustSamples.stream()
                    .filter(arg -> arg.getDistributionId().intValue() == distribution.getId())
                    .findFirst().orElse(null);
            TeamGroup teamGroup = teamGroups.stream()
                    .filter(arg -> arg.getId().intValue() == distribution.getTeamGroupId())
                    .findFirst().orElse(null);
            if (entrustSample == null || teamGroup == null) {
                continue;
            }
            String key = distribution.getTeamGroupId() + ":" + "1";
            //判断缓存是否存在
            if (!normProductionCache.containsKey(key)) {
                //初始化
                initNormProductionCache();
            }
            NormProduction normProduction = normProductionCache.get(key);
            if (normProduction == null) {
                //如果没有配置 标准产值设置  跳过不计算
                continue;
            }
            NormProduction.NormProductionDetail productionDetail =
                    initNormProductionDetail(entrustSample, normProduction, normProduction.getAnalyseRate());
            productionDetail.setUserId(distribution.getUserId());
            productionDetail.setCheckTime(distribution.getAcceptTime());
            productionDetail.setDistributionId(distribution.getId());
            productionDetail.setAssessId(distribution.getTeamGroupId());
            productionDetail.setGroupTeamName(teamGroup.getName());
            rts.add(productionDetail);
        }
        return rts;
    }

    /**
     * 初始化产值明细
     *
     * @param entrustSample  分样任务
     * @param normProduction 标准产值配置表
     * @return 标准产值明细
     */
    private NormProduction.NormProductionDetail initNormProductionDetail(
            EntrustSample entrustSample, NormProduction normProduction, Double rate) {

        NormProduction.NormProductionDetail productionDetail =
                new NormProduction.NormProductionDetail();
        productionDetail.setAnalyseRate(normProduction.getAnalyseRate());
        productionDetail.setAssessRate(normProduction.getAssessRate());
        productionDetail.setSeparateRate(normProduction.getSeparateRate());
        productionDetail.setReportedResultRate(normProduction.getReportedResultRate());

        productionDetail.setAssessId(normProduction.getAssessId());
        productionDetail.setEntrustId(entrustSample.getEntrustId());
        productionDetail.setProjectName(entrustSample.getProjectName());
        productionDetail.setSampleName(entrustSample.getSampleName());
        productionDetail.setSampleId(entrustSample.getSampleId());
        productionDetail.setEntrustCode(entrustSample.getEntrustCode());
        productionDetail.setWorkTimeCoefficient(calculateWorkTimeCoefficient(normProduction,
                rate));
        return productionDetail;
    }

    /**
     * 初始化标准产值缓存
     */
    private void initNormProductionCache() {
        QueryWrapper<NormProduction> qw = new QueryWrapper<>();
        qw.eq("status", 1);
        List<NormProduction> list = this.list(qw);
        for (NormProduction normProduction : list) {
            String key = normProduction.getAssessId() + ":" + normProduction.getType();
            normProductionCache.put(key, normProduction);
        }
    }

    /**
     * 计算标准产值的工时标准系数 plan
     * 额定工日*建议系数/报出对应分析结果*考核工值*分析占比
     *
     * @param normProduction 标准产值配置对象  如:六元素
     * @param rate           具体的操作占比   如:统计分析  85%
     * @return BigDecimal
     */
    private BigDecimal calculateWorkTimeCoefficient(NormProduction normProduction, Double rate) {
        //计算出工时标准系数:
        //额定工日*建议系数/报出对应分析结果*考核工值*分析占比
        BigDecimal quotaDayBig = BigDecimal.valueOf(normProduction.getQuotaDay());
        BigDecimal coefficientBig = BigDecimal.valueOf(normProduction.getCoefficient());
        BigDecimal reportedAnalyseRtsBig = BigDecimal.valueOf(normProduction.getReportedAnalyseResult());
        BigDecimal assessValueBig = BigDecimal.valueOf(normProduction.getAssessValue());
        BigDecimal analyseRateBig = BigDecimal.valueOf(rate);
        return quotaDayBig.multiply(coefficientBig)
                .divide(reportedAnalyseRtsBig, 6, RoundingMode.HALF_DOWN)
                .multiply(assessValueBig).multiply(analyseRateBig)
                .setScale(6, RoundingMode.HALF_DOWN);
    }
}
