package com.yd.csf.api.async;

import com.alibaba.fastjson.JSON;
import com.yd.common.enums.CommonEnum;
import com.yd.common.result.Result;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.csf.api.dto.AlgorithmCollectResDto;
import com.yd.csf.api.dto.AlgorithmResDto;
import com.yd.csf.api.service.ApiExpectedFortuneService;
import com.yd.csf.api.service.XxlJobService;
import com.yd.csf.feign.enums.FycSourceTypeEnum;
import com.yd.csf.feign.enums.OprSourceEnum;
import com.yd.csf.feign.request.expectedfortune.ApiGenerateExpectedFortuneRequest;
import com.yd.csf.feign.response.expectedfortune.ApiGenerateExpectedFortuneResponse;
import com.yd.csf.service.enums.RuleItemEnum;
import com.yd.csf.service.model.*;
import com.yd.csf.service.service.*;
import com.yd.feign.config.FeignTokenInterceptor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 发佣异步类
 */
@Slf4j
@Component
public class ApiExpectedFortuneAsyncService {

    @Resource
    private ApiExpectedFortuneService apiExpectedFortuneService;
    @Resource
    private PolicyFollowService policyFollowService;
    @Resource
    private ICalmTaskService iCalmTaskService;
    @Resource
    private XxlJobService xxlJobService;
    @Resource
    private IAgentAccumulatedFycService iAgentAccumulatedFycService;
    @Resource
    private IAgentDetailFycService iAgentDetailFycService;
    @Resource
    private IAgentAccumulatedFycLogService iAgentAccumulatedFycLogService;

    /**
     * 异步处理-执行预计发拥数据
     *
     * @return
     */
    @Async("commonAsyncExecutor")
    public Result execute(String policyNo, String token) {
        // 将 token 设置到 ThreadLocal 中，供 Feign 拦截器使用
        FeignTokenInterceptor.setThreadLocalToken(token);

        HttpServletRequest request1 = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token1 = request1.getHeader("Authorization");
        log.info("异步处理 token==============,{}",token1);

        try {
            ApiGenerateExpectedFortuneRequest request = new ApiGenerateExpectedFortuneRequest();
            request.setPolicyNo(policyNo);
            log.info("生成预计发佣 generateSyncWithLogAndRedis ——> PolicyNo：{}", policyNo);
            Result<ApiGenerateExpectedFortuneResponse> result =
                    apiExpectedFortuneService.generateSyncWithLogAndRedis(request);
            if (result != null && result.getCode() == 200) {
                log.info("新单跟进-同步生成预计出账记录成功: 保单号={}", policyNo);
            }
            return result;
        } finally {
            // 必须清理，防止内存泄漏
            FeignTokenInterceptor.clearThreadLocalToken();
        }
    }

    @Async("commonAsyncExecutor")
    public void buildCalmDateTask(List<AlgorithmCollectResDto> collectResDtos, String policyNo,BigDecimal exchangeRate) {
        log.info("buildCalmDateTask=>汇率exchangeRate,{}",exchangeRate);
        if (CollectionUtils.isEmpty(collectResDtos)) {
            log.info("构建冷静期定时任务，collectResDtos 为空，policyNo: {}", policyNo);
            return;
        }

        // 新单跟进对象
        PolicyFollow policyFollow = policyFollowService.queryOneByPolicyNo(policyNo);
        if (policyFollow == null) {
            log.warn("未找到保单跟进记录，policyNo: {}", policyNo);
            return;
        }

        // 过滤掉 calculatedValue 为 0 的项，并收集所有有效的 AlgorithmResDto，返回新的List<AlgorithmCollectResDto>
        List<AlgorithmCollectResDto> filteredCollectResDtos = collectResDtos.stream()
                .map(dto -> {
                    List<AlgorithmResDto> originalList = dto.getAlgorithmResDtoList();
                    if (CollectionUtils.isEmpty(originalList)) {
                        return null;
                    }
                    List<AlgorithmResDto> validList = originalList.stream()
                            .filter(res -> res.getCalculatedValue() != null
                                    && res.getCalculatedValue().compareTo(BigDecimal.ZERO) != 0)
                            .collect(Collectors.toList());
                    if (validList.isEmpty()) {
                        return null;
                    }
                    // 创建新对象
                    AlgorithmCollectResDto newDto = new AlgorithmCollectResDto();
                    BeanUtils.copyProperties(dto, newDto);
                    newDto.setAlgorithmResDtoList(validList);
                    return newDto;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        log.info("过滤掉 calculatedValue 为 0 的项，并收集所有有效的 AlgorithmResDto，返回新的List<AlgorithmCollectResDto>=>返回数据：{}", JSON.toJSONString(filteredCollectResDtos));
        if (CollectionUtils.isEmpty(filteredCollectResDtos)) {
            log.info("过滤后无有效发佣数据，policyNo: {}", policyNo);
            return;
        }

        //去重获取转介人业务ID列表
        List<String> clientUserBizIdList = filteredCollectResDtos
                .stream()
                .map(AlgorithmCollectResDto::getClientUserBizId)
                .distinct()
                .collect(Collectors.toList());
        //查询转介人对应累计积分
        List<AgentAccumulatedFyc> accumulatedFycList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(clientUserBizIdList)) {
            accumulatedFycList = iAgentAccumulatedFycService.queryList(clientUserBizIdList);
        }
        log.info("查询转介人对应累计积分=>返回数据：{}",JSON.toJSONString(accumulatedFycList));

        //循环，构建同保单号多个转介人多个期数多个佣金项目的冷静期定时任务记录和积分明细记录
        for (AlgorithmCollectResDto resDto : filteredCollectResDtos) {
            if (CollectionUtils.isEmpty(resDto.getAlgorithmResDtoList())) {
                continue;
            }
            List<AgentAccumulatedFyc> filterList = accumulatedFycList
                    .stream()
                    .filter(dto -> dto.getAgentId().equals(resDto.getClientUserBizId()))
                    .collect(Collectors.toList());
            AgentAccumulatedFyc agentAccumulatedFyc = null;
            if (CollectionUtils.isNotEmpty(filterList)) {
                agentAccumulatedFyc = filterList.get(0);
            }

            //积分解冻时间
            LocalDateTime thawingTime = resDto.getThawingTime();

            // 介绍费占比
            String brokerRatio = resDto.getBrokerRatio();
            // 将 brokerRatio 转为小数乘数，如 "30" -> 0.3, "60" -> 0.6
            BigDecimal ratioFactor = BigDecimal.ZERO;
            try {
                BigDecimal ratioNum = new BigDecimal(brokerRatio);
                ratioFactor = ratioNum.divide(new BigDecimal("100"), 6, RoundingMode.HALF_UP); // 保留足够精度
            } catch (Exception e) {
                log.warn("brokerRatio 转换失败，使用 0，policyNo: {}, brokerRatio: {}", policyNo, brokerRatio);
            }

            for (AlgorithmResDto algorithmResDto : resDto.getAlgorithmResDtoList()) {
                // 原始佣金值
                BigDecimal originalFyc = algorithmResDto.getCalculatedValue();
                // 折后佣金值（乘以介绍费占比）
                BigDecimal effectiveFyc = originalFyc.multiply(ratioFactor);

                if (thawingTime != null && thawingTime.compareTo(LocalDateTime.now()) <= 0) {
                    //判断积分解冻时间（年月日 + 00:00:00）（冷静期时间 + 期数）是否小于等于当前时间（年月日时分秒）
                    //如果小于等于当前时间，不用走定时任务来解冻积分，应该及时生效积分

                    //业务员积分明细表唯一业务ID
                    String detailFycBizId = RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_AGENT_DETAIL_FYC.getCode());
                    //新增积分明细
                    //status 定时任务0-冻结。非定时任务1-生效
                    addAgentDetailFyc(resDto,policyNo,algorithmResDto,detailFycBizId,agentAccumulatedFyc,1,exchangeRate,effectiveFyc);

                }else if (thawingTime != null && thawingTime.compareTo(LocalDateTime.now()) > 0){
                    //判断积分解冻时间（年月日 + 00:00:00）（冷静期时间 + 期数）是否大于当前时间（年月日时分秒）
                    //如果大于当前时间，走定时任务来解冻积分。
                    CalmTask calmTask = new CalmTask();
                    //保单号
                    calmTask.setPolicyNo(policyNo);
                    //新单跟进唯一业务ID
                    calmTask.setPolicyBizId(policyFollow.getPolicyBizId());
                    //执行时间（定时任务执行时间） = 积分解冻时间
                    calmTask.setExecutionTime(resDto.getThawingTime());
                    //冷静期天数
                    calmTask.setCoolingOffDays(policyFollow.getCoolingOffDays());
                    //保单冷静期定时任务表唯一业务ID
                    calmTask.setCalmTaskBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_CALM_TASK.getCode()));
                    //执行状态（0-未执行，1-执行中，2-已执行，3-执行异常）
                    //0-未执行
                    calmTask.setExecutionStatus("0");
                    //转介人名称
                    calmTask.setBrokerName(resDto.getClientUserName());
                    //转介人业务id
                    calmTask.setBrokerBizId(resDto.getClientUserBizId());
                    //佣金项目
                    calmTask.setCommissionName(algorithmResDto.getItemName());
                    //发佣期数
                    calmTask.setFortunePeriod(resDto.getFortunePeriod());
                    //汇率转换前佣金值（积分值）
                    calmTask.setFyc(effectiveFyc);
                    //汇率（保单币种->港币的汇率）
                    calmTask.setExchangeRate(exchangeRate);
                    //汇率转换后佣金值（积分值）
                    calmTask.setAfterFyc(calmTask.getFyc().multiply(calmTask.getExchangeRate()));
                    //冷静期结束日期
                    calmTask.setCoolingOffEndDate(policyFollow.getCoolingOffEndDate());
                    //业务员积分明细表唯一业务ID
                    String detailFycBizId = RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_AGENT_DETAIL_FYC.getCode());
                    calmTask.setDetailFycBizId(detailFycBizId);
                    //积分来源基本法项目配置表唯一业务ID
                    calmTask.setRuleItemBizId(algorithmResDto.getRuleItemBizId());
                    iCalmTaskService.saveOrUpdate(calmTask);

                    //新增积分明细
                    //status 定时任务0-冻结。非定时任务1-生效
                    addAgentDetailFyc(resDto,policyNo,algorithmResDto,detailFycBizId,agentAccumulatedFyc,0,exchangeRate,effectiveFyc);

                    //创建XXL-Job定时任务
                    xxlJobService.addScheduleJob(calmTask.getCalmTaskBizId(),"冷静期定时发送任务-","calmSendJobHandler",Date.from(resDto.getThawingTime().atZone(ZoneId.systemDefault()).toInstant()));
                }
            }
        }

        //更新积分总表的值
        updateAgentAccumulatedFyc(accumulatedFycList,filteredCollectResDtos,exchangeRate);

    }

    /**
     * 新增积分明细
     * @param resDto
     * @param policyNo
     * @param algorithmResDto
     * @param detailFycBizId
     * @param agentAccumulatedFyc
     * @param status 定时任务0-冻结。非定时任务1-生效
     * @param effectiveFyc 折后佣金值（乘以介绍费占比）
     */
    public void addAgentDetailFyc(AlgorithmCollectResDto resDto,
                                  String policyNo,
                                  AlgorithmResDto algorithmResDto,
                                  String detailFycBizId,
                                  AgentAccumulatedFyc agentAccumulatedFyc,
                                  Integer status,
                                  BigDecimal exchangeRate,
                                  BigDecimal effectiveFyc) {
        //新增积分明细
        AgentDetailFyc agentDetailFyc = new AgentDetailFyc();
        //积分来源类型
        agentDetailFyc.setSourceType(FycSourceTypeEnum.CALM_TASK.getItemValue());
        //积分来源名称
        agentDetailFyc.setSourceName(FycSourceTypeEnum.CALM_TASK.getItemLabel());
        //佣金项目类型 TODO
//        agentDetailFyc.setCommissionType();
        //佣金项目名称
        agentDetailFyc.setCommissionName(algorithmResDto.getItemName());
        //业务员ID
        agentDetailFyc.setAgentId(resDto.getClientUserBizId());
        //业务员姓名
        agentDetailFyc.setAgentName(resDto.getClientUserName());
        //积分提供的保单号
        agentDetailFyc.setPolicyNo(policyNo);
        //发佣期数
        agentDetailFyc.setFortunePeriod(resDto.getFortunePeriod());
        //积分来源基本法项目配置表唯一业务ID
        agentDetailFyc.setRuleItemBizId(algorithmResDto.getRuleItemBizId());
        //业务员积分明细表唯一业务ID
        agentDetailFyc.setDetailFycBizId(detailFycBizId);
        //状态(0:停用（冻结） 1:启用（生效）)
        //冻结
        agentDetailFyc.setStatus(status);
        //积分解冻时间
        agentDetailFyc.setThawingTime(resDto.getThawingTime());
        //变化前的业务员总FYC积分（已生效+未生效）
        agentDetailFyc.setBeforeFyc(agentAccumulatedFyc != null ? agentAccumulatedFyc.getTotalFyc() : BigDecimal.ZERO);
        //汇率转化前积分值（变化值(-代表减少))
        agentDetailFyc.setChangeFyc(effectiveFyc);
        //变化后的业务员总FYC积分
        agentDetailFyc.setAfterFyc(agentDetailFyc.getBeforeFyc().add(effectiveFyc));
        //汇率（保单币种->港币的汇率）
        agentDetailFyc.setExchangeRate(exchangeRate);
        //汇率转化后积分值（变化值(-代表减少)) = 汇率转化前积分值 * 汇率
        agentDetailFyc.setChangeAfterFyc(agentDetailFyc.getChangeFyc().multiply(agentDetailFyc.getExchangeRate()));
        iAgentDetailFycService.saveOrUpdate(agentDetailFyc);

    }

    /**
     * 更新积分总表的值
     * @param accumulatedFycList
     * @param filteredCollectResDtos
     */
    public void updateAgentAccumulatedFyc(List<AgentAccumulatedFyc> accumulatedFycList,
                                          List<AlgorithmCollectResDto> filteredCollectResDtos,
                                          BigDecimal exchangeRate) {
        log.info("更新积分总表的值=>accumulatedFycList入参：{}",JSON.toJSONString(accumulatedFycList));
        log.info("更新积分总表的值=>filteredCollectResDtos入参：{}",JSON.toJSONString(filteredCollectResDtos));
        //更新积分总表的值，更新这个accumulatedFycList的每个对象里面的：未生效累计积分（不限业务场景）、累计积分 = 未生效累计积分 + 已生效累计积分、未生效累计首期佣金积分值（佣金场景）、未生效累计非首期佣金积分值（佣金场景）
        // 将查询到的累计积分列表转为 Map（便于更新）
        Map<String, AgentAccumulatedFyc> fycMap = accumulatedFycList.stream()
                .collect(Collectors.toMap(
                        AgentAccumulatedFyc::getAgentId,
                        Function.identity(),
                        (v1, v2) -> v1
                ));
        log.info("将查询到的累计积分列表转为 Map=>fycMap：{}",JSON.toJSONString(fycMap));

        // 构建每个转介人本次的积分增量 Map
        // 未生效个人累计积分增量（定时（冻结））
        Map<String, BigDecimal> noDeltaMap = new HashMap<>();
        // 未生效首期佣金增量（定时（冻结））
        Map<String, BigDecimal> noFirstCommissionDeltaMap = new HashMap<>();
        // 未生效非首期佣金增量（定时（冻结））
        Map<String, BigDecimal> noRycDeltaMap = new HashMap<>();
        // 未生效累计首期销售佣金积分值（销售佣金场景（佣金场景的其中一个））增量（定时（冻结））
        Map<String, BigDecimal> noFirstSalesCommissionDeltaMap = new HashMap<>();

        // 已生效个人累计积分增量（非定时（生效））
        Map<String, BigDecimal> deltaMap = new HashMap<>();
        // 已生效首期佣金增量（非定时（生效））
        Map<String, BigDecimal> firstCommissionDeltaMap = new HashMap<>();
        // 已生效非首期佣金增量（非定时（生效））
        Map<String, BigDecimal> rycDeltaMap = new HashMap<>();
        // 已生效累计首期销售佣金积分值（销售佣金场景（佣金场景的其中一个））增量（非定时（生效））
        Map<String, BigDecimal> firstSalesCommissionDeltaMap = new HashMap<>();

        //收集去重的转介人业务ID
        HashSet<String> hashSet = new HashSet<>();

        for (AlgorithmCollectResDto resDto : filteredCollectResDtos) {
            String agentId = resDto.getClientUserBizId();
            Integer fortunePeriod = resDto.getFortunePeriod();

            hashSet.add(agentId);

            // 介绍费占比
            String brokerRatio = resDto.getBrokerRatio();
            // 将 brokerRatio 转为小数乘数，如 "30" -> 0.3, "60" -> 0.6
            BigDecimal ratioFactor = BigDecimal.ZERO;
            try {
                BigDecimal ratioNum = new BigDecimal(brokerRatio);
                ratioFactor = ratioNum.divide(new BigDecimal("100"), 6, RoundingMode.HALF_UP); // 保留足够精度
            } catch (Exception e) {
                log.warn("brokerRatio 转换失败, brokerRatio: {}", brokerRatio);
            }

            //积分解冻时间
            LocalDateTime thawingTime = resDto.getThawingTime();
            for (AlgorithmResDto algorithmResDto : resDto.getAlgorithmResDtoList()) {
                // 原始佣金值
                BigDecimal originalFyc = algorithmResDto.getCalculatedValue();
                if (originalFyc == null) continue;
                // 折后佣金值（乘以介绍费占比）
                BigDecimal effectiveFyc = originalFyc.multiply(ratioFactor);
                //effectiveFyc汇率转换后的值
                effectiveFyc = effectiveFyc.multiply(exchangeRate);

                if (thawingTime != null && thawingTime.compareTo(LocalDateTime.now()) <= 0) {
                    //判断积分解冻时间（年月日 + 00:00:00）（冷静期时间 + 期数）是否小于等于当前时间（年月日时分秒）
                    //如果小于等于当前时间，不用走定时任务来解冻积分，应该及时生效积分
                    // 已生效个人累计积分增量（非定时（生效））
                    deltaMap.merge(agentId, effectiveFyc, BigDecimal::add);
                    // 根据期数判断佣金类型
                    if (fortunePeriod != null && fortunePeriod == 1) {
                        //已生效首期佣金增量（非定时（生效））
                        firstCommissionDeltaMap.merge(agentId, effectiveFyc, BigDecimal::add);

                        if (RuleItemEnum.SALES.getRuleItemBizId().equals(algorithmResDto.getRuleItemBizId())) {
                            //销售佣金项目
                            //已生效累计首期销售佣金积分值（销售佣金场景（佣金场景的其中一个））增量（非定时（生效））
                            firstSalesCommissionDeltaMap.merge(agentId, effectiveFyc, BigDecimal::add);
                        }
                    } else {
                        //已生效非首期佣金增量（非定时（生效））
                        rycDeltaMap.merge(agentId, effectiveFyc, BigDecimal::add);
                    }

                }else if (thawingTime != null && thawingTime.compareTo(LocalDateTime.now()) > 0){
                    //判断积分解冻时间（年月日 + 00:00:00）（冷静期时间 + 期数）是否大于当前时间（年月日时分秒）
                    //如果大于当前时间，走定时任务来解冻积分。
                    // 未生效个人累计积分增量（定时（冻结））
                    noDeltaMap.merge(agentId, effectiveFyc, BigDecimal::add);
                    // 根据期数判断佣金类型
                    if (fortunePeriod != null && fortunePeriod == 1) {
                        //未生效首期佣金增量（定时（冻结））
                        noFirstCommissionDeltaMap.merge(agentId, effectiveFyc, BigDecimal::add);

                        if (RuleItemEnum.SALES.getRuleItemBizId().equals(algorithmResDto.getRuleItemBizId())) {
                            //销售佣金项目
                            //未生效累计首期销售佣金积分值（销售佣金场景（佣金场景的其中一个））增量（定时（冻结））
                            noFirstSalesCommissionDeltaMap.merge(agentId, effectiveFyc, BigDecimal::add);
                        }
                    } else {
                        //未生效非首期佣金增量（定时（冻结））
                        noRycDeltaMap.merge(agentId, effectiveFyc, BigDecimal::add);
                    }
                }
            }
        }
        log.info("收集去重的转介人业务ID=>hashSet：{}",JSON.toJSONString(hashSet));

        log.info("未生效个人累计积分增量（定时（冻结））=>noDeltaMap：{}",JSON.toJSONString(noDeltaMap));
        log.info("未生效首期佣金增量（定时（冻结））=>noFirstCommissionDeltaMap：{}",JSON.toJSONString(noFirstCommissionDeltaMap));
        log.info("未生效非首期佣金增量（定时（冻结））=>noRycDeltaMap：{}",JSON.toJSONString(noRycDeltaMap));
        log.info("已生效个人累计积分增量（非定时（生效））=>deltaMap：{}",JSON.toJSONString(deltaMap));
        log.info("已生效首期佣金增量（非定时（生效））=>firstCommissionDeltaMap：{}",JSON.toJSONString(firstCommissionDeltaMap));
        log.info("已生效非首期佣金增量（非定时（生效））=>rycDeltaMap：{}",JSON.toJSONString(rycDeltaMap));
        log.info("已生效累计首期销售佣金积分值（销售佣金场景（佣金场景的其中一个））增量（非定时（生效））=>firstSalesCommissionDeltaMap：{}",JSON.toJSONString(firstSalesCommissionDeltaMap));
        log.info("未生效累计首期销售佣金积分值（销售佣金场景（佣金场景的其中一个））增量（定时（冻结））=>noFirstSalesCommissionDeltaMap：{}",JSON.toJSONString(noFirstSalesCommissionDeltaMap));

        // 更新或新建累计积分记录
        List<AgentAccumulatedFyc> toUpdateList = new ArrayList<>();
        for (String agentId : hashSet) {
            //已生效个人累计积分增量（非定时（生效））
            BigDecimal delta = deltaMap.get(agentId);
            //未生效个人累计积分增量（定时（冻结））
            BigDecimal noDelta = noDeltaMap.get(agentId);

            //未生效首期佣金增量（定时（冻结））
            BigDecimal noFirstDelta = noFirstCommissionDeltaMap.getOrDefault(agentId, BigDecimal.ZERO);
            //未生效非首期佣金增量（定时（冻结））
            BigDecimal noRycDelta = noRycDeltaMap.getOrDefault(agentId, BigDecimal.ZERO);

            //已生效首期佣金增量（非定时（生效））
            BigDecimal firstDelta = firstCommissionDeltaMap.getOrDefault(agentId, BigDecimal.ZERO);
            //已生效非首期佣金增量（非定时（生效））
            BigDecimal rycDelta = rycDeltaMap.getOrDefault(agentId, BigDecimal.ZERO);

            //已生效累计首期销售佣金积分值（销售佣金场景（佣金场景的其中一个））增量（非定时（生效））
            BigDecimal firstSalesDelta = firstSalesCommissionDeltaMap.getOrDefault(agentId, BigDecimal.ZERO);
            //未生效累计首期销售佣金积分值（销售佣金场景（佣金场景的其中一个））增量（定时（冻结））
            BigDecimal noFirstSalesDelta = noFirstSalesCommissionDeltaMap.getOrDefault(agentId, BigDecimal.ZERO);

            AgentAccumulatedFyc fyc = fycMap.get(agentId);
            if (fyc == null) {
                continue;
            }

            // 增量值安全处理：get 可能返回 null，统一转为 ZERO
            BigDecimal safeDelta = delta == null ? BigDecimal.ZERO : delta;
            BigDecimal safeNoDelta = noDelta == null ? BigDecimal.ZERO : noDelta;
            BigDecimal safeNoFirstDelta = noFirstDelta == null ? BigDecimal.ZERO : noFirstDelta;
            BigDecimal safeNoRycDelta = noRycDelta == null ? BigDecimal.ZERO : noRycDelta;
            BigDecimal safeFirstDelta = firstDelta == null ? BigDecimal.ZERO : firstDelta;
            BigDecimal safeRycDelta = rycDelta == null ? BigDecimal.ZERO : rycDelta;
            BigDecimal safeFirstSalesDelta = firstSalesDelta == null ? BigDecimal.ZERO : firstSalesDelta;
            BigDecimal safeNoFirstSalesDelta = noFirstSalesDelta == null ? BigDecimal.ZERO : noFirstSalesDelta;

            // 原有字段安全处理：fyc 中的字段可能为 null，转为 ZERO 再进行 add
            BigDecimal effectOld = fyc.getEffect() == null ? BigDecimal.ZERO : fyc.getEffect();
            BigDecimal noEffectOld = fyc.getNoEffect() == null ? BigDecimal.ZERO : fyc.getNoEffect();
            BigDecimal noFirstCommissionOld = fyc.getNoFirstCommission() == null ? BigDecimal.ZERO : fyc.getNoFirstCommission();
            BigDecimal noRycOld = fyc.getNoRyc() == null ? BigDecimal.ZERO : fyc.getNoRyc();
            BigDecimal firstCommissionOld = fyc.getFirstCommission() == null ? BigDecimal.ZERO : fyc.getFirstCommission();
            BigDecimal rycOld = fyc.getRyc() == null ? BigDecimal.ZERO : fyc.getRyc();
            BigDecimal firstSalesCommissionOld = fyc.getFirstSalesCommission() == null ? BigDecimal.ZERO : fyc.getFirstSalesCommission();
            BigDecimal noFirstSalesCommissionOld = fyc.getNoFirstSalesCommission() == null ? BigDecimal.ZERO : fyc.getNoFirstSalesCommission();

            // 应用增量
            //未生效累计积分（不限业务场景）
            fyc.setNoEffect(noEffectOld.add(safeNoDelta));

            //未生效累计首期佣金积分值（佣金场景）
            fyc.setNoFirstCommission(noFirstCommissionOld.add(safeNoFirstDelta));

            //未生效累计非首期佣金积分值（佣金场景）
            fyc.setNoRyc(noRycOld.add(safeNoRycDelta));

            //已生效累计积分（不限业务场景）
            fyc.setEffect(effectOld.add(safeDelta));

            //已生效累计首期佣金积分值（佣金场景）
            fyc.setFirstCommission(firstCommissionOld.add(safeFirstDelta));

            //已生效累计非首期佣金积分值（佣金场景）
            fyc.setRyc(rycOld.add(safeRycDelta));

            //累计积分 = 未生效累计积分 + 已生效累计积分
            fyc.setTotalFyc(fyc.getNoEffect().add(fyc.getEffect()));

            //已生效累计首期销售佣金积分值（销售佣金场景（佣金场景的其中一个））增量（非定时（生效））
            fyc.setFirstSalesCommission(firstSalesCommissionOld.add(safeFirstSalesDelta));

            //未生效累计首期销售佣金积分值（销售佣金场景（佣金场景的其中一个））增量（定时（冻结））
            fyc.setNoFirstSalesCommission(noFirstSalesCommissionOld.add(safeNoFirstSalesDelta));

            //晋升职级累计积分 = 初始化已生效积分（不限业务场景） +  已生效累计首期销售佣金积分值（销售佣金场景（佣金场景的其中一个））
            BigDecimal promotion = fyc.getInitEffect().add(fyc.getFirstSalesCommission());
            fyc.setPromotion(promotion.compareTo(BigDecimal.ZERO) <= 0 ?  BigDecimal.ZERO : promotion);

            //最后计算日期，记录最后一次计算累计FYC的日期
            fyc.setLastCalcDate(LocalDateTime.now());
            toUpdateList.add(fyc);
        }

        log.info("更新或新建累计积分记录=>toUpdateList：{}",JSON.toJSONString(toUpdateList));

        // 批量保存
        if (CollectionUtils.isNotEmpty(toUpdateList)) {
            iAgentAccumulatedFycService.saveOrUpdateBatch(toUpdateList);
            log.info("更新业务员累计积分完成，涉及人数: {}", toUpdateList.size());

            //批量新增积分总表日志表
            List<AgentAccumulatedFycLog> saveLogList = toUpdateList.stream().map(dto -> {
                AgentAccumulatedFycLog log = new AgentAccumulatedFycLog();
                BeanUtils.copyProperties(dto,log);
                log.setId(null);
                log.setFycBizId(dto.getFycBizId());
                log.setFycLogBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_AGENT_ACCUMULATED_FYC_LOG.getCode()));
                //操作来源枚举-冻结
                log.setSourceType(OprSourceEnum.CALM_TASK_FREEZE.getItemValue());
                log.setCreateTime(LocalDateTime.now());
                log.setUpdateTime(LocalDateTime.now());
                return log;
            }).collect(Collectors.toList());
            iAgentAccumulatedFycLogService.saveOrUpdateBatch(saveLogList);
        }
    }


}