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.model.*;
import com.yd.csf.service.service.*;
import com.yd.feign.config.FeignTokenInterceptor;
import lombok.extern.slf4j.Slf4j;
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.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) {
        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);
            }

            for (AlgorithmResDto algorithmResDto : resDto.getAlgorithmResDtoList()) {
                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(algorithmResDto.getCalculatedValue());
                //冷静期结束日期
                calmTask.setCoolingOffEndDate(policyFollow.getCoolingOffEndDate());
                //业务员积分明细表唯一业务ID
                String detailFycBizId = RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_AGENT_DETAIL_FYC.getCode());
                calmTask.setDetailFycBizId(detailFycBizId);
                iCalmTaskService.saveOrUpdate(calmTask);

                //新增积分明细
                addAgentDetailFyc(resDto,policyNo,algorithmResDto,detailFycBizId,agentAccumulatedFyc);

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

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

    }

    /**
     * 新增积分明细
     * @param resDto
     * @param policyNo
     * @param algorithmResDto
     * @param detailFycBizId
     * @param agentAccumulatedFyc
     */
    public void addAgentDetailFyc(AlgorithmCollectResDto resDto,
                                  String policyNo,
                                  AlgorithmResDto algorithmResDto,
                                  String detailFycBizId,
                                  AgentAccumulatedFyc agentAccumulatedFyc) {
        //新增积分明细
        AgentDetailFyc agentDetailFyc = new AgentDetailFyc();
        //积分来源类型
        agentDetailFyc.setSourceType(FycSourceTypeEnum.CALM_TASK.getItemValue());
        //业务员ID
        agentDetailFyc.setAgentId(resDto.getClientUserBizId());
        //积分提供的保单号
        agentDetailFyc.setPolicyNo(policyNo);
        //积分来源基本法项目配置表唯一业务ID
        agentDetailFyc.setRuleItemBizId(algorithmResDto.getRuleItemBizId());
        //业务员积分明细表唯一业务ID
        agentDetailFyc.setDetailFycBizId(detailFycBizId);
        //状态(0:停用（冻结） 1:启用（生效）)
        //冻结
        agentDetailFyc.setStatus(0);
        //积分解冻时间
        agentDetailFyc.setThawingTime(resDto.getThawingTime());
        //变化前的业务员总FYC积分（已生效+未生效）
        agentDetailFyc.setBeforeFyc(agentAccumulatedFyc != null ? agentAccumulatedFyc.getTotalFyc() : BigDecimal.ZERO);
        //变化值（-代表减少）
        agentDetailFyc.setChangeFyc(algorithmResDto.getCalculatedValue().toString());
        //变化后的业务员总FYC积分
        agentDetailFyc.setAfterFyc(agentDetailFyc.getBeforeFyc().add(algorithmResDto.getCalculatedValue()));
        iAgentDetailFycService.saveOrUpdate(agentDetailFyc);

    }

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

        // 构建每个转介人本次的积分增量 Map
        // 未生效累计积分增量
        Map<String, BigDecimal> noEffectDeltaMap = new HashMap<>();
        // 未生效首期佣金增量
        Map<String, BigDecimal> noFirstCommissionDeltaMap = new HashMap<>();
        // 未生效非首期佣金增量
        Map<String, BigDecimal> noRycDeltaMap = new HashMap<>();

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

            for (AlgorithmResDto algorithmResDto : resDto.getAlgorithmResDtoList()) {
                BigDecimal val = algorithmResDto.getCalculatedValue();
                if (val == null) continue;

                // 累加 noEffect 增量
                noEffectDeltaMap.merge(agentId, val, BigDecimal::add);

                // 根据期数判断佣金类型
                if (fortunePeriod != null && fortunePeriod == 1) {
                    noFirstCommissionDeltaMap.merge(agentId, val, BigDecimal::add);
                } else {
                    noRycDeltaMap.merge(agentId, val, BigDecimal::add);
                }
            }
        }

        // 更新或新建累计积分记录
        List<AgentAccumulatedFyc> toUpdateList = new ArrayList<>();
        for (String agentId : noEffectDeltaMap.keySet()) {
            BigDecimal noEffectDelta = noEffectDeltaMap.get(agentId);
            BigDecimal noFirstDelta = noFirstCommissionDeltaMap.getOrDefault(agentId, BigDecimal.ZERO);
            BigDecimal noRycDelta = noRycDeltaMap.getOrDefault(agentId, BigDecimal.ZERO);

            AgentAccumulatedFyc fyc = fycMap.get(agentId);
            if (fyc == null) {
                continue;
            }
            // 应用增量
            //未生效累计积分（不限业务场景）
            fyc.setNoEffect(fyc.getNoEffect().add(noEffectDelta));
            //未生效累计首期佣金积分值（佣金场景）
            fyc.setNoFirstCommission(fyc.getNoFirstCommission().add(noFirstDelta));
            //未生效累计非首期佣金积分值（佣金场景）
            fyc.setNoRyc(fyc.getNoRyc().add(noRycDelta));
            //累计积分 = 未生效累计积分 + 已生效累计积分
            fyc.setTotalFyc(fyc.getNoEffect().add(fyc.getEffect()));

            toUpdateList.add(fyc);
        }

        // 批量保存
        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());
                return log;
            }).collect(Collectors.toList());
            iAgentAccumulatedFycLogService.saveOrUpdateBatch(saveLogList);
        }
    }


}