package com.yd.csf.api.async;

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.request.expectedfortune.ApiGenerateExpectedFortuneRequest;
import com.yd.csf.feign.response.expectedfortune.ApiGenerateExpectedFortuneResponse;
import com.yd.csf.service.model.CalmTask;
import com.yd.csf.service.model.Policy;
import com.yd.csf.service.model.PolicyFollow;
import com.yd.csf.service.service.ICalmTaskService;
import com.yd.csf.service.service.PolicyFollowService;
import com.yd.csf.service.service.PolicyService;
import com.yd.feign.config.FeignTokenInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
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 PolicyService policyService;
    @Resource
    private ICalmTaskService iCalmTaskService;
    @Resource
    private XxlJobService xxlJobService;

    /**
     * 异步处理-执行预计发拥数据
     *
     * @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();
        }
    }

//    /**
//     * 异步处理-构建冷静期定时任务
//     * @param collectResDtos
//     */
//    @Async("commonAsyncExecutor")
//    public void buildCalmDateTask(List<AlgorithmCollectResDto> collectResDtos,String policyNo){
//        //collectResDtos要分组，分组条件是clientUserBizId，sumCalculatedValue和commissionName需要分组统计计算，拿到分组后的创建新的List<AlgorithmCollectResDto>返回
//
//    }

    /**
     * 异步处理-构建冷静期定时任务
     * @param collectResDtos 原始计算结果收集列表
     * @param policyNo 保单号
     */
    @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);
        //保单对象
//        Policy policy = policyService.queryOne(policyNo);

        // 按 clientUserBizId 分组，计算每个用户的 sumCalculatedValue 和 commissionName
        Map<String, AlgorithmCollectResDto> groupedMap = collectResDtos.stream()
                .filter(dto -> StringUtils.isNotBlank(dto.getClientUserBizId()))
                .collect(Collectors.toMap(
                        AlgorithmCollectResDto::getClientUserBizId,
                        Function.identity(),
                        (existing, replacement) -> {
                            // 合并：累加 sumCalculatedValue，合并 commissionName
                            BigDecimal sum1 = existing.getSumCalculatedValue() != null ? existing.getSumCalculatedValue() : BigDecimal.ZERO;
                            BigDecimal sum2 = calculateSumFromResList(replacement.getAlgorithmResDtoList());
                            existing.setSumCalculatedValue(sum1.add(sum2));

                            String commission1 = existing.getCommissionName() != null ? existing.getCommissionName() : "";
                            String commission2 = buildCommissionName(replacement.getAlgorithmResDtoList());
                            existing.setCommissionName(mergeCommissionNames(commission1, commission2));
                            return existing;
                        }
                ));

        // 构造calmTask列表返回
        List<CalmTask> resultList = groupedMap.values().stream().map(dto -> {
            //计算合计值
            BigDecimal totalSum = dto.getSumCalculatedValue();
            if (totalSum == null || (totalSum != null && totalSum.compareTo(BigDecimal.ZERO) == 0)) {
                //计算合计值为空或者0，直接返回null，不构造此CalmTask对象。
                return null;
            }
            CalmTask calmTask = new CalmTask();
            calmTask.setBrokerBizId(dto.getClientUserBizId());
            calmTask.setBrokerName(dto.getClientUserName());
            //当前保单转介人累计FYC（当前保单转介人基本法计算积分合值）
            calmTask.setTotalFyc(totalSum);
            calmTask.setCommissionName(dto.getCommissionName());
            //执行状态->未执行
            calmTask.setExecutionStatus("0");
            calmTask.setCalmTaskBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_CALM_TASK.getCode()));
            //冷静期天数
            calmTask.setCoolingOffDays(policyFollow.getCoolingOffDays());
            //冷静期结束日期
            calmTask.setCoolingOffEndDate(policyFollow.getCoolingOffEndDate());
            //执行时间（定时任务执行时间）
            calmTask.setExecutionTime(policyFollow.getCoolingOffEndDate().toInstant()
                    .atZone(ZoneId.of("Asia/Shanghai"))
                    .toLocalDateTime());
            //新单跟进唯一业务ID
            calmTask.setPolicyBizId(policyFollow.getPolicyBizId());
            //保单号
            calmTask.setPolicyNo(policyNo);
            return calmTask;
        }).collect(Collectors.toList());
        iCalmTaskService.saveOrUpdateBatch(resultList);
        log.info("完成基本法分组计算，policyNo: {}, 分组后用户数: {}", policyNo, resultList.size());

        // 构建冷静期定时任务逻辑
        //创建XXL-Job定时任务
        if (CollectionUtils.isNotEmpty(resultList)) {
            //循环创建定时任务（多个冷静期的定时任务）
            for (CalmTask calmTask : resultList) {
                xxlJobService.addScheduleJob(calmTask.getCalmTaskBizId(),"冷静期定时发送任务-","calmSendJobHandler",calmTask.getCoolingOffEndDate());
            }
        }

    }

    /**
     * 从 AlgorithmResDto 列表中计算所有 calculatedValue 的总和
     */
    private BigDecimal calculateSumFromResList(List<AlgorithmResDto> resDtoList) {
        if (CollectionUtils.isEmpty(resDtoList)) {
            return BigDecimal.ZERO;
        }
        return resDtoList.stream()
                .map(AlgorithmResDto::getCalculatedValue)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * 从 AlgorithmResDto 列表中构建去重后的佣金项目名称（分号拼接）
     */
    private String buildCommissionName(List<AlgorithmResDto> resDtoList) {
        if (CollectionUtils.isEmpty(resDtoList)) {
            return "";
        }
        return resDtoList.stream()
                .map(AlgorithmResDto::getItemName)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.joining(";"));
    }

    /**
     * 合并两个佣金名称字符串（去重后用分号拼接）
     */
    private String mergeCommissionNames(String name1, String name2) {
        Set<String> nameSet = new LinkedHashSet<>();
        if (StringUtils.isNotBlank(name1)) {
            nameSet.addAll(Arrays.asList(name1.split(";")));
        }
        if (StringUtils.isNotBlank(name2)) {
            nameSet.addAll(Arrays.asList(name2.split(";")));
        }
        return String.join(";", nameSet);
    }
}
