package cn.newfeifan.mall.module.distri.service.ordercalc;

import cn.newfeifan.mall.framework.common.util.json.JsonUtils;
import cn.newfeifan.mall.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.newfeifan.mall.module.distri.controller.admin.integral.vo.IntegralSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.admin.ptprofit.vo.PtProfitSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.admin.ptprofitlog.vo.PtProfitLogSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.admin.ptprofitlogdetails.vo.PtProfitLogDetailsSaveReqVO;
import cn.newfeifan.mall.module.distri.dal.dataobject.integral.IntegralDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.orderpercentage.OrderPercentageDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.ptprofit.PtProfitDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.sharepath.SharePathDO;
import cn.newfeifan.mall.module.distri.enums.CaclEnum;
import cn.newfeifan.mall.module.distri.enums.SocialStatusEnum;
import cn.newfeifan.mall.module.distri.mq.message.order.DistriOrderMessage;
import cn.newfeifan.mall.module.distri.mq.message.order.OrderCalcMessage;
import cn.newfeifan.mall.module.distri.mq.message.order.OrderItemMessage;
import cn.newfeifan.mall.module.distri.service.consumptionerrorlog.ConsumptionErrorLogService;
import cn.newfeifan.mall.module.distri.service.dailyawardrecords.DailyAwardRecordsService;
import cn.newfeifan.mall.module.distri.service.dailybill.DailyBillService;
import cn.newfeifan.mall.module.distri.service.duser.DuserService;
import cn.newfeifan.mall.module.distri.service.integral.IntegralService;
import cn.newfeifan.mall.module.distri.service.orderpercentage.OrderPercentageService;
import cn.newfeifan.mall.module.distri.service.partitioncrash.PartitionCrashService;
import cn.newfeifan.mall.module.distri.service.ptprofit.PtProfitService;
import cn.newfeifan.mall.module.distri.service.ptprofitlog.PtProfitLogService;
import cn.newfeifan.mall.module.distri.service.ptprofitlogdetails.PtProfitLogDetailsService;
import cn.newfeifan.mall.module.distri.service.sharepath.SharePathService;
import cn.newfeifan.mall.module.distri.service.shopsettlement.ShopSettlementService;
import cn.newfeifan.mall.module.infra.dal.dataobject.job.JobDO;
import cn.newfeifan.mall.module.infra.dal.dataobject.job.JobLogDO;
import cn.newfeifan.mall.module.infra.dal.mysql.job.JobLogMapper;
import cn.newfeifan.mall.module.infra.dal.mysql.job.JobMapper;
import cn.newfeifan.mall.module.infra.enums.job.JobLogStatusEnum;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import cn.newfeifan.mall.module.distri.controller.admin.ordercalc.vo.*;
import cn.newfeifan.mall.module.distri.dal.dataobject.ordercalc.OrderCalcDO;
import cn.newfeifan.mall.framework.common.pojo.PageResult;
import cn.newfeifan.mall.framework.common.util.object.BeanUtils;

import cn.newfeifan.mall.module.distri.dal.mysql.ordercalc.OrderCalcMapper;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.module.distri.enums.ErrorCodeConstants.*;

/**
 * 订单产生数据计算 Service 实现类
 *
 * @author 非繁人
 */
@Service
@Validated
public class OrderCalcServiceImpl implements OrderCalcService {

    @Resource
    private OrderCalcMapper orderCalcMapper;

    @Resource
    private PtProfitService ptProfitService;

    @Resource
    private PtProfitLogService ptProfitLogService;

    @Resource
    @Lazy
    private SharePathService sharePathService;

    @Resource
    private OrderPercentageService orderPercentageService;

    @Resource
    @Lazy
    private DuserService duserService;

    @Resource
    @Lazy
    private IntegralService integralService;

    @Resource
    private PartitionCrashService partitionCrashService;

    @Resource
    private PtProfitLogDetailsService ptProfitLogDetailsService;

    @Resource
    private DailyBillService dailyBillService;

    @Resource
    private ShopSettlementService shopSettlementService;

    @Resource
    private DailyAwardRecordsService dailyAwardRecordsService;

    @Resource
    private JobLogMapper jobLogMapper;

    @Resource
    private JobMapper jobMapper;

    @Resource
    private ConsumptionErrorLogService consumptionErrorLogService;

    @Override
    public Long createOrderCalc(OrderCalcSaveReqVO createReqVO) {
        // 插入
        OrderCalcDO orderCalc = BeanUtils.toBean(createReqVO, OrderCalcDO.class);
        orderCalcMapper.insert(orderCalc);
        // 返回
        return orderCalc.getId();
    }

    @Override
    public void updateOrderCalc(OrderCalcSaveReqVO updateReqVO) {
        // 校验存在
        validateOrderCalcExists(updateReqVO.getId());
        // 更新
        OrderCalcDO updateObj = BeanUtils.toBean(updateReqVO, OrderCalcDO.class);
        orderCalcMapper.updateById(updateObj);
    }

    @Override
    public void deleteOrderCalc(Long id) {
        // 校验存在
        validateOrderCalcExists(id);
        // 删除
        orderCalcMapper.deleteById(id);
    }

    private void validateOrderCalcExists(Long id) {
        if (orderCalcMapper.selectById(id) == null) {
            throw exception(ORDER_CALC_NOT_EXISTS);
        }
    }

    @Override
    public OrderCalcDO getOrderCalc(Long id) {
        return orderCalcMapper.selectById(id);
    }

    @Override
    public PageResult<OrderCalcDO> getOrderCalcPage(OrderCalcPageReqVO pageReqVO) {
        return orderCalcMapper.selectPage(pageReqVO);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void calc(List<OrderCalcMessage> tradeOrderDO, List<OrderCalcMessage> bonusQuotaOrderDO) {

        // 获取到当前订单的所有人
        List<Long> userId = tradeOrderDO.stream().map(OrderCalcMessage::getUserId).collect(Collectors.toList());
        // 判断当前下单的人员是否有进入营销模块用户表, 如果没有的话, 需要初始化
        duserService.hasUserAndCreat(userId);
        // 判断当前下单人是否有有上级, 如果没有, 创建直推人关系
        sharePathService.createSharePathByUserId(userId);

        try {
            OrderPercentageDO orderPercentageDO = orderPercentageService.queryStatus();
            // 当前计算百分比模板
            String percentTemplate = JsonUtils.toJsonString(orderPercentageDO);

            // 订单完成的七天后计算,分配权益,现在是即算即得所以注释了,后续变动可以打开
//            calc(tradeOrderDO, orderPercentageDO, percentTemplate);

            /*
            计算合赢奖三部曲：
                1：计算每日订单
                2：计算每日合赢奖的收益（冻结的）
                3：将冻结的合赢将转换成可用的
             */
            //计算每日订单收益
            //  1
            calcDailyBill(bonusQuotaOrderDO, orderPercentageDO, percentTemplate);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            // todo 计算当天用户的碰撞
            // 计算兄弟分区， 以及后代分区
            //  2
            List<Long> userId2 = bonusQuotaOrderDO.stream().map(OrderCalcMessage::getUserId).collect(Collectors.toList());
            partitionCrashService.calcCrash(userId2);

            //  3
            dailyAwardRecordsService.transitionBonus();

            // 计算每家店铺每日订单
            dailyBillService.caleDailyBill();

            // 结算订单，签收七天的订单
            shopSettlementService.settlementOrder();

            // 每日消费分校对预警
            consumptionErrorLogService.calcEveryDayConsumptionPointsErrorLog();

            System.out.println("=================计算程序结束====================");
        }

        // 不是用的quzt 手动加上日志
        JobDO job = jobMapper.selectOne(JobDO::getHandlerName, "tradeOrderAutoCalcJob");

        Long count = jobLogMapper.getJobLogCount(job.getHandlerName());

        // 如果今天有记录并且是成功的那就不加了
        if(count > 0){
            return;
        }

        JobLogDO log = new JobLogDO();
        log.setBeginTime(LocalDateTime.now());
        log.setStatus(JobLogStatusEnum.SUCCESS.getStatus());
        log.setJobId(job.getId());
        log.setHandlerName(job.getHandlerName());
        log.setHandlerParam(job.getHandlerParam());
        log.setExecuteIndex(1);

        jobLogMapper.insert(log);
    }

    /**
     * 将原来程序中的合赢将计算程序分离出来（这里用来计算每日的订单合赢奖）
     *
     * @param bonusQuotaOrderDO 每日符合条件的订单
     * @param orderPercentageDO 订单百分比
     * @param percentTemplate   计算比例模板
     */

    private void calcDailyBill(List<OrderCalcMessage> bonusQuotaOrderDO, OrderPercentageDO orderPercentageDO, String percentTemplate) {
        // 每个订单收益
        List<OrderCalcSaveReqVO> saveList = new ArrayList<>();

        bonusQuotaOrderDO.forEach(k -> {
            // 添加平台利润记录详情
            List<PtProfitLogDetailsSaveReqVO> ptProfitLogDetailsSaveReqVOS = new ArrayList<>();
            // 计算单个订单的总单价
            long priceStream = k.getOrderItemMessages().stream().mapToLong(OrderItemMessage::getPrice).sum();
            // 计算单个订单的总成本
            long longStream = k.getOrderItemMessages().stream().mapToLong(OrderItemMessage::getCostPrice).sum();
            BigDecimal price = new BigDecimal(priceStream);
            BigDecimal costPrice = new BigDecimal(longStream);

            // 计算
            // 计算利润: (价格 - 成本价格) * 产品数量
            //用户自得和直推奖不用计算,从orderItem里面获取
            final BigDecimal[] profit = {new BigDecimal("0"), new BigDecimal("0"), new BigDecimal("0")};
            k.getOrderItemMessages().forEach(j -> {
                BigDecimal onePrice = new BigDecimal(j.getPrice());
                BigDecimal oneCostPrice = new BigDecimal(j.getCostPrice());
                BigDecimal productCount = new BigDecimal(j.getCount());
                BigDecimal oneGrossProfit = onePrice.subtract(oneCostPrice).multiply(productCount);
                profit[0] = profit[0].add(oneGrossProfit);  // 注意这里的改动
                profit[1] = profit[1].add(new BigDecimal(j.getIncreaseIntegral()));     //自得积分
                profit[2] = profit[2].add(new BigDecimal(j.getAncestorIncreaseIntegral()));     //直推奖积分

                // 参与过订单计算后就标记为已分配权益
                updateOrderItemTransitionTime(j.getOrderItemId());
                //  添加日志表的二级表
                PtProfitLogDetailsSaveReqVO ptProfitLogDetailsSaveReqVO = PtProfitLogDetailsSaveReqVO.builder()
                        .orderItemId(j.getOrderItemId())
                        .build();
                ptProfitLogDetailsSaveReqVOS.add(ptProfitLogDetailsSaveReqVO);
            });

            // 计算毛利: 利润 * 1
            BigDecimal grossProfit = profit[0].multiply(new BigDecimal(orderPercentageDO.getGrossProfitPerc())).setScale(4, RoundingMode.DOWN);
            // 合赢将: 毛利 * 0.12
            BigDecimal bonusQuota = grossProfit.multiply(new BigDecimal(orderPercentageDO.getGrossProfitBonusQuotaPerc())).setScale(4, RoundingMode.DOWN);

            // 用户所得: 毛利 * 0.35
            BigDecimal descendantQuota = profit[1];

            // 直推奖: 毛利 * 0.3 (上一级)
            BigDecimal ancestorQuota = profit[2];

            Long grossProfitInt = grossProfit.multiply(new BigDecimal("10000")).setScale(0, RoundingMode.DOWN).longValue();
            Long bonusQuotaInt = bonusQuota.multiply(new BigDecimal("10000")).setScale(0, RoundingMode.DOWN).longValue();
            BigDecimal platformQuota = grossProfit.multiply(new BigDecimal(orderPercentageDO.getGrossProfitPlatformQuotaPerc())).setScale(4, RoundingMode.DOWN);

            Long ancestorQuotaInt = ancestorQuota.longValue();
            Long descendantQuotaInt = descendantQuota.longValue();
            Long platformQuotaInt = platformQuota.multiply(new BigDecimal("10000")).setScale(0, RoundingMode.DOWN).longValue();

            // ========== 汇总计算 =================
            OrderCalcSaveReqVO orderCalcSaveReqVO = OrderCalcSaveReqVO.builder()
                    .userId(k.getUserId())
                    .orderNo(k.getNo())
                    .orderId(k.getOrderId())
                    .cost(costPrice.longValue())
                    .price(price.longValue())
                    .productCount(k.getProductCount())
                    .nickName(k.getNickName())
                    .name(k.getName())
                    .grossProfit(grossProfitInt)
                    .grossProfitUserQuota(descendantQuotaInt)
                    .grossProfitPlatformQuota(platformQuotaInt)
                    .grossProfitAncestorQuota(ancestorQuotaInt)
                    .percentTemplate(percentTemplate).build();
            saveList.add(orderCalcSaveReqVO);

            // 合赢奖记录
            PtProfitLogSaveReqVO hyjLog = PtProfitLogSaveReqVO.builder()
                    .orderId(k.getOrderId())
                    .profitStatus(CaclEnum.TOGETHER_AWARD.getType())
                    .orderNo(k.getNo())
                    .amount(bonusQuotaInt)
                    .afterAmount(0L)
                    .generateUserId(k.getUserId())
                    .percentTemplate(percentTemplate).build();
            // 添加获得合赢奖的记录
            hyjLog.setId(ptProfitLogService.createPtProfitLog(hyjLog));
            for (PtProfitLogDetailsSaveReqVO ptProfitLogDetailsSaveReqVO : ptProfitLogDetailsSaveReqVOS) {
                ptProfitLogDetailsSaveReqVO.setDistriPtProfitLogId(hyjLog.getId());
            }
            ptProfitLogDetailsService.saveBatch(ptProfitLogDetailsSaveReqVOS);
        });

        // 将信息存储到数据库中
        orderCalcMapper.insertBatch(BeanUtils.toBean(saveList, OrderCalcDO.class));
    }

    private void updateOrderItemTransitionTime(Long orderItemId) {
        orderCalcMapper.updateOrderItemTransitionTime(orderItemId);
    }

    @Override
    public List<OrderCalcDO> queryTodayCalcByUserIds(LocalDateTime todayStart, LocalDateTime todayEnd, List<Long> userList) {
        return orderCalcMapper.selectList(new LambdaQueryWrapperX<OrderCalcDO>()
                .betweenIfPresent(OrderCalcDO::getCreateTime, todayStart, todayEnd)
                .in(OrderCalcDO::getUserId, userList));
    }

    @Override
    public void updateOrderItem(Long orderItemId) {
        orderCalcMapper.updateOrderItemById(orderItemId);
    }

    @Override
    public void calc(List<OrderCalcMessage> tradeOrderDO) {
        OrderPercentageDO orderPercentageDO = orderPercentageService.queryStatus();
        // 当前计算百分比模板
        String percentTemplate = JsonUtils.toJsonString(orderPercentageDO);

        calc(tradeOrderDO, orderPercentageDO, percentTemplate);
    }

    private void calc(List<OrderCalcMessage> tradeOrderDO, OrderPercentageDO orderPercentageDO, String percentTemplate) {

        // 平台收益日志
        List<PtProfitLogSaveReqVO> ptProfitLogSaveReqVOS = new ArrayList<>();

        // todo 修改用户身价 如何从订单中获取身价?
        BigDecimal oneHundred = new BigDecimal(BigInteger.ONE);


        // 计算,毛利中100 之外的百分比
        BigDecimal otherOneHundred = oneHundred.subtract(new BigDecimal(orderPercentageDO.getGrossProfitUserQuotaPerc()))
                .subtract(new BigDecimal(orderPercentageDO.getGrossProfitAncestorQuotaPerc()))
                .subtract(new BigDecimal(orderPercentageDO.getGrossProfitPlatformQuotaPerc()));


        tradeOrderDO.forEach(k -> {
            PtProfitDO ptProfitDO = ptProfitService.getPtProfit();
            // 平台收益
            List<PtProfitSaveReqVO> ptProfitSaveReqVOS = new ArrayList<>();

            // 计算
            // 计算利润: (价格 - 成本价格) * 产品数量
            //用户自得和直推奖不用计算,从orderItem里面获取
            final BigDecimal[] profit = {new BigDecimal("0"), new BigDecimal("0"), new BigDecimal("0"), new BigDecimal("0")};
            k.getOrderItemMessages().forEach(j -> {
                BigDecimal onePrice = new BigDecimal(j.getPrice());
                BigDecimal oneCostPrice = new BigDecimal(j.getCostPrice());
                BigDecimal productCount = new BigDecimal(j.getCount());
                BigDecimal oneGrossProfit = onePrice.subtract(oneCostPrice).multiply(productCount);
                profit[0] = profit[0].add(oneGrossProfit);  // 注意这里的改动
                profit[1] = profit[1].add(new BigDecimal(j.getIncreaseIntegral()));     //自得积分
                profit[2] = profit[2].add(new BigDecimal(j.getAncestorIncreaseIntegral()));     //直推奖
                profit[3] = profit[3].add(new BigDecimal(j.getFreezeHighQuota()));     //用户获得冻结最大可用额度

                // 遍历订单项拿到订单项编号
                //将当前订单项设置为已分配权益
                updateOrderItem(j.getOrderItemId());
            });


            // 计算毛利: 利润 * 1
            BigDecimal grossProfit = profit[0].multiply(new BigDecimal(orderPercentageDO.getGrossProfitPerc())).setScale(4, RoundingMode.DOWN);

            // 计算平台收益
            BigDecimal grossProfitAfterBonus = profit[0].multiply(oneHundred.subtract(new BigDecimal(orderPercentageDO.getGrossProfitPerc()))).setScale(4, RoundingMode.DOWN);

            if (otherOneHundred.compareTo(new BigDecimal(BigInteger.ZERO)) > 0) {
                grossProfitAfterBonus = grossProfitAfterBonus.add(grossProfit.multiply(otherOneHundred).setScale(4, RoundingMode.DOWN));
            }

            // 用户所得: 毛利 * 0.35
            BigDecimal descendantQuota = profit[1];

            // 直推奖: 毛利 * 0.3 (上一级)
            BigDecimal ancestorQuota = profit[2];

            // 平台服务费: 毛利 * 0.05
            BigDecimal platformQuota = grossProfit.multiply(new BigDecimal(orderPercentageDO.getGrossProfitPlatformQuotaPerc())).setScale(4, RoundingMode.DOWN);


            // 计算当前下单人的毛利的十倍
//            BigDecimal highQuota = grossProfit.multiply(new BigDecimal("10")).setScale(4, RoundingMode.DOWN);
            BigDecimal highQuota = profit[3];

            // 乘以 10000 并转换为整数
            Long ancestorQuotaInt = ancestorQuota.longValue();
            Long descendantQuotaInt = descendantQuota.longValue();
            Long highQuotaInt = highQuota.longValue();
            Long grossProfitAfterBonusInt = grossProfitAfterBonus.multiply(new BigDecimal("10000")).setScale(0, RoundingMode.DOWN).longValue();
            Long platformQuotaInt = platformQuota.multiply(new BigDecimal("10000")).setScale(0, RoundingMode.DOWN).longValue();


            // 获取当前下单人关系
            SharePathDO sharePath = getSharePath(k.getUserId());
            // 如果sharePath为空, 则说明没有直推人关系
            IntegralDO integralDOAncestor = integralService.selectByUser(sharePath.getAncestor());      //父级
            IntegralDO integralDO = integralService.selectByUser(sharePath.getDescendant());            //自己
            IntegralDO ptIntegral = integralService.selectByUser(1L);                         //pt


            // ========== 身价计算 ==============
            //推荐人身价计算
            double orderAncestorSocialStatus = Double.parseDouble(orderPercentageDO.getOrderAncestorSocialStatus());
            double ancestorSocial = k.getOrderItemMessages().get(0).getTotalPrice() * orderAncestorSocialStatus / 100;
            duserService.updateDuserSocial(integralDOAncestor.getUserId(), (long) ancestorSocial, SocialStatusEnum.SHOPPING_ANCESTOR_SOCIAL.getStatus());

            //自得身价计算
            double orderUserSocialStatus = Double.parseDouble(orderPercentageDO.getOrderUserSocialStatus());
            double descendantSocial = k.getOrderItemMessages().get(0).getTotalPrice() * orderUserSocialStatus / 100;
            duserService.updateDuserSocial(integralDO.getUserId(), (long) descendantSocial, SocialStatusEnum.SHOPPING_SOCIAL.getStatus());

            /*
            原本这里有添加到distri_order_calc表的记录,但是现在要合赢奖和(直推奖、自得奖）分开，所以现在搬走了
             */

            // ========== 修改用户钱包 =================

            //直推奖也要限制额度
            Long ancestorHighQuota = integralDOAncestor.getHighQuota() + new BigDecimal(orderPercentageDO.getBaseMaxQuota()).longValue();//加上基础的最大额度值

            //amount用于记录本次添加的值
            Long amount = 0L;
            //平台需要补回的收益
            Long ptReplenish = ancestorQuotaInt;

            //如果直推人的可获取额度大于0,则能够获取
            if (ancestorHighQuota.compareTo(0L) > 0) {
                if (ancestorHighQuota.compareTo(ancestorQuotaInt) > 0) {
                    //如果最大额度 > 直推人可获取额度,则直接获取
                    amount = ancestorQuotaInt;
                    //平台没有需要补回的收益
                    ptReplenish = 0L;
                } else {
                    //如果最大额度 < 直推人可获取额度,则获取自己的最大额度
                    amount = ancestorHighQuota;
                    //用户本次没有拿到的直推奖
                    ptReplenish = ancestorQuotaInt - ancestorHighQuota;
                }
            }
            changeUserWallet(integralDO, integralDOAncestor, ptIntegral, amount,
                    descendantQuotaInt, highQuotaInt, grossProfitAfterBonusInt, platformQuotaInt, ptReplenish);

            // ========== 修改平台信息 =================
            // 每个订单计算的过程
            // 增加平台收益
            // 平台服务费
            PtProfitSaveReqVO ptProfitSaveReqVO =
                    PtProfitSaveReqVO.builder()
                            .ptAdd(platformQuotaInt)
                            .ptGrossAdd(grossProfitAfterBonusInt)
                            .ptTotalAdd(platformQuotaInt + grossProfitAfterBonusInt).build();


            // 当直推人获取的积分额度不足时,平台收益要加回来,并生成log
            if (ptReplenish.compareTo(0L) > 0) {
                calcIntegral(ptProfitSaveReqVOS, ptProfitSaveReqVO, ptReplenish,
                        k.getOrderId(), k.getNo());
            }

            ptProfitSaveReqVOS.add(ptProfitSaveReqVO);
            // ========== 增加日志记录 =================

            // 平台记录
            // 平台总收益
            // 平台总收益
            PtProfitLogSaveReqVO ptTotal = PtProfitLogSaveReqVO.builder()
                    .orderId(k.getOrderId())
                    .profitStatus(CaclEnum.PLATFORM_TOTAL_ADD.getType())
                    .orderNo(k.getNo())
                    .amount(platformQuotaInt + grossProfitAfterBonusInt)
                    .afterAmount(ptProfitDO.getPtTotalAdd() + platformQuotaInt + grossProfitAfterBonusInt)
                    .percentTemplate(percentTemplate)
                    .generateUserId(integralDO.getUserId())
                    .build();
            // 平台收益
            PtProfitLogSaveReqVO ptGrossAddLog = PtProfitLogSaveReqVO.builder()
                    .orderId(k.getOrderId())
                    .profitStatus(CaclEnum.PLATFORM_REVENUE.getType())
                    .orderNo(k.getNo())
                    .amount(grossProfitAfterBonusInt)
                    .afterAmount(ptProfitDO.getPtGrossAdd() + ptProfitSaveReqVO.getPtGrossAdd())
                    .percentTemplate(percentTemplate)
                    .generateUserId(integralDO.getUserId())
                    .build();

            // 平台服务费
            PtProfitLogSaveReqVO ptAddLog = PtProfitLogSaveReqVO.builder()
                    .orderId(k.getOrderId())
                    .profitStatus(CaclEnum.PLATFORM_SERVICE_FEE.getType())
                    .orderNo(k.getNo())
                    .amount(platformQuotaInt)
                    .afterAmount(ptProfitDO.getPtAdd() + ptProfitSaveReqVO.getPtAdd())
                    .percentTemplate(percentTemplate)
                    .generateUserId(integralDO.getUserId())
                    .build();


            // 直推奖记录
            PtProfitLogSaveReqVO tjrLog = PtProfitLogSaveReqVO.builder()
                    .orderId(k.getOrderId())
                    .profitStatus(CaclEnum.RECOMMENDED_PERSON_QUOTA.getType())
                    .orderNo(k.getNo())
                    .userId(sharePath.getAncestor())
                    .amount(amount)
                    .afterAmount(integralDOAncestor.getCurrentQuota())
                    .freezeAmount(-amount)
                    .afterFreezeAmount(integralDOAncestor.getFreezeQuota())
                    .ancestorQuotaAmount(ptReplenish)
                    .maxAvailablePointsAmount(-amount)
                    .afterMaxAvailablePointsAmount(ancestorHighQuota - amount)
                    .percentTemplate(percentTemplate)
                    .generateUserId(integralDO.getUserId())
                    .build();


            // 用户自得记录 + 户冻结积分转化成可用 + 扣减最高可用额度记录
            PtProfitLogSaveReqVO ztrLog = PtProfitLogSaveReqVO.builder()
                    .orderId(k.getOrderId())
                    .profitStatus(CaclEnum.DIRECT_REFERRAL_QUOTA.getType())
                    .orderNo(k.getNo())
                    .userId(sharePath.getDescendant())
                    .amount(descendantQuotaInt)
                    .afterAmount(integralDO.getCurrentQuota())
                    .freezeAmount(-descendantQuotaInt)
                    .afterFreezeAmount(integralDO.getFreezeQuota())
                    .maxAvailablePointsAmount(highQuotaInt)
                    .afterMaxAvailablePointsAmount(integralDO.getHighQuota()+ new BigDecimal(orderPercentageDO.getBaseMaxQuota()).longValue())
                    .freezeHighQuota(-highQuotaInt)
                    .afterFreezeHighQuota(integralDO.getFreezeHighQuota())
                    .percentTemplate(percentTemplate)
                    .generateUserId(integralDO.getUserId())
                    .build();

            ptProfitLogSaveReqVOS.add(ptTotal);
            ptProfitLogSaveReqVOS.add(ptGrossAddLog);
            ptProfitLogSaveReqVOS.add(ptAddLog);
            ptProfitLogSaveReqVOS.add(tjrLog);
            ptProfitLogSaveReqVOS.add(ztrLog);


            PtProfitDO ptProfit = ptProfitService.getPtProfit();
            // 计算总积分
            Long total = ptProfitSaveReqVOS.stream().mapToLong(PtProfitSaveReqVO::getPtTotalAdd).sum();
            Long add = ptProfitSaveReqVOS.stream().mapToLong(PtProfitSaveReqVO::getPtAdd).sum();
            Long grossAdd = ptProfitSaveReqVOS.stream().mapToLong(PtProfitSaveReqVO::getPtGrossAdd).sum();
            ptProfit.setPtAdd(ptProfit.getPtAdd() + add);
            ptProfit.setPtTotalAdd(ptProfit.getPtTotalAdd() + total);
            ptProfit.setPtGrossAdd(ptProfit.getPtGrossAdd() + grossAdd);
            PtProfitSaveReqVO ptProfitSaveReqVO2 = PtProfitSaveReqVO.builder()
                    .id(ptProfitDO.getId())
                    .ptTotalAdd(ptProfit.getPtTotalAdd())
                    .ptAdd(ptProfit.getPtAdd())
                    .ptGrossAdd(ptProfit.getPtGrossAdd()).build();
            ptProfitService.updatePtProfit(ptProfitSaveReqVO2);
        });

        // 信息整合
        ptProfitLogService.saveBatch(ptProfitLogSaveReqVOS);
    }

    /**
     * 在用户获取直推奖的时候溢出的需要加入到平台,并记录log
     */
    private void calcIntegral(List<PtProfitSaveReqVO> ptProfitSaveReqVOS, PtProfitSaveReqVO ptProfitSaveReqVO
            , Long ancestorQuotaInt, Long orderId, String orderNo) {
        ptProfitSaveReqVO.setPtGrossAdd(ptProfitSaveReqVO.getPtGrossAdd() + ancestorQuotaInt);
        ptProfitSaveReqVO.setPtTotalAdd(ptProfitSaveReqVO.getPtGrossAdd() + ptProfitSaveReqVO.getPtAdd());

        PtProfitLogSaveReqVO ptProfitLog = PtProfitLogSaveReqVO.builder()
                .orderId(orderId)
                .profitStatus(CaclEnum.GROSS_PROFIT_ANCESTOR_QUOTA_PERC_EXCEED_MAXIMUM_LIMIT.getType())
                .orderNo(orderNo)
                .amount(ancestorQuotaInt)
                .afterAmount(ptProfitSaveReqVOS.stream().mapToLong(PtProfitSaveReqVO::getPtGrossAdd).sum() + ancestorQuotaInt)
                .build();
        ptProfitLogService.createPtProfitLog(ptProfitLog);
    }

    private PtProfitDO calcPtProfit(PtProfitDO ptProfitDO, List<PtProfitSaveReqVO> ptProfitSaveReqVOS) {

        Long currentPtAdd = 0L;
        Long currentPtGrossAdd = 0L;

        for (PtProfitSaveReqVO ptProfitSaveReqVO : ptProfitSaveReqVOS) {
            currentPtAdd = currentPtAdd + ptProfitSaveReqVO.getPtAdd();
            currentPtGrossAdd = currentPtGrossAdd + ptProfitSaveReqVO.getPtGrossAdd();
        }

        ptProfitDO.setPtAdd(ptProfitDO.getPtAdd() + currentPtAdd);
        ptProfitDO.setPtGrossAdd(ptProfitDO.getPtGrossAdd() + currentPtGrossAdd);
        ptProfitDO.setPtTotalAdd(currentPtAdd + currentPtGrossAdd + ptProfitDO.getPtTotalAdd());

        return ptProfitDO;
    }

    private static void addCaclDo(String percentTemplate, List<OrderCalcSaveReqVO> saveList, DistriOrderMessage k, Long grossProfit, Long ancestorQuota, Long descendantQuota, Long bonusQuota, Long platformQuota) {
        OrderCalcSaveReqVO orderCalcSaveReqVO = OrderCalcSaveReqVO.builder()
                .userId(k.getUserId())
                .orderNo(k.getNo())
                .cost(k.getCostPrice())
                .price(k.getPrice())
                .grossProfit(grossProfit)
                .grossProfitUserQuota(ancestorQuota)
                .grossProfitAncestorQuota(descendantQuota)
                .grossProfitBonusQuota(bonusQuota)
                .grossProfitPlatformQuota(platformQuota)
                .percentTemplate(percentTemplate).build();
        saveList.add(orderCalcSaveReqVO);
    }

    /**
     * 修改用户钱包
     *
     * @param integralDO         当前用户钱包
     * @param integralDOAncestor 推荐人钱包
     * @param pt                 pt钱包
     * @param ancestorQuota      推荐人额度
     * @param descendantQuota    直推人额度
     * @param highQuota          最大可用额度
     * @param ptA                pt收益
     * @param ptB                pt服务费
     * @param ptReplenish        超出没有获取到的积分
     */
    private void changeUserWallet(IntegralDO integralDO, IntegralDO integralDOAncestor, IntegralDO pt,
                                  Long ancestorQuota, Long descendantQuota, Long highQuota, Long ptA, Long ptB, Long ptReplenish) {
        // 修改用户钱包
        // 增加直推人额度
        integralDO.setHighQuota(integralDO.getHighQuota() + highQuota);
        //增加累计峰值
        integralDO.setHighQuotaTotal(integralDO.getHighQuotaTotal() + highQuota);
        integralDO.setFreezeHighQuota(integralDO.getFreezeHighQuota() - highQuota);
        // todo 增加累计额度

        integralDO.setCurrentQuota(integralDO.getCurrentQuota() + descendantQuota);
        integralDO.setFreezeQuota(integralDO.getFreezeQuota() - descendantQuota);
        // 增加推荐人额度
        integralDOAncestor.setCurrentQuota(integralDOAncestor.getCurrentQuota() + ancestorQuota);
        // 减少推荐人的可获取额度
        integralDOAncestor.setHighQuota(integralDOAncestor.getHighQuota() - ancestorQuota);
        integralDOAncestor.setAncestorQuota(integralDOAncestor.getAncestorQuota() + ancestorQuota);
        integralDOAncestor.setFreezeQuota(integralDOAncestor.getFreezeQuota() - ancestorQuota - ptReplenish);
        integralService.updateIntegral(BeanUtils.toBean(integralDOAncestor, IntegralSaveReqVO.class));

        // 增加平台额度
        pt.setCurrentQuota(pt.getCurrentQuota() + ptA + ptB);

//        integralSaveReqVOS.add(BeanUtils.toBean(integralDO, IntegralSaveReqVO.class));
//        integralSaveReqVOS.add(BeanUtils.toBean(integralDOAncestor, IntegralSaveReqVO.class));

        integralService.updateIntegral(BeanUtils.toBean(integralDO, IntegralSaveReqVO.class));
        integralService.updateIntegral(BeanUtils.toBean(pt, IntegralSaveReqVO.class));

    }


    // 获取当前订单的下单人的直推关系
    public SharePathDO getSharePath(Long userId) {
        return sharePathService.getSharePathByDescendant(userId);
    }


}
