package com.xy.job;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xy.annotate.RestMappingController;
import com.xy.device.EnumDeviceActiveStatus;
import com.xy.dto.*;
import com.xy.dto.be.MercDto;
import com.xy.entity.MercFeeCountDay;
import com.xy.enums.MercStatus;
import com.xy.error.CommRuntimeException;
import com.xy.merc.EnumMercDeviceAlgorithmChargingPayType;
import com.xy.service.*;
import com.xy.service.be.MercFeignService;
import com.xy.service.be.MercService;
import com.xy.sys.EnumMercFeeType;
import com.xy.utils.LambdaUtils;
import com.xy.utils.PageBean;
import com.xy.utils.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 商户佣金费用收益每日统计任务（不含今天） 每日凌晨4点执行 （算法服务费是凌晨3点执行）
 */
@Slf4j
@Component
@RequiredArgsConstructor
@Api(tags = "商户佣金费用收益每日统计任务")
@RestMappingController("job/feeCountDay")
public class MercFeeCountDayJob {


    private final DeviceInfoService deviceInfoService;

    private final MercFeignService mercFeignService;

    private final DeviceChargingHistoryServiceImpl deviceChargingHistoryService;

    private final MercFeeCountDayServiceImpl mercFeeCountDayService;

    private final DeviceAlgorithmChargingHistoryServiceImpl deviceAlgorithmChargingHistoryService;

    private final MercDeviceAlgorithmChargingService mercDeviceAlgorithmChargingService;

    private final DeviceSimChargeServiceImpl deviceSimChargeService;

    private final MercService mercService;

    @PostMapping("queryByDay")
    @ApiOperation("指定日期查询")
    public R queryByDay(@RequestBody @Validated MercFeeCountDayDto.ExcuteDayDTO dto) {
        Integer type = dto.getType();
        String date = dto.getDate();
        DateTime yesterday = DateUtil.yesterday();
        String queryDay = DateUtil.format(yesterday, DatePattern.PURE_DATE_PATTERN);
        if (StrUtil.isNotEmpty(date)) {
            queryDay = date;
        }
        String monthValue = StrUtil.sub(queryDay, 0, 6);
        Integer dateValue = Integer.valueOf(queryDay);
        LocalDate dayDate = LocalDate.parse(queryDay, DateTimeFormatter.BASIC_ISO_DATE);
        LocalDateTime dayTime = dayDate.atStartOfDay();
        LocalDateTime beginTime = LocalDateTimeUtil.beginOfDay(dayTime);
        LocalDateTime endTime = LocalDateTimeUtil.endOfDay(dayTime);

        List<String> columnsMerc = Arrays.asList(LambdaUtils.getUnderlineCaseName(MercDto.Vo::getId));

        List<MercDto.Vo> approvedMercList = getApprovedMercList(columnsMerc);
        if (CollUtil.isEmpty(approvedMercList)) {
            return R.ok();
        }

        List<MercFeeCountDay> saveMercFeeCountList = new ArrayList<>();
        for (MercDto.Vo merc : approvedMercList) {
            Long parentMercId = merc.getId();
            List<Long> mercIds = R.feignCheckData(mercService.getChildMercIds(new MercDto.QuerySubDTO().setParentMercID(parentMercId)));
            if (CollUtil.isEmpty(mercIds)) {
                // 子商户都没有，就不用查分佣收益了
                continue;
            }
            //~~~~~~~~~~~~~1设备管理费
            if (type == 1) {
                PageBean<DeviceChargingHistoryDto.PageVo> pageVoPageBean = getDeviceManagerFeeMerc(parentMercId, beginTime, endTime);
                List<DeviceChargingHistoryDto.PageVo> records = pageVoPageBean == null ? null : pageVoPageBean.getRecords();
                if (CollUtil.isNotEmpty(records)) {
                    // 根据设备分组获取，每台设备缴费金额
                    Map<Long, Integer> devicePayMoneyMap = records.stream()
                            .collect(Collectors.groupingBy(DeviceChargingHistoryDto.PageVo::getMercId,
                                    Collectors.summingInt(DeviceChargingHistoryDto.PageVo::getChargingMoney)));
                    // 根据设备分组获取，每台设备佣金金额
                    Map<Long, Integer> deviceAgentMoneyMap = records.stream()
                            .collect(Collectors.groupingBy(DeviceChargingHistoryDto.PageVo::getMercId,
                                    Collectors.summingInt(DeviceChargingHistoryDto.PageVo::getAgentMoney)));
                    Set<Long> subMercIdSet = devicePayMoneyMap.keySet();
                    for (Long mercId : subMercIdSet) {
                        Integer payMoney = devicePayMoneyMap.get(mercId);
                        Integer brokerage = deviceAgentMoneyMap.get(mercId);
                        MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                        deviceDayFee.setFeeType(EnumMercFeeType.T1.getIntCode());
                        deviceDayFee.setParentMercId(parentMercId);
                        deviceDayFee.setDateValue(dateValue);
                        deviceDayFee.setPayMoney(payMoney);
                        deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                        deviceDayFee.setBrokerage(brokerage);
                        deviceDayFee.setMercId(mercId);
                        deviceDayFee.setParentMercId(parentMercId);
                        saveMercFeeCountList.add(deviceDayFee);
                    }
                } else {
                    // 没有费用的也要记录，为了前端收益概览的展示
                    for (Long mercId : mercIds) {

                        MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                        deviceDayFee.setFeeType(EnumMercFeeType.T1.getIntCode());
                        deviceDayFee.setParentMercId(parentMercId);
                        deviceDayFee.setDateValue(dateValue);
                        deviceDayFee.setPayMoney(0);
                        deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                        deviceDayFee.setBrokerage(0);
                        deviceDayFee.setMercId(mercId);
                        deviceDayFee.setParentMercId(parentMercId);
                        saveMercFeeCountList.add(deviceDayFee);
                    }
                }
            } else if (type == 2) {
                //~~~~~~~~~~~~~2设备激活费
                PageBean<DeviceAlgorithmChargingHistoryDto.PageByTopMercVO> deviceActiveFeeByMerc = getDeviceActiveFeeByMerc(parentMercId, beginTime, endTime);
                List<DeviceAlgorithmChargingHistoryDto.PageByTopMercVO> deviceActiveFeeList = deviceActiveFeeByMerc == null ? null : deviceActiveFeeByMerc.getRecords();
                if (CollUtil.isNotEmpty(deviceActiveFeeList)) {
                    // 根据设备分组获取，每台设备缴费金额
                    Map<Long, Integer> devicePayMoneyMap = deviceActiveFeeList.stream()
                            .collect(Collectors.groupingBy(DeviceAlgorithmChargingHistoryDto.PageByTopMercVO::getMercId,
                                    Collectors.summingInt(DeviceAlgorithmChargingHistoryDto.PageByTopMercVO::getChargingMoney)));
                    // 根据设备分组获取，每台设备佣金金额
                    Map<Long, Integer> deviceAgentMoneyMap = deviceActiveFeeList.stream()
                            .collect(Collectors.groupingBy(DeviceAlgorithmChargingHistoryDto.PageByTopMercVO::getMercId,
                                    Collectors.summingInt(DeviceAlgorithmChargingHistoryDto.PageByTopMercVO::getAgentMoney)));
                    Set<Long> subMercIdSet = devicePayMoneyMap.keySet();
                    for (Long mercId : subMercIdSet) {
                        Integer payMoney = devicePayMoneyMap.get(mercId);
                        Integer brokerage = deviceAgentMoneyMap.get(mercId);
                        MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                        deviceDayFee.setFeeType(EnumMercFeeType.T2.getIntCode());
                        deviceDayFee.setParentMercId(parentMercId);
                        deviceDayFee.setDateValue(dateValue);
                        deviceDayFee.setPayMoney(payMoney);
                        deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                        deviceDayFee.setBrokerage(brokerage);
                        deviceDayFee.setMercId(mercId);
                        deviceDayFee.setParentMercId(parentMercId);
                        saveMercFeeCountList.add(deviceDayFee);
                    }
                } else {
                    // 没有费用的也要记录，为了前端收益概览的展示
                    for (Long mercId : mercIds) {

                        MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                        deviceDayFee.setFeeType(EnumMercFeeType.T2.getIntCode());
                        deviceDayFee.setParentMercId(parentMercId);
                        deviceDayFee.setDateValue(dateValue);
                        deviceDayFee.setPayMoney(0);
                        deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                        deviceDayFee.setBrokerage(0);
                        deviceDayFee.setMercId(mercId);
                        deviceDayFee.setParentMercId(parentMercId);
                        saveMercFeeCountList.add(deviceDayFee);
                    }
                }

            } else if (type == 3) {
                //~~~~~~~~~~~~~3算法服务费
                PageBean<MercDeviceAlgorithmChargingDto.PageByTopMercVO> deviceAgFeeByMerc = getDeviceAgFeeByMerc(parentMercId, beginTime, endTime);
                List<MercDeviceAlgorithmChargingDto.PageByTopMercVO> deviceAgFeeList = deviceAgFeeByMerc == null ? null : deviceAgFeeByMerc.getRecords();
                if (CollUtil.isNotEmpty(deviceAgFeeList)) {
                    // 根据设备分组获取，每台设备缴费金额
                    Map<Long, Integer> devicePayMoneyMap = deviceAgFeeList.stream()
                            .collect(Collectors.groupingBy(MercDeviceAlgorithmChargingDto.PageByTopMercVO::getMercId,
                                    Collectors.summingInt(MercDeviceAlgorithmChargingDto.PageByTopMercVO::getFeeBalance)));
                    // 根据设备分组获取，每台设备佣金金额
                    Map<Long, Integer> deviceAgentMoneyMap = deviceAgFeeList.stream()
                            .collect(Collectors.groupingBy(MercDeviceAlgorithmChargingDto.PageByTopMercVO::getMercId,
                                    Collectors.summingInt(MercDeviceAlgorithmChargingDto.PageByTopMercVO::getFee)));
                    Set<Long> subMercIdSet = devicePayMoneyMap.keySet();
                    for (Long mercId : subMercIdSet) {
                        Integer payMoney = devicePayMoneyMap.get(mercId);
                        Integer brokerage = deviceAgentMoneyMap.get(mercId);
                        MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                        deviceDayFee.setFeeType(EnumMercFeeType.T3.getIntCode());
                        deviceDayFee.setParentMercId(parentMercId);
                        deviceDayFee.setDateValue(dateValue);
                        deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                        deviceDayFee.setPayMoney(payMoney);
                        deviceDayFee.setBrokerage(brokerage);
                        deviceDayFee.setMercId(mercId);
                        deviceDayFee.setParentMercId(parentMercId);
                        saveMercFeeCountList.add(deviceDayFee);
                    }
                } else {
                    // 没有费用的也要记录，为了前端收益概览的展示
                    for (Long mercId : mercIds) {

                        MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                        deviceDayFee.setFeeType(EnumMercFeeType.T3.getIntCode());
                        deviceDayFee.setParentMercId(parentMercId);
                        deviceDayFee.setDateValue(dateValue);
                        deviceDayFee.setPayMoney(0);
                        deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                        deviceDayFee.setBrokerage(0);
                        deviceDayFee.setMercId(mercId);
                        deviceDayFee.setParentMercId(parentMercId);
                        saveMercFeeCountList.add(deviceDayFee);
                    }
                }

            } else if (type == 4) {
                //~~~~~~~~~~~~~4流量卡费
                PageBean<DeviceSimChargeDto.PageByTopMercVO> simFeeByMerc = getSimFeeByMerc(parentMercId, beginTime, endTime);
                List<DeviceSimChargeDto.PageByTopMercVO> simFeeList = simFeeByMerc == null ? null : simFeeByMerc.getRecords();
                if (CollUtil.isNotEmpty(simFeeList)) {
                    // 根据设备分组获取，每台设备缴费金额
                    Map<Long, Integer> devicePayMoneyMap = simFeeList.stream()
                            .collect(Collectors.groupingBy(DeviceSimChargeDto.PageByTopMercVO::getMercId,
                                    Collectors.summingInt(DeviceSimChargeDto.PageByTopMercVO::getMoney)));
                    // 根据设备分组获取，每台设备佣金金额
                    Map<Long, Integer> deviceAgentMoneyMap = simFeeList.stream()
                            .collect(Collectors.groupingBy(DeviceSimChargeDto.PageByTopMercVO::getMercId,
                                    Collectors.summingInt(DeviceSimChargeDto.PageByTopMercVO::getAgentMoney)));
                    Set<Long> subMercIdSet = devicePayMoneyMap.keySet();
                    for (Long mercId : subMercIdSet) {
                        Integer payMoney = devicePayMoneyMap.get(mercId);
                        Integer brokerage = deviceAgentMoneyMap.get(mercId);
                        MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                        deviceDayFee.setFeeType(EnumMercFeeType.T4.getIntCode());
                        deviceDayFee.setParentMercId(parentMercId);
                        deviceDayFee.setDateValue(dateValue);
                        deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                        deviceDayFee.setPayMoney(payMoney);
                        deviceDayFee.setBrokerage(brokerage);
                        deviceDayFee.setMercId(mercId);
                        deviceDayFee.setParentMercId(parentMercId);
                        saveMercFeeCountList.add(deviceDayFee);
                    }
                } else {
                    // 没有费用的也要记录，为了前端收益概览的展示
                    for (Long mercId : mercIds) {

                        MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                        deviceDayFee.setFeeType(EnumMercFeeType.T4.getIntCode());
                        deviceDayFee.setParentMercId(parentMercId);
                        deviceDayFee.setDateValue(dateValue);
                        deviceDayFee.setPayMoney(0);
                        deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                        deviceDayFee.setBrokerage(0);
                        deviceDayFee.setMercId(mercId);
                        deviceDayFee.setParentMercId(parentMercId);
                        saveMercFeeCountList.add(deviceDayFee);
                    }
                }

            }
        }
        return R.ok(saveMercFeeCountList);
    }


    @PostMapping("excuteJob")
    @ApiOperation("指定日期执行")
    public R excuteJob(@RequestBody @Validated MercFeeCountDayDto.ExcuteDayDTO dto) {
        return R.ok(dayJob(dto.getDate()));
    }

    /**
     * 商户佣金费用收益每日统计（不含今天）
     * 类型 1设备管理费。2设备激活费。3算法扣费标准。4流量卡费
     *
     * @param date yyyyMMdd
     * @return
     */
    @XxlJob("mercFeeCountDayJob")
    public ReturnT<String> dayJob(String date) {
        log.info("-----------商户佣金费用收益每日统计 开始-----------");
//        long startTime = System.currentTimeMillis();
        DateTime yesterday = DateUtil.yesterday();
        String queryDay = DateUtil.format(yesterday, DatePattern.PURE_DATE_PATTERN);
        if (StrUtil.isNotEmpty(date)) {
            queryDay = date;

            // 指定日期需要判断是否重复执行
            MercFeeCountDayDto.SelectList selectList = new MercFeeCountDayDto.SelectList();
            selectList.setDateValue(Integer.valueOf(queryDay));
            List<MercFeeCountDayDto.Vo> vos = R.feignCheckData(mercFeeCountDayService.list(selectList));
            if (CollUtil.isNotEmpty(vos)) {
                throw new CommRuntimeException("已存在日期【" + date + "】的数据，请勿重复执行！");
            }
        }
        String monthValue = StrUtil.sub(queryDay, 0, 6);
        Integer dateValue = Integer.valueOf(queryDay);
        LocalDate dayDate = LocalDate.parse(queryDay, DateTimeFormatter.BASIC_ISO_DATE);
        LocalDateTime dayTime = dayDate.atStartOfDay();
        LocalDateTime beginTime = LocalDateTimeUtil.beginOfDay(dayTime);
        LocalDateTime endTime = LocalDateTimeUtil.endOfDay(dayTime);

        List<String> columnsMerc = Arrays.asList(LambdaUtils.getUnderlineCaseName(MercDto.Vo::getId));

        List<MercDto.Vo> approvedMercList = getApprovedMercList(columnsMerc);
        if (CollUtil.isEmpty(approvedMercList)) {
            return ReturnT.SUCCESS;
        }


        for (MercDto.Vo merc : approvedMercList) {
            Long parentMercId = merc.getId();
            List<Long> mercIds = R.feignCheckData(mercService.getChildMercIds(new MercDto.QuerySubDTO().setParentMercID(parentMercId)));
            if (CollUtil.isEmpty(mercIds)) {
                // 子商户都没有，就不用查分佣收益了
                continue;
            }
            //~~~~~~~~~~~~~1设备管理费
            PageBean<DeviceChargingHistoryDto.PageVo> pageVoPageBean = getDeviceManagerFeeMerc(parentMercId, beginTime, endTime);
            List<DeviceChargingHistoryDto.PageVo> records = pageVoPageBean == null ? null : pageVoPageBean.getRecords();
            if (CollUtil.isNotEmpty(records)) {
                // 根据设备分组获取，每台设备缴费金额
                Map<Long, Integer> devicePayMoneyMap = records.stream()
                        .collect(Collectors.groupingBy(DeviceChargingHistoryDto.PageVo::getMercId,
                                Collectors.summingInt(DeviceChargingHistoryDto.PageVo::getChargingMoney)));
                // 根据设备分组获取，每台设备佣金金额
                Map<Long, Integer> deviceAgentMoneyMap = records.stream()
                        .collect(Collectors.groupingBy(DeviceChargingHistoryDto.PageVo::getMercId,
                                Collectors.summingInt(DeviceChargingHistoryDto.PageVo::getAgentMoney)));
                Set<Long> subMercIdSet = devicePayMoneyMap.keySet();
                List<MercFeeCountDay> saveMercFeeCountList = new ArrayList<>();
                for (Long mercId : subMercIdSet) {
                    Integer payMoney = devicePayMoneyMap.get(mercId);
                    Integer brokerage = deviceAgentMoneyMap.get(mercId);
                    MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                    deviceDayFee.setFeeType(EnumMercFeeType.T1.getIntCode());
                    deviceDayFee.setParentMercId(parentMercId);
                    deviceDayFee.setDateValue(dateValue);
                    deviceDayFee.setPayMoney(payMoney);
                    deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                    deviceDayFee.setBrokerage(brokerage);
                    deviceDayFee.setMercId(mercId);
                    deviceDayFee.setParentMercId(parentMercId);
                    saveMercFeeCountList.add(deviceDayFee);
                }
                mercFeeCountDayService.saveBatch(saveMercFeeCountList);
            } else {
                // 没有费用的也要记录，为了前端收益概览的展示
                List<MercFeeCountDay> saveMercFeeCountList = new ArrayList<>();
                for (Long mercId : mercIds) {

                    MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                    deviceDayFee.setFeeType(EnumMercFeeType.T1.getIntCode());
                    deviceDayFee.setParentMercId(parentMercId);
                    deviceDayFee.setDateValue(dateValue);
                    deviceDayFee.setPayMoney(0);
                    deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                    deviceDayFee.setBrokerage(0);
                    deviceDayFee.setMercId(mercId);
                    deviceDayFee.setParentMercId(parentMercId);
                    saveMercFeeCountList.add(deviceDayFee);
                }
                mercFeeCountDayService.saveBatch(saveMercFeeCountList);
            }

            //~~~~~~~~~~~~~1设备管理费

            //~~~~~~~~~~~~~2设备激活费
            PageBean<DeviceAlgorithmChargingHistoryDto.PageByTopMercVO> deviceActiveFeeByMerc = getDeviceActiveFeeByMerc(parentMercId, beginTime, endTime);
            List<DeviceAlgorithmChargingHistoryDto.PageByTopMercVO> deviceActiveFeeList = deviceActiveFeeByMerc == null ? null : deviceActiveFeeByMerc.getRecords();
            if (CollUtil.isNotEmpty(deviceActiveFeeList)) {
                // 根据设备分组获取，每台设备缴费金额
                Map<Long, Integer> devicePayMoneyMap = deviceActiveFeeList.stream()
                        .collect(Collectors.groupingBy(DeviceAlgorithmChargingHistoryDto.PageByTopMercVO::getMercId,
                                Collectors.summingInt(DeviceAlgorithmChargingHistoryDto.PageByTopMercVO::getChargingMoney)));
                // 根据设备分组获取，每台设备佣金金额
                Map<Long, Integer> deviceAgentMoneyMap = deviceActiveFeeList.stream()
                        .collect(Collectors.groupingBy(DeviceAlgorithmChargingHistoryDto.PageByTopMercVO::getMercId,
                                Collectors.summingInt(DeviceAlgorithmChargingHistoryDto.PageByTopMercVO::getAgentMoney)));
                Set<Long> subMercIdSet = devicePayMoneyMap.keySet();
                List<MercFeeCountDay> saveMercFeeCountList = new ArrayList<>();
                for (Long mercId : subMercIdSet) {
                    Integer payMoney = devicePayMoneyMap.get(mercId);
                    Integer brokerage = deviceAgentMoneyMap.get(mercId);
                    MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                    deviceDayFee.setFeeType(EnumMercFeeType.T2.getIntCode());
                    deviceDayFee.setParentMercId(parentMercId);
                    deviceDayFee.setDateValue(dateValue);
                    deviceDayFee.setPayMoney(payMoney);
                    deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                    deviceDayFee.setBrokerage(brokerage);
                    deviceDayFee.setMercId(mercId);
                    deviceDayFee.setParentMercId(parentMercId);
                    saveMercFeeCountList.add(deviceDayFee);
                }
                mercFeeCountDayService.saveBatch(saveMercFeeCountList);
            } else {
                // 没有费用的也要记录，为了前端收益概览的展示
                List<MercFeeCountDay> saveMercFeeCountList = new ArrayList<>();
                for (Long mercId : mercIds) {

                    MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                    deviceDayFee.setFeeType(EnumMercFeeType.T2.getIntCode());
                    deviceDayFee.setParentMercId(parentMercId);
                    deviceDayFee.setDateValue(dateValue);
                    deviceDayFee.setPayMoney(0);
                    deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                    deviceDayFee.setBrokerage(0);
                    deviceDayFee.setMercId(mercId);
                    deviceDayFee.setParentMercId(parentMercId);
                    saveMercFeeCountList.add(deviceDayFee);
                }
                mercFeeCountDayService.saveBatch(saveMercFeeCountList);
            }

            //~~~~~~~~~~~~~2设备激活费

            //~~~~~~~~~~~~~3算法服务费
            PageBean<MercDeviceAlgorithmChargingDto.PageByTopMercVO> deviceAgFeeByMerc = getDeviceAgFeeByMerc(parentMercId, beginTime, endTime);
            List<MercDeviceAlgorithmChargingDto.PageByTopMercVO> deviceAgFeeList = deviceAgFeeByMerc == null ? null : deviceAgFeeByMerc.getRecords();
            if (CollUtil.isNotEmpty(deviceAgFeeList)) {
                // 根据设备分组获取，每台设备缴费金额
                Map<Long, Integer> devicePayMoneyMap = deviceAgFeeList.stream()
                        .collect(Collectors.groupingBy(MercDeviceAlgorithmChargingDto.PageByTopMercVO::getMercId,
                                Collectors.summingInt(MercDeviceAlgorithmChargingDto.PageByTopMercVO::getFeeBalance)));
                // 根据设备分组获取，每台设备佣金金额
                Map<Long, Integer> deviceAgentMoneyMap = deviceAgFeeList.stream()
                        .collect(Collectors.groupingBy(MercDeviceAlgorithmChargingDto.PageByTopMercVO::getMercId,
                                Collectors.summingInt(MercDeviceAlgorithmChargingDto.PageByTopMercVO::getFee)));
                Set<Long> subMercIdSet = devicePayMoneyMap.keySet();
                List<MercFeeCountDay> saveMercFeeCountList = new ArrayList<>();
                for (Long mercId : subMercIdSet) {
                    Integer payMoney = devicePayMoneyMap.get(mercId);
                    Integer brokerage = deviceAgentMoneyMap.get(mercId);
                    MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                    deviceDayFee.setFeeType(EnumMercFeeType.T3.getIntCode());
                    deviceDayFee.setParentMercId(parentMercId);
                    deviceDayFee.setDateValue(dateValue);
                    deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                    deviceDayFee.setPayMoney(payMoney);
                    deviceDayFee.setBrokerage(brokerage);
                    deviceDayFee.setMercId(mercId);
                    deviceDayFee.setParentMercId(parentMercId);
                    saveMercFeeCountList.add(deviceDayFee);
                }
                mercFeeCountDayService.saveBatch(saveMercFeeCountList);
            } else {
                // 没有费用的也要记录，为了前端收益概览的展示
                List<MercFeeCountDay> saveMercFeeCountList = new ArrayList<>();
                for (Long mercId : mercIds) {

                    MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                    deviceDayFee.setFeeType(EnumMercFeeType.T3.getIntCode());
                    deviceDayFee.setParentMercId(parentMercId);
                    deviceDayFee.setDateValue(dateValue);
                    deviceDayFee.setPayMoney(0);
                    deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                    deviceDayFee.setBrokerage(0);
                    deviceDayFee.setMercId(mercId);
                    deviceDayFee.setParentMercId(parentMercId);
                    saveMercFeeCountList.add(deviceDayFee);
                }
                mercFeeCountDayService.saveBatch(saveMercFeeCountList);
            }
            //~~~~~~~~~~~~~3算法服务费

            //~~~~~~~~~~~~~4流量卡费
            PageBean<DeviceSimChargeDto.PageByTopMercVO> simFeeByMerc = getSimFeeByMerc(parentMercId, beginTime, endTime);
            List<DeviceSimChargeDto.PageByTopMercVO> simFeeList = simFeeByMerc == null ? null : simFeeByMerc.getRecords();
            if (CollUtil.isNotEmpty(simFeeList)) {
                // 根据设备分组获取，每台设备缴费金额
                Map<Long, Integer> devicePayMoneyMap = simFeeList.stream()
                        .collect(Collectors.groupingBy(DeviceSimChargeDto.PageByTopMercVO::getMercId,
                                Collectors.summingInt(DeviceSimChargeDto.PageByTopMercVO::getMoney)));
                // 根据设备分组获取，每台设备佣金金额
                Map<Long, Integer> deviceAgentMoneyMap = simFeeList.stream()
                        .collect(Collectors.groupingBy(DeviceSimChargeDto.PageByTopMercVO::getMercId,
                                Collectors.summingInt(DeviceSimChargeDto.PageByTopMercVO::getAgentMoney)));
                Set<Long> subMercIdSet = devicePayMoneyMap.keySet();
                List<MercFeeCountDay> saveMercFeeCountList = new ArrayList<>();
                for (Long mercId : subMercIdSet) {
                    Integer payMoney = devicePayMoneyMap.get(mercId);
                    Integer brokerage = deviceAgentMoneyMap.get(mercId);
                    MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                    deviceDayFee.setFeeType(EnumMercFeeType.T4.getIntCode());
                    deviceDayFee.setParentMercId(parentMercId);
                    deviceDayFee.setDateValue(dateValue);
                    deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                    deviceDayFee.setPayMoney(payMoney);
                    deviceDayFee.setBrokerage(brokerage);
                    deviceDayFee.setMercId(mercId);
                    deviceDayFee.setParentMercId(parentMercId);
                    saveMercFeeCountList.add(deviceDayFee);
                }
                mercFeeCountDayService.saveBatch(saveMercFeeCountList);
            } else {
                // 没有费用的也要记录，为了前端收益概览的展示
                List<MercFeeCountDay> saveMercFeeCountList = new ArrayList<>();
                for (Long mercId : mercIds) {

                    MercFeeCountDay deviceDayFee = new MercFeeCountDay();
                    deviceDayFee.setFeeType(EnumMercFeeType.T4.getIntCode());
                    deviceDayFee.setParentMercId(parentMercId);
                    deviceDayFee.setDateValue(dateValue);
                    deviceDayFee.setPayMoney(0);
                    deviceDayFee.setMonthValue(Integer.valueOf(monthValue));
                    deviceDayFee.setBrokerage(0);
                    deviceDayFee.setMercId(mercId);
                    deviceDayFee.setParentMercId(parentMercId);
                    saveMercFeeCountList.add(deviceDayFee);
                }
                mercFeeCountDayService.saveBatch(saveMercFeeCountList);
            }
            //~~~~~~~~~~~~~4流量卡费
        }
        return ReturnT.SUCCESS;
    }

    private List<MercDto.Vo> getApprovedMercList(List<String> columnsMerc) {
        return R.feignCheckData(mercFeignService.listMerc(new MercDto.ListDTO().setStatus(String.valueOf(MercStatus.APPROVED.getCode())).setColumnList(columnsMerc)));
    }

    /**
     * 指定商户已激活设备
     *
     * @param mercId
     * @return
     */
    private List<DeviceInfoDto.Vo> getActiveDevicesByMercId(Long mercId) {
        DeviceInfoDto.ListCommon listCommon = new DeviceInfoDto.ListCommon().setVo(new DeviceInfoDto.Vo().setActiveState(EnumDeviceActiveStatus.N_1.getIntCode()).setMercId(mercId));
        return R.feignCheckData(deviceInfoService.listCommon(listCommon));
    }

    /**
     * 获取指定商户的子商户设备管理费缴纳记录
     *
     * @param mercId
     * @param beginCreateTime 开始时间
     * @param endCreateTime   结束时间
     * @return
     */
    private PageBean<DeviceChargingHistoryDto.PageVo> getDeviceManagerFeeMerc(Long mercId, LocalDateTime beginCreateTime, LocalDateTime endCreateTime) {
        DeviceChargingHistoryDto.PageByTopMerc pageByTopMerc = new DeviceChargingHistoryDto.PageByTopMerc();
        PageBean page = new PageBean();
        page.setSize(-1);
        pageByTopMerc.setCurMercId(mercId);
        pageByTopMerc.setBeginCreateTime(beginCreateTime);
        pageByTopMerc.setEndCreateTime(endCreateTime);
        pageByTopMerc.setPage(page);
        return R.feignCheckData(deviceChargingHistoryService.pageByTopMerc(pageByTopMerc));
    }

    /**
     * 获取指定商户的子商户设备激活费缴纳记录
     *
     * @param mercId
     * @param beginCreateTime
     * @param endCreateTime
     * @return
     */
    private PageBean<DeviceAlgorithmChargingHistoryDto.PageByTopMercVO> getDeviceActiveFeeByMerc(Long mercId, LocalDateTime beginCreateTime, LocalDateTime endCreateTime) {

        DeviceAlgorithmChargingHistoryDto.PageByTopMerc pageByTopMerc = new DeviceAlgorithmChargingHistoryDto.PageByTopMerc();
        PageBean page = new PageBean();
        page.setSize(-1);
        pageByTopMerc.setCurMercId(mercId);
        pageByTopMerc.setBeginCreateTime(beginCreateTime);
        pageByTopMerc.setEndCreateTime(endCreateTime);
        pageByTopMerc.setPage(page);
        return R.feignCheckData(deviceAlgorithmChargingHistoryService.pageByTopMerc(pageByTopMerc));
    }

    /**
     * 获取指定商户的子商户设备算法服务费缴纳记录
     *
     * @param mercId
     * @param beginCreateTime
     * @param endCreateTime
     * @return
     */
    private PageBean<MercDeviceAlgorithmChargingDto.PageByTopMercVO> getDeviceAgFeeByMerc(Long mercId, LocalDateTime beginCreateTime, LocalDateTime endCreateTime) {

        MercDeviceAlgorithmChargingDto.PageByTopMerc pageByTopMerc = new MercDeviceAlgorithmChargingDto.PageByTopMerc();
        PageBean page = new PageBean();
        page.setSize(-1);
        String payType = EnumMercDeviceAlgorithmChargingPayType.N_2.getCode();
        pageByTopMerc.setPayType(Integer.valueOf(payType));
        pageByTopMerc.setCurMercId(mercId);
        pageByTopMerc.setBeginCreateTime(beginCreateTime);
        pageByTopMerc.setEndCreateTime(endCreateTime);
        pageByTopMerc.setPage(page);
        return R.feignCheckData(mercDeviceAlgorithmChargingService.pageByMerc(pageByTopMerc));
    }

    /**
     * 获取指定商户的子商户流量卡缴纳记录
     *
     * @param mercId
     * @param beginCreateTime
     * @param endCreateTime
     * @return
     */
    private PageBean<DeviceSimChargeDto.PageByTopMercVO> getSimFeeByMerc(Long mercId, LocalDateTime beginCreateTime, LocalDateTime endCreateTime) {

        DeviceSimChargeDto.PageByTopMerc pageByTopMerc = new DeviceSimChargeDto.PageByTopMerc();
        PageBean page = new PageBean();
        page.setSize(-1);
        pageByTopMerc.setStatus(2);
        pageByTopMerc.setCurMercId(mercId);
        pageByTopMerc.setBeginCreateTime(beginCreateTime);
        pageByTopMerc.setEndCreateTime(endCreateTime);
        pageByTopMerc.setPage(page);
        return R.feignCheckData(deviceSimChargeService.pageByTopMerc(pageByTopMerc));
    }

}
