package com.yd.csf.service.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yd.common.constant.CommonConstant;
import com.yd.common.constant.RedisConstants;
import com.yd.common.enums.ResultCode;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.common.utils.RedisUtil;
import com.yd.csf.service.component.ReceivableService;
import com.yd.csf.service.dto.*;
import com.yd.csf.service.enums.CommissionExpectedStatusEnum;
import com.yd.csf.service.model.Commission;
import com.yd.csf.service.model.CommissionExpected;
import com.yd.csf.service.model.Policy;
import com.yd.csf.service.service.*;
import com.yd.csf.service.dao.CommissionExpectedMapper;
import com.yd.csf.service.vo.CommissionExpectedStatisticsVO;
import com.yd.csf.service.vo.CommissionExpectedVO;
import com.yd.csf.service.vo.ReceivableReportVO;
import com.yd.product.feign.client.announcementcommissionratio.ApiAnnouncementCommissionRatioFeignClient;
import com.yd.product.feign.client.expectedspecies.ApiExpectedSpeciesFeignClient;
import com.yd.product.feign.request.expectedspecies.ApiExpectedSpeciesListRequest;
import com.yd.product.feign.response.expectedspecies.ApiExpectedSpeciesListResponse;
import com.yd.user.feign.client.sysdict.ApiSysDictFeignClient;
import com.yd.user.feign.response.sysdict.GetDictItemListByDictTypeResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Zhang Jianan
 * @description 针对表【commission_expected(预计入账表)】的数据库操作Service实现
 * @createDate 2025-10-08 19:47:40
 */
@Service
@Slf4j
public class CommissionExpectedServiceImpl extends ServiceImpl<CommissionExpectedMapper, CommissionExpected>
        implements CommissionExpectedService {

    @Resource
    private PolicyService policyService;
    @Resource
    private PolicyFollowService policyFollowService;
    @Resource
    private CommissionService commissionService;
    @Resource
    private ReceivableService receivableService;
    @Autowired
    private ApiSysDictFeignClient apiSysDictFeignClient;
    @Resource
    private ApiExpectedSpeciesFeignClient apiExpectedSpeciesFeignClient;
    @Resource
    private ApiAnnouncementCommissionRatioFeignClient apiAnnouncementCommissionRatioFeignClient;
    @Resource
    private RedisUtil redisUtil;


    @Override
    public Page<CommissionExpectedVO> getCommissionExpectedVOPage(Page<CommissionExpected> commissionExpectedPage) {
        List<CommissionExpected> CommissionExpectedList = commissionExpectedPage.getRecords();
        Page<CommissionExpectedVO> CommissionExpectedVOPage = new Page<>(commissionExpectedPage.getCurrent(), commissionExpectedPage.getSize(), commissionExpectedPage.getTotal());
        if (CollUtil.isEmpty(CommissionExpectedList)) {
            return CommissionExpectedVOPage;
        }

        // 关联查询保单信息
        Set<String> policyNoSet = CommissionExpectedList.stream().map(CommissionExpected::getPolicyNo).collect(Collectors.toSet());
        QueryWrapper<Policy> queryWrapper = new QueryWrapper<Policy>();
        queryWrapper.select("policy_no", "payment_premium", "product_name", "insurance_company", "reconciliation_company", "currency");
        queryWrapper.in("policy_no", policyNoSet);
        List<Policy> policyList = policyService.list(queryWrapper);
        Map<String, Policy> policyMap = policyList.stream().collect(Collectors.toMap(Policy::getPolicyNo, a -> a, (oldValue, newValue) -> newValue));

        // 填充信息
        List<CommissionExpectedVO> CommissionExpectedVOList = CommissionExpectedList.stream().map(commissionExpected -> {
            CommissionExpectedVO commissionExpectedVO = CommissionExpectedVO.objToVo(commissionExpected);
            Policy policy = policyMap.get(commissionExpected.getPolicyNo());
            if (policy != null) {
                // 填充保费、产品名称、保险公司、对账公司
                commissionExpectedVO.setPremium(policy.getPaymentPremium());
                commissionExpectedVO.setProductName(policy.getProductName());
                commissionExpectedVO.setInsuranceCompany(policy.getInsuranceCompany());
                commissionExpectedVO.setReconciliationCompany(policy.getReconciliationCompany());
                commissionExpectedVO.setPolicyCurrency(policy.getCurrency());
            }
            return commissionExpectedVO;
        }).collect(Collectors.toList());
        CommissionExpectedVOPage.setRecords(CommissionExpectedVOList);
        return CommissionExpectedVOPage;
    }

    /**
     * 校验数据
     *
     * @param commissionExpected
     * @param add                对创建的数据进行校验
     */
    @Override
    public void validCommissionExpected(CommissionExpected commissionExpected, boolean add) {
        if (commissionExpected == null) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "预计入账对象不能为空");
        }
        // 入账业务类型不能为空
        String commissionBizType = commissionExpected.getCommissionBizType();
        if (ObjectUtils.isEmpty(commissionBizType)) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "应收款类型不能为空");
        }
        if (ObjectUtils.isEmpty(commissionExpected.getCommissionName())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "应收款名称不能为空");
        }
        if ("R".equals(commissionBizType)) {
            // 关联保单应收单，保单号不能为空
            String policyNo = commissionExpected.getPolicyNo();
            if (StringUtils.isBlank(policyNo)) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "保单号不能为空");
            }
            String commissionName = commissionExpected.getCommissionName();
            if (StringUtils.isBlank(commissionName)) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账名称不能为空");
            }
            BigDecimal commissionRatio = commissionExpected.getCommissionRatio();
            if (ObjectUtils.isEmpty(commissionRatio)) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账比例不能为空");
            }
            if (StringUtils.isBlank(commissionExpected.getCurrency())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账币种不能为空");
            }
            Integer commissionPeriod = commissionExpected.getCommissionPeriod();
            if (ObjectUtils.isEmpty(commissionPeriod)) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "佣金期数不能为空");
            }
            Integer totalPeriod = commissionExpected.getTotalPeriod();
            if (ObjectUtils.isEmpty(totalPeriod)) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "总入账期数不能为空");
            }
        }
        if ("U".equals(commissionBizType)) {
            if (ObjectUtils.isEmpty(commissionExpected.getAmount())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账金额不能为空");
            }
            if (StringUtils.isBlank(commissionExpected.getCurrency())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账币种不能为空");
            }
        }
        // 创建数据时，参数不能为空
        if (add) {
            // todo 补充校验规则
//            ThrowUtils.throwIf(StringUtils.isBlank(title), ErrorCode.PARAMS_ERROR);
        }
    }

    /**
     * 获取查询条件
     *
     * @param commissionExpectedQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<CommissionExpected> getQueryWrapper(CommissionExpectedQueryRequest commissionExpectedQueryRequest) {
        QueryWrapper<CommissionExpected> queryWrapper = new QueryWrapper<>();
        if (commissionExpectedQueryRequest == null) {
            return queryWrapper;
        }
        // 获取查询参数
        String receivableNo = commissionExpectedQueryRequest.getReceivableNo();
        String policyNo = commissionExpectedQueryRequest.getPolicyNo();
        String commissionType = commissionExpectedQueryRequest.getCommissionType();
        List<String> insurerCompanyBizIdList = commissionExpectedQueryRequest.getInsurerCompanyBizIdList();
        List<String> reconciliationCompanyBizIdList = commissionExpectedQueryRequest.getReconciliationCompanyBizIdList();
        List<String> statusList = commissionExpectedQueryRequest.getStatusList();
        Date commissionDateStart = commissionExpectedQueryRequest.getCommissionDateStart();
        Date commissionDateEnd = commissionExpectedQueryRequest.getCommissionDateEnd();
        Integer commissionPeriod = commissionExpectedQueryRequest.getCommissionPeriod();
        String productLaunchBizId = commissionExpectedQueryRequest.getProductLaunchBizId();
        String commissionBizType = commissionExpectedQueryRequest.getCommissionBizType();
        String teamBizId = commissionExpectedQueryRequest.getTeamBizId();
        // 精确查询
        queryWrapper.eq(ObjectUtils.isNotEmpty(receivableNo), "receivable_no", receivableNo);
        queryWrapper.eq(ObjectUtils.isNotEmpty(policyNo), "policy_no", policyNo);
        queryWrapper.eq(ObjectUtils.isNotEmpty(commissionType), "commission_type", commissionType);
        queryWrapper.in(ObjectUtils.isNotEmpty(insurerCompanyBizIdList), "insurance_company_biz_id", insurerCompanyBizIdList);
        queryWrapper.in(ObjectUtils.isNotEmpty(reconciliationCompanyBizIdList), "reconciliation_company_biz_id", reconciliationCompanyBizIdList);
        queryWrapper.eq(ObjectUtils.isNotEmpty(commissionPeriod), "commission_period", commissionPeriod);
        queryWrapper.eq(ObjectUtils.isNotEmpty(productLaunchBizId), "product_launch_biz_id", productLaunchBizId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(commissionBizType), "commission_biz_type", commissionBizType);
        queryWrapper.in(ObjectUtils.isNotEmpty(statusList), "status", statusList);
        // 范围查询
        queryWrapper.gt(ObjectUtils.isNotEmpty(commissionDateStart), "commission_date", commissionDateStart);
        queryWrapper.lt(ObjectUtils.isNotEmpty(commissionDateEnd), "commission_date", commissionDateEnd);
        // 转介人所属团队业务ID 关联保单表查询
        if (StringUtils.isNotBlank(teamBizId)) {
            queryWrapper.apply("EXISTS (SELECT 1 FROM policy_broker pb WHERE pb.policy_no = commission_expected.policy_no AND pb.team_biz_id = {0})",
                    teamBizId);
        }
        // 默认排序规则
        queryWrapper.orderByDesc("commission_date");
        // 排序字段
        String sortField = commissionExpectedQueryRequest.getSortField();
        String sortOrder = commissionExpectedQueryRequest.getSortOrder();
        queryWrapper.orderBy(ObjectUtils.isNotEmpty(sortField) && sortField.equals("reconciliation_company"), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        queryWrapper.orderBy(ObjectUtils.isNotEmpty(sortField) && sortField.equals("commission_name"), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        queryWrapper.orderBy(ObjectUtils.isNotEmpty(sortField) && sortField.equals("commission_period"), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        queryWrapper.orderBy(ObjectUtils.isNotEmpty(sortField) && sortField.equals("amount"), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }

    /**
     * 获取预计入账封装
     *
     * @param commissionExpected
     * @return
     */
    @Override
    public CommissionExpectedVO getCommissionExpectedVO(CommissionExpected commissionExpected) {
        // 对象转封装类
        CommissionExpectedVO commissionExpectedVO = CommissionExpectedVO.objToVo(commissionExpected);

        // 查询已入账入账记录
        List<Commission> commissionList = commissionService.list(new QueryWrapper<Commission>().eq("commissionExpectedBizId", commissionExpected.getCommissionExpectedBizId()));
        // 关联已入账入账记录
        commissionExpectedVO.setCommissionList(commissionList);

        return commissionExpectedVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addCommissionExpected(CommissionExpectedAddRequest commissionExpectedAddRequest) {
        List<CommissionExpectedAddDto> addDtoList = commissionExpectedAddRequest.getCommissionExpectedAddDtoList();
        if (CollUtil.isEmpty(addDtoList)) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "预计入账列表不能为空");
        }
        validateAddCommissionExpected(addDtoList);

        // 查询保单信息
        Set<String> policyNoSet = addDtoList.stream()
                .map(CommissionExpectedAddDto::getPolicyNo)
                .filter(StringUtils::isNotBlank).collect(Collectors.toSet());

        Map<String, Policy> policyMap = new HashMap<>();
        if (CollUtil.isNotEmpty(policyNoSet)) {
            List<Policy> policyList = policyService.lambdaQuery().in(Policy::getPolicyNo, policyNoSet).list();
            // 保单映射
            policyMap = policyList.stream().collect(Collectors.toMap(Policy::getPolicyNo, Function.identity()));
        }

        List<CommissionExpected> addList = new ArrayList<>();
        List<CommissionExpected> updateList = new ArrayList<>();
        for (CommissionExpectedAddDto addDto : addDtoList) {
            CommissionExpected commissionExpected = new CommissionExpected();
            BeanUtils.copyProperties(addDto, commissionExpected);
            // 默认已入账金额为 0
            commissionExpected.setPaidAmount(BigDecimal.ZERO);
            commissionExpected.setPaidRatio(BigDecimal.ZERO);
            // 校验参数
            validCommissionExpected(commissionExpected, true);
            // 结算汇率初始值为 1
            commissionExpected.setDefaultExchangeRate(BigDecimal.valueOf(1));
            // 查询默认结算汇率
            commissionExpected.setDefaultExchangeRate(queryDefaultExchangeRate(addDto.getCurrency()));

            // 预计总金额
            if ("R".equals(addDto.getCommissionBizType())) {
                Policy policy = policyMap.get(addDto.getPolicyNo());
                if (ObjectUtils.isEmpty(policy)) {
                    throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "保单号为" + addDto.getPolicyNo() + "的保单不存在");
                }
                BigDecimal expectedAmount = policy.getPaymentPremium()
                        .multiply(commissionExpected.getCommissionRatio())
                        .multiply(commissionExpected.getDefaultExchangeRate())
                        .divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP);

                commissionExpected.setExpectedAmount(expectedAmount);
                // 设置关联字段
                commissionExpected.setInsuranceCompanyBizId(policy.getInsuranceCompanyBizId());
                commissionExpected.setProductLaunchBizId(policy.getProductLaunchBizId());
                commissionExpected.setPremium(policy.getPaymentPremium());
            } else {
                BigDecimal expectedAmount = addDto.getAmount()
                        .multiply(commissionExpected.getDefaultExchangeRate());
                commissionExpected.setExpectedAmount(expectedAmount);
            }

            if (StringUtils.isBlank(addDto.getCommissionExpectedBizId())) {
                // 生成应收账款编号
                commissionExpected.setReceivableNo(receivableService.generateReceivableNo(addDto.getCommissionBizType(), addDto.getReconciliationCompanyCode(), addDto.getReconciliationCompany()));
                // 生成新单编号
                commissionExpected.setCommissionExpectedBizId(RandomStringGenerator.generateBizId16("commission_expected"));
                commissionExpected.setCreateTime(new Date());
                commissionExpected.setUpdateTime(new Date());
                // 设置默认状态
                commissionExpected.setStatus(CommissionExpectedStatusEnum.PENDING.getItemValue());
                addList.add(commissionExpected);
            } else {
                commissionExpected.setUpdateTime(new Date());
                updateList.add(commissionExpected);
            }
        }
        // 新增预计入账
        if (CollectionUtils.isNotEmpty(addList)) {
            this.saveBatch(addList);
        }
        if (CollectionUtils.isNotEmpty(updateList)) {
            List<String> bizIdList = updateList.stream().map(CommissionExpected::getCommissionExpectedBizId).collect(Collectors.toList());
            List<CommissionExpected> list = this.list(new QueryWrapper<CommissionExpected>().in("commission_expected_biz_id", bizIdList));
            Map<String, CommissionExpected> map = list.stream().collect(Collectors.toMap(CommissionExpected::getCommissionExpectedBizId, a -> a));
            for (CommissionExpected update : updateList) {
                CommissionExpected commissionExpectedFromDb = map.get(update.getCommissionExpectedBizId());
                update.setId(commissionExpectedFromDb.getId());
            }
            this.updateBatchById(updateList);
        }
        return true;
    }

    private void validateAddCommissionExpected(List<CommissionExpectedAddDto> addDtoList) {
        for (CommissionExpectedAddDto request : addDtoList) {
            // 校验数据
            if (StringUtils.isBlank(request.getCommissionType())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账项目类型不能为空");
            }
            // commissionType 只能是数字
            if (!StringUtils.isNumeric(request.getCommissionType())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账项目类型只能是字典值");
            }
            // commissionName 不能为空
            if (StringUtils.isBlank(request.getCommissionName())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账项目名称不能为空");
            }
            if ("R".equals(request.getCommissionBizType())) {
                if (request.getCommissionRatio() == null) {
                    throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "关联保单应收单，佣金比例不能为空");
                }
            }
        }
    }

    private BigDecimal queryDefaultExchangeRate(String currency) {
        if ("HKD".equalsIgnoreCase(currency)) {
            return BigDecimal.valueOf(1);
        }
        Result<List<GetDictItemListByDictTypeResponse>> result = apiSysDictFeignClient.getDictItemListByDictType("csf_exchange_rate_hkd");
        if (CollectionUtils.isNotEmpty(result.getData())) {
            for (GetDictItemListByDictTypeResponse dictItem : result.getData()) {
                if (StringUtils.equalsIgnoreCase(dictItem.getItemLabel(), currency)) {
                    return new BigDecimal(dictItem.getItemValue());
                }
            }
        }
        return BigDecimal.ONE;
    }

    @Override
    public Boolean deleteCommissionExpected(String commissionExpectedBizId) {
        if (StringUtils.isBlank(commissionExpectedBizId)) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "预计入账业务id不能为空");
        }
        // 校验预计入账是否存在
        CommissionExpected commissionExpected = getByBizId(commissionExpectedBizId);
        if (commissionExpected == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "预计入账不存在");
        }
        return this.removeById(commissionExpected.getId());
    }

    @Override
    public Boolean updateCommissionExpected(CommissionExpectedUpdateRequest commissionExpectedUpdateRequest) {
        // 校验预计入账是否存在
        CommissionExpected commissionExpected = getByBizId(commissionExpectedUpdateRequest.getCommissionExpectedBizId());
        if (commissionExpected == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "预计入账不存在");
        }

        // 校验数据
        validCommissionExpected(commissionExpected, false);
        // 转换为实体类
        BeanUtils.copyProperties(commissionExpectedUpdateRequest, commissionExpected, "id", "commissionBizId");
        // 更新默认结算汇率
        commissionExpected.setDefaultExchangeRate(queryDefaultExchangeRate(commissionExpectedUpdateRequest.getCurrency()));
        // 更新预计入账金额
        if ("R".equals(commissionExpectedUpdateRequest.getCommissionBizType())) {
            // 查询保单
            Policy policy = policyService.queryOne(commissionExpected.getPolicyNo());
            if (policy == null) {
                throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "保单不存在");
            }
            commissionExpected.setExpectedAmount(
                    policy.getPaymentPremium()
                            .multiply(commissionExpectedUpdateRequest.getCommissionRatio())
                            .multiply(commissionExpected.getDefaultExchangeRate())
                            .divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP)
            );
            commissionExpected.setPremium(policy.getPaymentPremium());
        } else {
            commissionExpected.setExpectedAmount(
                    commissionExpectedUpdateRequest.getAmount()
                            .multiply(commissionExpected.getDefaultExchangeRate())
            );
        }
        if (StringUtils.isBlank(commissionExpected.getReceivableNo())) {
            commissionExpected.setReceivableNo(receivableService.generateReceivableNo(
                    commissionExpected.getCommissionBizType(),
                    commissionExpected.getReconciliationCompanyCode(),
                    commissionExpected.getReconciliationCompany()));
        }

        commissionExpected.setUpdateTime(new Date());
        // 更新预计入账
        return this.updateById(commissionExpected);
    }

    @Override
    public CommissionExpectedStatisticsVO getExpectedStatistics(List<Long> expectedIds) {
        if (CollectionUtils.isEmpty(expectedIds)) {
            CommissionExpectedStatisticsVO expectedStatisticsVO = new CommissionExpectedStatisticsVO();
            expectedStatisticsVO.setTotalAmount(BigDecimal.ZERO);
            expectedStatisticsVO.setTotalPaidAmount(BigDecimal.ZERO);
            expectedStatisticsVO.setPendingPaidAmount(BigDecimal.ZERO);
            expectedStatisticsVO.setPaidAmountRatio(BigDecimal.ZERO);
            expectedStatisticsVO.setTotalPolicyCount(0);
            return expectedStatisticsVO;
        }
        // 自定义统计数据
        CommissionExpectedStatisticsVO commissionStatistics = baseMapper.getExpectedStatistics(expectedIds);

        BigDecimal totalAmount = commissionStatistics.getTotalAmount();
        BigDecimal totalPaidAmount = commissionStatistics.getTotalPaidAmount();
        // 计算待入账金额
        commissionStatistics.setPendingPaidAmount(totalAmount.subtract(totalPaidAmount));
        // 计算已入账比例
        BigDecimal divided = BigDecimal.ZERO;
        if (totalAmount.compareTo(BigDecimal.ZERO) > 0) {
            divided = totalPaidAmount.divide(totalAmount, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
        }
        commissionStatistics.setPaidAmountRatio(divided);

        return commissionStatistics;
    }

    @Override
    public CommissionExpected getByBizId(String commissionExpectedBizId) {
        return this.getOne(new QueryWrapper<CommissionExpected>().eq("commission_expected_biz_id", commissionExpectedBizId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getExpectedCommissionByProductlaunchId(Policy policy, String productLaunchBizId,
                                                       String insuranceCompanyBizId, String reconciliationCompany, String reconciliationCompanyCode, String reconciliationCompanyBizId) {
        String policyNo = policy.getPolicyNo();
        if (ObjectUtils.isEmpty(policyNo)) {
            throw new BusinessException("保单号不能为空");
        }
        BigDecimal paymentPremium = policy.getPaymentPremium();
        if (paymentPremium == null) {
            throw new BusinessException("保费不能为空");
        }
        Date effectiveDate = policy.getEffectiveDate();
        if (effectiveDate == null) {
            throw new BusinessException("保单生效日期不能为空");
        }
        String paymentTerm = Convert.toStr(policy.getPaymentTerm());
        if (paymentTerm == null) {
            throw new BusinessException("保单供款年期不能为空");
        }
        //查询redis缓存的字典列表信息
        List<GetDictItemListByDictTypeResponse> dictTypeResponses = redisUtil.getCacheObject(RedisConstants.DICT_LIST);

        if (StringUtils.isNotBlank(productLaunchBizId)) {
            List<ApiExpectedSpeciesListResponse> expectedSpeciesList = queryExpectedSpeciesByFeign(productLaunchBizId);

            List<CommissionExpected> commissionExpectedList = new ArrayList<>();
            if (CollUtil.isNotEmpty(expectedSpeciesList)) {
                // 根据供款年期匹配规格
                List<ApiExpectedSpeciesListResponse> collect = expectedSpeciesList.stream()
                        .filter(i -> paymentTerm.equals(i.getPaymentTerm()))
                        .collect(Collectors.toList());

                if (ObjectUtils.isEmpty(collect)) {
                    throw new BusinessException(ResultCode.FAIL.getCode(), "未查询到对应供款年期的佣金规格");
                }

                // 计算佣金总期数 list 中 endPeriod最大值
                Integer maxEndPeriod = collect.stream()
                        .map(item -> Convert.toInt(item.getEndPeriod()))
                        .max(Integer::compareTo)
                        .orElse(0);

                for (ApiExpectedSpeciesListResponse item : collect) {
                    CommissionExpected commissionExpected = new CommissionExpected();
                    commissionExpected.setCommissionExpectedBizId(RandomStringGenerator.generateBizId16("commission_expected"));
                    commissionExpected.setReceivableNo(receivableService.generateReceivableNo("R", reconciliationCompanyCode, reconciliationCompany));
                    commissionExpected.setCommissionBizType("R");
                    commissionExpected.setPolicyNo(policyNo);
                    commissionExpected.setPremium(paymentPremium);
                    commissionExpected.setInsuranceCompanyBizId(insuranceCompanyBizId);
                    commissionExpected.setProductLaunchBizId(productLaunchBizId);
                    commissionExpected.setReconciliationCompany(reconciliationCompany);
                    commissionExpected.setReconciliationCompanyCode(reconciliationCompanyCode);
                    commissionExpected.setReconciliationCompanyBizId(reconciliationCompanyBizId);
                    commissionExpected.setCommissionPeriod(Convert.toInt(item.getIssueNumber()));
                    commissionExpected.setTotalPeriod(maxEndPeriod);
                    commissionExpected.setCommissionName(GetDictItemListByDictTypeResponse.getItemLabel(dictTypeResponses,
                            "csf_commission_type", item.getExpenseName()));
                    commissionExpected.setCommissionType(item.getExpenseName());
                    commissionExpected.setCommissionRatio(item.getCommissionRate());
                    commissionExpected.setAmount(null);
                    commissionExpected.setCurrency(item.getCurrency());
                    commissionExpected.setCommissionDate(calculateCommissionDate(item.getEndPeriod(), effectiveDate));
                    commissionExpected.setStatus(CommissionExpectedStatusEnum.PENDING.getItemValue());
                    commissionExpected.setStatusDesc(null);
                    commissionExpected.setDefaultExchangeRate(queryDefaultExchangeRate(item.getCurrency()));
                    commissionExpected.setExpectedAmount(calculateExpectedAmount(
                            paymentPremium,
                            item.getCommissionRate(),
                            "R",
                            null,
                            item.getCurrency(),
                            commissionExpected.getDefaultExchangeRate()));
                    commissionExpected.setPaidAmount(BigDecimal.ZERO);
                    commissionExpected.setPaidRatio(BigDecimal.ZERO);
                    commissionExpected.setRemark("");
                    commissionExpected.setIsDeleted(0);
                    commissionExpected.setCreatorId("");
                    commissionExpected.setUpdaterId("");
                    commissionExpected.setCreateTime(new Date());
                    commissionExpected.setUpdateTime(new Date());

                    commissionExpectedList.add(commissionExpected);
                }
                // 保存预计来佣
                this.saveBatch(commissionExpectedList);
            }
        }
    }

    @Override
    public List<ApiExpectedSpeciesListResponse> queryExpectedSpeciesByFeign(String productLaunchBizId) {
        ApiExpectedSpeciesListRequest apiExpectedSpeciesListRequest = new ApiExpectedSpeciesListRequest();
        apiExpectedSpeciesListRequest.setProductLaunchBizId(productLaunchBizId);
        Result<List<ApiExpectedSpeciesListResponse>> result = apiExpectedSpeciesFeignClient.list(apiExpectedSpeciesListRequest);

        if (result != null && result.getCode() == 200) {
            return result.getData();
        } else {
            log.error("查询预计出佣规格失败: productLaunchBizId={}", productLaunchBizId);
            throw new BusinessException(ResultCode.FAIL.getCode(), "查询预计出佣规格失败");
        }
    }

    @Override
    public Boolean checkProductExpectedFortune(String productLaunchBizId) {
        Result<Boolean> result = apiAnnouncementCommissionRatioFeignClient.isData(productLaunchBizId);
        if (result != null && result.getData() != null) {
            return result.getData();
        }
        return false;
    }

    private BigDecimal calculateExpectedAmount(BigDecimal premium, BigDecimal commissionRatio, String commissionBizType,
                                                BigDecimal amount, String currency, BigDecimal defaultExchangeRate) {
        if ("R".equals(commissionBizType)) {
            // 关联保单应收单：保费 × 佣金比例 × 默认结算汇率 ÷ 100
            BigDecimal exchangeRate = defaultExchangeRate;
            if (exchangeRate == null) {
                exchangeRate = queryDefaultExchangeRate(currency);
            }
            return premium
                    .multiply(commissionRatio)
                    .multiply(exchangeRate)
                    .divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP);
        } else {
            // 非关联保单应收单：金额 × 默认结算汇率
            BigDecimal exchangeRate = defaultExchangeRate;
            if (exchangeRate == null) {
                exchangeRate = queryDefaultExchangeRate(currency);
            }
            return amount.multiply(exchangeRate);
        }
    }

    /**
     * 根据保单生效日期和佣金期数计算预计来佣日期，首期为保单生效日次月，后续期数为首期的次年
     * @param endPeriod 佣金期数
     * @param effectiveDate 保单生效日期
     * @return 预计来佣日期
     */
    private Date calculateCommissionDate(String endPeriod, Date effectiveDate) {
        if (effectiveDate == null || StringUtils.isBlank(endPeriod)) {
            return null;
        }

        Calendar cal = Calendar.getInstance();
        cal.setTime(effectiveDate);
        // 首期：保单生效日次月
        cal.add(Calendar.MONTH, 1);

        Integer period = Convert.toInt(endPeriod);
        if (period == null || period <= 0) {
            return cal.getTime();
        }

        // 后续期数：在首期基础上增加 (period - 1) 年
        // 例如：第2期为首期次年，第3期为首期+2年
        cal.add(Calendar.YEAR, period - 1);

        return cal.getTime();
    }

    @Override
    public IPage<ReceivableReportVO> receivableReportPage(Page<ReceivableReportVO> page, List<Long> expectedIds) {
        return baseMapper.receivableReportPage(page, expectedIds);
    }

}




