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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yd.base.feign.client.exchangerate.ApiExchangeRateFeignClient;
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.enums.PolicyStatusEnum;
import com.yd.csf.service.model.*;
import com.yd.csf.service.service.*;
import com.yd.csf.service.dao.CommissionExpectedMapper;
import com.yd.csf.service.model.SpeciesCondition;
import com.yd.csf.service.helper.SpeciesConditionMatcher;
import com.yd.csf.service.vo.*;
import com.yd.insurance.base.feign.client.insurancereconciliationcompany.ApiInsuranceReconciliationCompanyFeignClient;
import com.yd.insurance.base.feign.request.insurancereconciliationcompany.ApiInsuranceReconciliationCompanyPageRequest;
import com.yd.insurance.base.feign.response.insurancereconciliationcompany.ApiInsuranceReconciliationCompanyPageResponse;
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.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.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StreamUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
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;
    @Resource
    private ApiExpectedSpeciesFeignClient apiExpectedSpeciesFeignClient;
    @Resource
    private ApiAnnouncementCommissionRatioFeignClient apiAnnouncementCommissionRatioFeignClient;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private ApiExchangeRateFeignClient apiExchangeRateFeignClient;
    @Resource
    private ApiInsuranceReconciliationCompanyFeignClient companyFeignClient;
    @Resource
    private CustomerService customerService;

    // 用于对象转换的ObjectMapper
    private static final ObjectMapper objectMapper = new ObjectMapper();


    @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<String> policyNoList = policyList.stream().map(Policy::getPolicyNo).collect(Collectors.toList());
        List<PolicyFollow> policyFollowList = new ArrayList<>();
        if (!org.springframework.util.CollectionUtils.isEmpty(policyNoList)) {
            policyFollowList = policyFollowService.lambdaQuery()
                    .in(PolicyFollow::getPolicyNo, policyNoList)
                    .list();
        }
        Map<String, PolicyFollow> policyFollowMap = policyFollowList.stream()
                .collect(Collectors.toMap(PolicyFollow::getPolicyNo, Function.identity()));
        // 填充信息
        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());
            }
            PolicyFollow policyFollow = policyFollowMap.get(commissionExpected.getPolicyNo());
            if (policyFollow != null) {
                commissionExpectedVO.setProductName(policyFollow.getProductName());
                commissionExpectedVO.setProductLaunchBizId(policyFollow.getProductLaunchBizId());
            }
            return commissionExpectedVO;
        }).collect(Collectors.toList());
        CommissionExpectedVOPage.setRecords(CommissionExpectedVOList);

        enrichReceivableReportWithCompanyName(CommissionExpectedVOPage);
        return CommissionExpectedVOPage;
    }

    /**
     * 应收款管理列表查询
     * @param request
     * @param allExpectedList
     * @return
     */
    @Override
    public Page<CommissionExpectedNewVO> getCommissionExpectedVONewPage(CommissionExpectedQueryRequest request,
                                                                        List<CommissionExpected> allExpectedList) {
        if (CollUtil.isEmpty(allExpectedList)) {
            return new Page<>(request.getPageNo(), request.getPageSize(), 0);
        }

        // 批量查询实际佣金记录（按预计来佣业务ID分组）
        List<String> expectedBizIdList = allExpectedList.stream()
                .map(CommissionExpected::getCommissionExpectedBizId)
                .collect(Collectors.toList());
        List<Commission> allCommissions = commissionService.lambdaQuery()
                .in(Commission::getCommissionExpectedBizId, expectedBizIdList)
                .orderByAsc(Commission::getCreateTime)
                .list();
        Map<String, List<Commission>> commissionMap = allCommissions.stream()
                .collect(Collectors.groupingBy(Commission::getCommissionExpectedBizId));

        // 批量查询保单信息（Policy 和 PolicyFollow）
        Set<String> policyNoSet = allExpectedList.stream()
                .map(CommissionExpected::getPolicyNo)
                .collect(Collectors.toSet());
        allCommissions.forEach(c -> policyNoSet.add(c.getPolicyNo()));
        policyNoSet.remove(null);

        Map<String, Policy> policyMap = new HashMap<>();
        Map<String, PolicyFollow> policyFollowMap = 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(), (v1, v2) -> v1));

            List<PolicyFollow> policyFollowList = policyFollowService.lambdaQuery()
                    .in(PolicyFollow::getPolicyNo, policyNoSet)
                    .list();
            policyFollowMap = policyFollowList.stream()
                    .collect(Collectors.toMap(PolicyFollow::getPolicyNo, Function.identity(), (v1, v2) -> v1));
        }

        // 构建完整混合列表
        List<CommissionExpectedNewVO> allMixedRecords = new ArrayList<>();
        for (CommissionExpected expected : allExpectedList) {
            // 主记录
            CommissionExpectedNewVO mainVo = buildMainVo(expected, policyMap, policyFollowMap);
            allMixedRecords.add(mainVo);

            // 子记录
            List<Commission> commissions = commissionMap.getOrDefault(
                    expected.getCommissionExpectedBizId(), Collections.emptyList());
            int subIndex = 1;
            for (Commission commission : commissions) {
                CommissionExpectedNewVO subVo = buildSubVo(commission, policyMap, policyFollowMap, mainVo);
                subVo.setNo(mainVo.getNo() + "-" + subIndex);
                subVo.setType(2);
                subVo.setGapRate(mainVo.getGapRate());
                allMixedRecords.add(subVo);
                subIndex++;
            }
        }

        // 手动分页
        int pageNo = (int) request.getPageNo();
        int pageSize = (int) request.getPageSize();
        int total = allMixedRecords.size();
        int fromIndex = (pageNo - 1) * pageSize;
        int toIndex = Math.min(fromIndex + pageSize, total);

        List<CommissionExpectedNewVO> pageRecords;
        if (fromIndex >= total) {
            pageRecords = Collections.emptyList();
        } else {
            pageRecords = allMixedRecords.subList(fromIndex, toIndex);
        }

        Page<CommissionExpectedNewVO> resultPage = new Page<>(pageNo, pageSize, total);
        resultPage.setRecords(pageRecords);

        // 回填对账公司名称
        enrichCommissionExpectedNewVOWithCompanyName(resultPage);
        return resultPage;
    }

    /**
     * 构建主记录（预计来佣）
     */
    private CommissionExpectedNewVO buildMainVo(CommissionExpected expected,
                                                Map<String, Policy> policyMap,
                                                Map<String, PolicyFollow> policyFollowMap) {
        CommissionExpectedNewVO vo = new CommissionExpectedNewVO();
        BeanUtils.copyProperties(expected, vo);

        // 入账年月（估）：取预计来佣日期
        vo.setCommissionDateMonth(expected.getCommissionDate());
        vo.setType(1);
        vo.setNo(StringUtils.isNotBlank(expected.getReceivableNo()) ? expected.getReceivableNo() : expected.getCommissionExpectedBizId());
        //入账年月实
        vo.setCommissionDate(null);
        //本次入账比例
        vo.setRevenueRatio(null);
        vo.setRealRemark(expected.getRemark());
        vo.setCommissionExpectedBizId(expected.getCommissionExpectedBizId());

        // 填充保单信息
        Policy policy = policyMap.get(expected.getPolicyNo());
        if (policy != null) {
            vo.setPremium(policy.getPaymentPremium());
            vo.setPolicyCurrency(policy.getCurrency());
            vo.setInsuranceCompany(policy.getInsuranceCompany());
            vo.setReconciliationCompany(policy.getReconciliationCompany());
        }
        PolicyFollow policyFollow = policyFollowMap.get(expected.getPolicyNo());
        if (policyFollow != null) {
            vo.setProductName(policyFollow.getProductName());
//            vo.setProductLaunchBizId(policyFollow.getProductLaunchBizId());
            vo.setIssueNumber(policyFollow.getIssueNumber() != null ? Integer.parseInt(policyFollow.getIssueNumber().toString()) : null);
        }

        // 累积数据
        BigDecimal paidAmount = ObjectUtils.defaultIfNull(expected.getPaidAmount(), BigDecimal.ZERO);
        BigDecimal paidRatio = ObjectUtils.defaultIfNull(expected.getPaidRatio(), BigDecimal.ZERO);
//        vo.setPaidRatio(paidRatio);
//        vo.setPaidAmount(paidAmount);
        vo.setRealAmount(paidAmount);           // 实收金额（累积）
        vo.setExpectedAmount(expected.getExpectedAmount());

        // 产品来佣率
        BigDecimal commissionRatio = expected.getCommissionRatio();
        vo.setCommissionRatio(commissionRatio);

        if (commissionRatio != null && commissionRatio.compareTo(BigDecimal.ZERO) != 0) {
            // 实佣率 = paidRatio
            vo.setRealRate(paidRatio);
            // 达成率缺口 = 1 - 总实佣率/产品来佣率
            BigDecimal gap = BigDecimal.ONE.subtract(
                    paidRatio.divide(commissionRatio, 4, RoundingMode.HALF_UP)
            );
            // gap 可能为负，小于0时取0；然后转换为百分比数值（乘100，保留2位小数）
//            BigDecimal gapRate = gap.compareTo(BigDecimal.ZERO) < 0
//                    ? BigDecimal.ZERO
//                    : gap.multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
            BigDecimal gapRate = gap.multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
            vo.setGapRate(gapRate);

            // 计算累积已入账比例 = 总实佣率/产品对应来佣率
            BigDecimal totalRevenueRatio = paidRatio.divide(commissionRatio, 4, RoundingMode.HALF_UP);
            vo.setTotalRevenueRatio(totalRevenueRatio.multiply(BigDecimal.valueOf(100))
                    .setScale(2, RoundingMode.HALF_UP));
        } else {
            vo.setRealRate(BigDecimal.ZERO);
            vo.setGapRate(BigDecimal.ZERO);
            if ("U".equals(expected.getCommissionBizType())) {
                //应收款类型 R=关联保单应收单 totalRevenueRatio取值paidRatio
                vo.setTotalRevenueRatio(new BigDecimal("100.00"));
            }else {
                vo.setTotalRevenueRatio(BigDecimal.ZERO);
            }
        }

        // 待入账金额
        // 待入账金额归零 = 已入账来佣比例（实佣率）>= 产品来佣率
        if (commissionRatio != null && paidRatio.compareTo(commissionRatio) >= 0) {
            vo.setPendingAmount(BigDecimal.ZERO);
        } else if (commissionRatio != null) {
            if (expected.getExpectedAmount() != null) {
                //待入账金额 = 预计来佣金额 - 已入账来佣金额
                vo.setPendingAmount(expected.getExpectedAmount().subtract(paidAmount));
            }
        } else {
            // 非关联类型
            if (expected.getAmount() != null) {
                BigDecimal pending = expected.getAmount().subtract(paidAmount);
                vo.setPendingAmount(pending.compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO : pending);
            }
        }

        return vo;
    }

    /**
     * 构建从记录（实际来佣）
     */
    private CommissionExpectedNewVO buildSubVo(Commission commission,
                                               Map<String, Policy> policyMap,
                                               Map<String, PolicyFollow> policyFollowMap,
                                               CommissionExpectedNewVO mainVo) {
        CommissionExpectedNewVO vo = new CommissionExpectedNewVO();
        // 从主记录复制公共字段（排除特有字段）
        BeanUtils.copyProperties(mainVo, vo, "type", "no",
                "realReconciliationYearMonth", "realCommissionDate", "realExchangeRate",
                "realAmount", "realCurrentCommissionRatio", "realUpdateTime", "realUpdaterName",
                "realRate", "gapRate", "revenueRatio", "realRemark");

        // 基本实际字段
        vo.setRealReconciliationYearMonth(
                StringUtils.isNotBlank(commission.getReconciliationYearMonth()) ?
                        commission.getReconciliationYearMonth().replace("-", "") : "");
//        vo.setRealCommissionDate(commission.getCommissionDate());
        vo.setRealExchangeRate(commission.getExchangeRate());
        vo.setRealAmount(commission.getHkdAmount());
        vo.setRealCurrentCommissionRatio(commission.getCurrentCommissionRatio());
        vo.setRealUpdateTime(commission.getUpdateTime());
        vo.setRealUpdaterName(commission.getUpdaterName());
        vo.setRealRemark(commission.getRemark());
        vo.setCommissionDate(commission.getCommissionDate());
        vo.setRealRemark(commission.getRemark());
        vo.setCommissionBizId(commission.getCommissionBizId());

        // 覆盖公共业务字段
//        vo.setAmount(commission.getAmount());
//        vo.setCommissionDate(commission.getCommissionDate());
        vo.setCommissionPeriod(commission.getCommissionPeriod());
        vo.setCommissionName(commission.getCommissionName());
//        vo.setCommissionType(commission.getCommissionType());
//        vo.setCurrency(commission.getCurrency());
//        vo.setRemark(commission.getRemark());
        vo.setPolicyNo(commission.getPolicyNo());

        // 重新获取保单信息
        Policy policy = policyMap.get(commission.getPolicyNo());
        if (policy != null) {
            vo.setPremium(policy.getPaymentPremium());
            vo.setPolicyCurrency(policy.getCurrency());
            vo.setInsuranceCompany(policy.getInsuranceCompany());
            vo.setReconciliationCompany(policy.getReconciliationCompany());
        }
        PolicyFollow policyFollow = policyFollowMap.get(commission.getPolicyNo());
        if (policyFollow != null) {
            vo.setProductName(policyFollow.getProductName());
//            vo.setProductLaunchBizId(policyFollow.getProductLaunchBizId());
        }

        // 计算比率字段
        BigDecimal currentRatio = commission.getCurrentCommissionRatio(); // 本次实佣率
        BigDecimal productRatio = mainVo.getCommissionRatio();            // 产品来佣率（从主记录来）
        vo.setRealRate(currentRatio);  // 实佣率（本次）

        if (productRatio != null && productRatio.compareTo(BigDecimal.ZERO) != 0) {
            // 本次入账比例 = 本次实佣率 / 产品来佣率
            BigDecimal revenue = currentRatio.divide(productRatio, 4, RoundingMode.HALF_UP);
            BigDecimal revenueRatio = revenue.compareTo(BigDecimal.ONE) > 0 ? BigDecimal.ONE : revenue;
            vo.setRevenueRatio(revenueRatio.multiply(BigDecimal.valueOf(100))
                    .setScale(2, RoundingMode.HALF_UP));
            // 本次达成率缺口 = 1 - (实佣率（本次） / 产品来佣率)
            BigDecimal cumulativePaidRatio = currentRatio != null ? currentRatio : BigDecimal.ZERO;
            BigDecimal gap = BigDecimal.ONE.subtract(
                    cumulativePaidRatio.divide(productRatio, 4, RoundingMode.HALF_UP)
            );
            BigDecimal gapRate = gap.compareTo(BigDecimal.ZERO) < 0
                    ? BigDecimal.ZERO
                    : gap.multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
            vo.setGapRate(gapRate);
        } else {
            if ("U".equals(commission.getCommissionBizType())) {
                vo.setRevenueRatio(new BigDecimal("100.00"));
            }else {
                vo.setRevenueRatio(BigDecimal.ZERO);
            }
            vo.setGapRate(BigDecimal.ZERO);
        }

        return vo;
    }

    /**
     * 为混合结果集回填对账公司名称（类似 enrichReceivableReportWithCompanyName）
     */
    private void enrichCommissionExpectedNewVOWithCompanyName(Page<CommissionExpectedNewVO> page) {
        if (page == null || CollectionUtils.isEmpty(page.getRecords())) {
            return;
        }

        // 收集所有非空的对账公司 bizId（去重）
        List<String> bizIdList = page.getRecords().stream()
                .map(CommissionExpectedNewVO::getReconciliationCompanyBizId)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        if (bizIdList.isEmpty()) {
            return;
        }

        // 调用 Feign 批量查询对账公司信息
        ApiInsuranceReconciliationCompanyPageRequest request = new ApiInsuranceReconciliationCompanyPageRequest();
        request.setReconciliationCompanyBizIdList(bizIdList);
        request.setPageNo(1);
        request.setPageSize(bizIdList.size());

        Result result = companyFeignClient.page(request);
        List<ApiInsuranceReconciliationCompanyPageResponse> companyList = extractCompanyListFromResult(result);
        if (companyList.isEmpty()) {
            return;
        }

        // 构建 bizId -> name 映射
        Map<String, String> nameMap = companyList.stream()
                .filter(c -> StringUtils.isNotBlank(c.getReconciliationCompanyBizId()))
                .collect(Collectors.toMap(
                        ApiInsuranceReconciliationCompanyPageResponse::getReconciliationCompanyBizId,
                        ApiInsuranceReconciliationCompanyPageResponse::getName,
                        (v1, v2) -> v1
                ));

        // 回填名称
        page.getRecords().forEach(vo -> {
            if (StringUtils.isNotBlank(vo.getReconciliationCompanyBizId())) {
                String name = nameMap.get(vo.getReconciliationCompanyBizId());
                if (StringUtils.isNotBlank(name)) {
                    vo.setReconciliationCompany(name);
                }
            }
        });
    }

    private void enrichReceivableReportWithCompanyName(IPage<CommissionExpectedVO> page) {
        if (page == null || CollectionUtils.isEmpty(page.getRecords())) {
            return;
        }

        // 收集所有非空的对账公司 bizId（去重）
        List<String> bizIdList = page.getRecords().stream()
                .map(CommissionExpectedVO::getReconciliationCompanyBizId)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        if (bizIdList.isEmpty()) {
            return;
        }

        // 调用 Feign 批量查询对账公司信息
        ApiInsuranceReconciliationCompanyPageRequest request = new ApiInsuranceReconciliationCompanyPageRequest();
        request.setReconciliationCompanyBizIdList(bizIdList);
        request.setPageNo(1);
        request.setPageSize(bizIdList.size());

        Result result = companyFeignClient.page(request);
        List<ApiInsuranceReconciliationCompanyPageResponse> companyList = extractCompanyListFromResult(result);
        if (companyList.isEmpty()) {
            return;
        }

        // 构建 bizId -> name 映射
        Map<String, String> nameMap = companyList.stream()
                .filter(c -> StringUtils.isNotBlank(c.getReconciliationCompanyBizId()))
                .collect(Collectors.toMap(
                        ApiInsuranceReconciliationCompanyPageResponse::getReconciliationCompanyBizId,
                        ApiInsuranceReconciliationCompanyPageResponse::getName,
                        (v1, v2) -> v1 // 重复时保留第一个
                ));
        // 回填名称
        page.getRecords().forEach(vo -> {
            if (StringUtils.isNotBlank(vo.getReconciliationCompanyBizId())) {
                String name = nameMap.get(vo.getReconciliationCompanyBizId());
                if (StringUtils.isNotBlank(name)) {
                    vo.setReconciliationCompany(name);
                }
            }
        });
    }

    private List<ApiInsuranceReconciliationCompanyPageResponse> extractCompanyListFromResult(Result result) {
        if (result == null || result.getCode() != 200 || result.getData() == null) {
            return Collections.emptyList();
        }
        Object data = result.getData();
        try {
            // 将 data 转为 JSON 字符串再解析为 Map，以便提取 records
            Map<String, Object> dataMap = JSON.parseObject(JSON.toJSONString(data), new com.alibaba.fastjson.TypeReference<Map<String, Object>>() {
            });
            Object recordsObj = dataMap.get("records");
            if (recordsObj instanceof List) {
                List<?> recordsList = (List<?>) recordsObj;
                List<ApiInsuranceReconciliationCompanyPageResponse> companyList = new ArrayList<>();
                for (Object item : recordsList) {
                    // 将每个元素转换为目标类型
                    ApiInsuranceReconciliationCompanyPageResponse company = JSON.parseObject(
                            JSON.toJSONString(item),
                            ApiInsuranceReconciliationCompanyPageResponse.class
                    );
                    companyList.add(company);
                }
                return companyList;
            }
        } catch (Exception e) {
            log.error("解析公司列表失败", e);
        }
        return Collections.emptyList();
    }

    /**
     * 校验数据
     *
     * @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();
        LocalDate commissionDateStart = commissionExpectedQueryRequest.getCommissionDateStart();
        LocalDate 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);
        if (CollectionUtils.isNotEmpty(commissionExpectedQueryRequest.getPolicyNoList())) {
            queryWrapper.in(CollectionUtils.isNotEmpty(commissionExpectedQueryRequest.getPolicyNoList()),"policy_no",commissionExpectedQueryRequest.getPolicyNoList());
        }else {
            if (commissionExpectedQueryRequest.getQueryFlag() != null && commissionExpectedQueryRequest.getQueryFlag()) {
                //查询不到数据
                queryWrapper.apply("1=0");
            }
        }

        // 范围查询
        queryWrapper.ge(ObjectUtils.isNotEmpty(commissionDateStart), "commission_date", commissionDateStart);
        queryWrapper.le(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);

            // 预计总金额
            if ("R".equals(addDto.getCommissionBizType())) {
                Policy policy = policyMap.get(addDto.getPolicyNo());
                if (ObjectUtils.isEmpty(policy)) {
                    throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "保单号为" + addDto.getPolicyNo() + "的保单不存在");
                }
                // 结算汇率初始值为 1
                commissionExpected.setDefaultExchangeRate(BigDecimal.valueOf(1));
                // 查询默认结算汇率
                commissionExpected.setDefaultExchangeRate(queryExchangeRateByFeign(policy.getCurrency(), addDto.getCurrency()));
                // 查询港币汇率
                BigDecimal exchangeRateHkd = queryExchangeRateByFeign(addDto.getCurrency(), "HKD");
                // 转换为港币金额
                BigDecimal expectedAmount = policy.getPaymentPremium()
                        .multiply(commissionExpected.getCommissionRatio())
                        .multiply(commissionExpected.getDefaultExchangeRate())
                        .multiply(exchangeRateHkd)
                        .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(addDto.getExchangeRate());
                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(), "入账项目类型不能为空");
            }
            if (!StringUtils.isNumeric(request.getCommissionType())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账项目类型只能是字典值");
            }
            if (StringUtils.isBlank(request.getCommissionName())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账项目名称不能为空");
            }
            if (StringUtils.isBlank(request.getCurrency())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账币种不能为空");
            }
            if (request.getExchangeRate() == null) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "结算汇率不能为空");
            }
            if ("R".equals(request.getCommissionBizType())) {
                if (request.getCommissionRatio() == null) {
                    throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "关联保单应收单，佣金比例不能为空");
                }
            }
        }
    }

    @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");

        // 更新预计入账金额
        if ("R".equals(commissionExpectedUpdateRequest.getCommissionBizType())) {
            // 查询保单
            Policy policy = policyService.queryOne(commissionExpected.getPolicyNo());
            if (policy == null) {
                throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "保单不存在");
            }
            // 更新默认结算汇率
            commissionExpected.setDefaultExchangeRate(queryExchangeRateByFeign(policy.getCurrency(), commissionExpectedUpdateRequest.getCurrency()));
            // 查询港币汇率
            BigDecimal exchangeRateHkd = queryExchangeRateByFeign(commissionExpectedUpdateRequest.getCurrency(), "HKD");
            // 转换为港币金额
            commissionExpected.setExpectedAmount(
                    policy.getPaymentPremium()
                            .multiply(commissionExpectedUpdateRequest.getCommissionRatio())
                            .multiply(commissionExpected.getDefaultExchangeRate())
                            .multiply(exchangeRateHkd)
                            .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);
            expectedStatisticsVO.setTotalPremium(BigDecimal.ZERO);
            return expectedStatisticsVO;
        }
        // 自定义统计数据
        CommissionExpectedStatisticsVO commissionStatistics = baseMapper.getExpectedStatistics(expectedIds);

        // 计算总保费
        String policyNos = commissionStatistics.getPolicyNos();
        if (ObjectUtils.isNotEmpty(policyNos)) {
            List<CommissionExpected> commissionExpectedList = this.listByIds(expectedIds);

            Map<String, BigDecimal> exchangeRateMap = new HashMap<>();
            for (CommissionExpected commissionExpected : commissionExpectedList) {
                exchangeRateMap.put(commissionExpected.getPolicyNo(), commissionExpected.getDefaultExchangeRate());
            }

            Set<String> policyNoSet = commissionExpectedList.stream().map(CommissionExpected::getPolicyNo).collect(Collectors.toSet());
            // 查询总保费
            List<Policy> policyList = policyService.lambdaQuery().in(Policy::getPolicyNo, policyNoSet).list();
            BigDecimal totalPremium = BigDecimal.ZERO;
            if (CollectionUtils.isNotEmpty(policyList)) {
                for (Policy policy : policyList) {
                    BigDecimal exchangeRate = exchangeRateMap.getOrDefault(policy.getPolicyNo(), BigDecimal.ONE);
                    totalPremium = totalPremium.add(policy.getTotalPaymentPremium().multiply(exchangeRate));
                }
                commissionStatistics.setTotalPremium(totalPremium);
            }
        } else {
            commissionStatistics.setTotalPremium(BigDecimal.ZERO);
        }

        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 CommissionExpectedStatisticsVO getExpectedStatisticsNew(List<Long> expectedIds) {
        // 空集合直接返回空统计
        if (CollectionUtils.isEmpty(expectedIds)) {
            return emptyStatistics();
        }

        // 查询所有记录（包含失效状态）
        List<CommissionExpected> allExpectedList = this.listByIds(expectedIds);
        if (CollectionUtils.isEmpty(allExpectedList)) {
            return emptyStatistics();
        }

        // 过滤掉已失效的记录（status = "3"）
        List<CommissionExpected> validList = allExpectedList.stream()
                .filter(e -> !"3".equals(e.getStatus()))
                .collect(Collectors.toList());

        if (validList.isEmpty()) {
            return emptyStatistics();
        }

        // 手动聚合计算
        BigDecimal totalAmount = BigDecimal.ZERO;
        BigDecimal totalPaidAmount = BigDecimal.ZERO;
        //累计已入账来佣比例（同保单多个入账项目累计的实佣率）
        BigDecimal totalPaidRatio = BigDecimal.ZERO;
        //累计来佣比例（同保单多个入账项目累计的产品来佣率）
        BigDecimal totalCommissionRatio = BigDecimal.ZERO;
        Set<String> policyNoSet = new HashSet<>();

        for (CommissionExpected expected : validList) {
            totalAmount = totalAmount.add(ObjectUtils.defaultIfNull(expected.getExpectedAmount(), BigDecimal.ZERO));
            totalPaidAmount = totalPaidAmount.add(ObjectUtils.defaultIfNull(expected.getPaidAmount(), BigDecimal.ZERO));
            totalPaidRatio = totalPaidRatio.add(ObjectUtils.defaultIfNull(expected.getPaidRatio(), BigDecimal.ZERO));
            totalCommissionRatio = totalCommissionRatio.add(ObjectUtils.defaultIfNull(expected.getCommissionRatio(), BigDecimal.ZERO));
            if (StringUtils.isNotBlank(expected.getPolicyNo())) {
                policyNoSet.add(expected.getPolicyNo());
            }
        }

        // 计算总保费（HKD）
        BigDecimal totalPremium = BigDecimal.ZERO;
        BigDecimal fromTotalPremium = BigDecimal.ZERO;
        if (CollectionUtils.isNotEmpty(policyNoSet)) {
            List<Policy> policyList = policyService.lambdaQuery()
                    .in(Policy::getPolicyNo, policyNoSet)
                    .list();
            if (CollectionUtils.isNotEmpty(policyList)) {
                for (Policy policy : policyList) {
                    // 获取保单币种到港币的汇率
                    BigDecimal rate = queryExchangeRateByFeign(policy.getCurrency(), "HKD");
                    if (rate == null) rate = BigDecimal.ONE;
                    totalPremium = totalPremium.add(policy.getTotalPaymentPremium().multiply(rate));
                    fromTotalPremium = fromTotalPremium.add(policy.getTotalPaymentPremium());
                }
            }
        }

        // 组装返回对象
        CommissionExpectedStatisticsVO vo = new CommissionExpectedStatisticsVO();
        vo.setTotalAmount(totalAmount);
        vo.setTotalPaidAmount(totalPaidAmount);
        vo.setPendingPaidAmount(totalAmount.subtract(totalPaidAmount));

        if (totalAmount.compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal ratio = totalPaidAmount.divide(totalAmount, 4, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(100));
            vo.setPaidAmountRatio(ratio);
        } else {
            vo.setPaidAmountRatio(BigDecimal.ZERO);
        }

        // 待入账金额归零 = 已入账来佣比例（累计实佣率）>= 累计产品来佣率
        if (totalPaidRatio.compareTo(totalCommissionRatio) >= 0){
            vo.setPendingPaidAmount(BigDecimal.ZERO);
        }
        vo.setTotalPolicyCount(policyNoSet.size());
        vo.setTotalPremium(totalPremium);
        vo.setFromTotalPremium(fromTotalPremium);
        vo.setPolicyNos(null); // 原字段可能用于其他逻辑，此处置空
        return vo;
    }

    /**
     * 返回空的统计对象
     */
    private CommissionExpectedStatisticsVO emptyStatistics() {
        CommissionExpectedStatisticsVO vo = new CommissionExpectedStatisticsVO();
        vo.setTotalAmount(BigDecimal.ZERO);
        vo.setTotalPaidAmount(BigDecimal.ZERO);
        vo.setPendingPaidAmount(BigDecimal.ZERO);
        vo.setPaidAmountRatio(BigDecimal.ZERO);
        vo.setTotalPolicyCount(0);
        vo.setTotalPremium(BigDecimal.ZERO);
        return vo;
    }

    @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 professionalInvestor) {
        String policyNo = policy.getPolicyNo();
        if (ObjectUtils.isEmpty(policyNo)) {
            throw new BusinessException("保单号不能为空");
        }
        BigDecimal paymentPremium = policy.getPaymentPremium();
        if (paymentPremium == null) {
            throw new BusinessException("保费不能为空");
        }
        Integer policyHolderAge = policy.getPolicyHolderAge();
        if (policyHolderAge == null) {
            throw new BusinessException("保單持有人年齡不能为空");
        }
        Date effectiveDate = policy.getEffectiveDate();
        log.info("getExpectedCommissionByProductlaunchId的effectiveDate生效日期：{}", effectiveDate);
        if (effectiveDate == null) {
            throw new BusinessException("保单生效日期不能为空");
        }
        Date coolingOffEndDate = policy.getCoolingOffEndDate();
        if (coolingOffEndDate == 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)) {
                // 匹配规格并获取不匹配的条件
                MatchResult matchResult = matchExpectedSpecies(expectedSpeciesList, policy, professionalInvestor);

                if (matchResult.getMatchedList().isEmpty()) {
                    String errorMsg = matchResult.getUnmatchedConditions().isEmpty()
                            ? "未查询到预计来佣规格"
                            : "未查询到预计来佣规格，不匹配条件：" + String.join("、", matchResult.getUnmatchedConditions());

                    log.info("未查询到预计来佣规格，产品id：{}，当前规格：{}", productLaunchBizId, JSONUtil.toJsonStr(expectedSpeciesList));

                    throw new BusinessException(ResultCode.FAIL.getCode(), errorMsg);
                }

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

                int size = matchedList.size();
                for (int i = 0; i < size; i++) {
                    ApiExpectedSpeciesListResponse item = matchedList.get(i);

                    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.setPolicyCurrency(policy.getCurrency());
                    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(i, effectiveDate));
                    commissionExpected.setStatus(CommissionExpectedStatusEnum.PENDING.getItemValue());
                    commissionExpected.setStatusDesc(null);
                    commissionExpected.setDefaultExchangeRate(queryExchangeRateByFeign(policy.getCurrency(), item.getCurrency()));
                    commissionExpected.setExpectedAmount(calculateExpectedAmount(
                            paymentPremium,
                            item.getCommissionRate(),
                            "R",
                            null,
                            item.getCurrency(),
                            policy.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);
            }
        }
    }

    /**
     * 匹配规格结果内部类
     */
    private static class MatchResult {
        private List<ApiExpectedSpeciesListResponse> matchedList;
        private List<String> unmatchedConditions;

        public MatchResult(List<ApiExpectedSpeciesListResponse> matchedList, List<String> unmatchedConditions) {
            this.matchedList = matchedList;
            this.unmatchedConditions = unmatchedConditions;
        }

        public List<ApiExpectedSpeciesListResponse> getMatchedList() {
            return matchedList;
        }

        public List<String> getUnmatchedConditions() {
            return unmatchedConditions;
        }
    }

    /**
     * 匹配预计规格并返回不匹配的条件
     *
     * @param expectedSpeciesList 预计规格列表
     * @param policy              保单对象
     * @return 匹配结果
     */
    private MatchResult matchExpectedSpecies(
            List<ApiExpectedSpeciesListResponse> expectedSpeciesList,
            Policy policy,
            String professionalInvestor) {

        List<String> unmatchedConditions = new ArrayList<>();

        // 1. 生效日期独立验证（第一步）
        Date effectiveDate = policy.getEffectiveDate();

        List<ApiExpectedSpeciesListResponse> validDateList = filterAndCheck(
                expectedSpeciesList,
                i -> isEffective(i.getEffectiveStart(), i.getEffectiveEnd(), effectiveDate),
                unmatchedConditions,
                "生效日期[" + DateUtil.format(effectiveDate, "yyyy-MM-dd") + "]");

        if (!unmatchedConditions.isEmpty()) {
            return new MatchResult(Collections.emptyList(), unmatchedConditions);
        }

        // 1. 出单经纪公司独立验证
        String reconciliationCompanyBizId = policy.getReconciliationCompanyBizId();
        validDateList = filterAndCheck(
                validDateList,
                i -> i.getReconciliationCompany().equals(reconciliationCompanyBizId),
                unmatchedConditions,
                "出单经纪公司[" + policy.getReconciliationCompany() + "]");

        if (!unmatchedConditions.isEmpty()) {
            return new MatchResult(Collections.emptyList(), unmatchedConditions);
        }

        // 2. 获取第一个规格的条件模板
        String firstSpeciesJson = validDateList.get(0).getSpeciesJson();
        List<SpeciesCondition> conditionTemplates = parseSpeciesJson(firstSpeciesJson);

        log.info("当前佣金匹配条件: {}", JSONUtil.toJsonStr(conditionTemplates));

        if (conditionTemplates.isEmpty()) {
            // 没有配置任何条件，返回所有日期验证通过的规格
            return new MatchResult(validDateList, Collections.emptyList());
        }

        // 4. 构建实际值映射
        Map<String, Object> actualValues = buildActualValuesMap(policy, professionalInvestor);

        // 5. 逐个条件类型进行过滤
        List<ApiExpectedSpeciesListResponse> currentList = validDateList;

        for (SpeciesCondition conditionTemplate : conditionTemplates) {
            String typeCode = conditionTemplate.getTypeCode();
            Object actualValue = actualValues.get(typeCode);

            String conditionDesc = String.format("%s[%s]",
                    SpeciesConditionMatcher.getConditionName(typeCode), actualValue);

            currentList = filterBySpeciesCondition(
                    currentList,
                    typeCode,
                    actualValue,
                    unmatchedConditions,
                    conditionDesc);

            if (!unmatchedConditions.isEmpty()) {
                return new MatchResult(Collections.emptyList(), unmatchedConditions);
            }
        }

        return new MatchResult(currentList, unmatchedConditions);
    }

    /**
     * 解析speciesJson
     */
    private List<SpeciesCondition> parseSpeciesJson(String speciesJson) {
        if (speciesJson == null || speciesJson.trim().isEmpty()) {
            return Collections.emptyList();
        }
        try {
            return objectMapper.readValue(speciesJson,
                    new TypeReference<List<SpeciesCondition>>() {
                    });
        } catch (IOException e) {
            log.error("解析speciesJson失败: {}", speciesJson, e);
            return Collections.emptyList();
        }
    }

    /**
     * 构建实际值映射
     */
    private Map<String, Object> buildActualValuesMap(Policy policy, String professionalInvestor) {
        Map<String, Object> map = new HashMap<>();
        map.put("PAYMENT_TERM", policy.getPaymentTerm() != null ? String.valueOf(policy.getPaymentTerm()) : null);
        map.put("RECONCILIATION_COMPANY", policy.getReconciliationCompanyBizId());
        map.put("AGE", policy.getPolicyHolderAge());
        map.put("PREMIUM", calculateInitialPremiumInHkd(policy.getPaymentPremium(), policy.getCurrency()));
        map.put("PROFESSIONAL", professionalInvestor);
        map.put("POLICY_CURRENCY", policy.getCurrency());
        map.put("GUARANTEE_PERIOD", policy.getGuaranteePeriod());
        map.put("PROTECTION_PLAN", policy.getProductName());
        return map;
    }

    // 匹配来佣规格 - 计算期交保费港币金额
    private BigDecimal calculateInitialPremiumInHkd(BigDecimal paymentPremium, String policyCurrency) {
        // 查汇率
        BigDecimal exchangeRate = queryExchangeRateByFeign(policyCurrency, "HKD");
        return paymentPremium.multiply(exchangeRate);
    }

    /**
     * 根据species条件过滤列表
     */
    private List<ApiExpectedSpeciesListResponse> filterBySpeciesCondition(
            List<ApiExpectedSpeciesListResponse> list,
            String typeCode,
            Object actualValue,
            List<String> unmatchedConditions,
            String conditionDesc) {

        List<ApiExpectedSpeciesListResponse> filtered = list.stream()
                .filter(item -> {
                    List<SpeciesCondition> conditions = parseSpeciesJson(item.getSpeciesJson());
                    if (conditions.isEmpty()) return false;
                    return conditions.stream()
                            .anyMatch(c -> typeCode.equals(c.getTypeCode())
                                    && SpeciesConditionMatcher.matches(
                                    typeCode, c.getValue(), actualValue));
                })
                .collect(Collectors.toList());

        if (filtered.isEmpty()) {
            unmatchedConditions.add(conditionDesc);
        }
        return filtered;
    }

    private boolean isEffective(LocalDateTime effectiveStart, LocalDateTime effectiveEnd, Date effectiveDate) {
        LocalDateTime effectiveDateLocal = effectiveDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        return effectiveDateLocal.compareTo(effectiveStart) >= 0
                && effectiveDateLocal.compareTo(effectiveEnd) <= 0;
    }

    /**
     * 过滤列表并检查是否为空
     *
     * @param list                待过滤的列表
     * @param predicate           过滤条件
     * @param unmatchedConditions 不匹配条件列表
     * @param conditionDesc       条件描述
     * @return 过滤后的列表
     */
    private List<ApiExpectedSpeciesListResponse> filterAndCheck(
            List<ApiExpectedSpeciesListResponse> list,
            java.util.function.Predicate<ApiExpectedSpeciesListResponse> predicate,
            List<String> unmatchedConditions, String conditionDesc) {
        List<ApiExpectedSpeciesListResponse> filtered = list.stream()
                .filter(predicate)
                .collect(Collectors.toList());
        if (filtered.isEmpty()) {
            unmatchedConditions.add(conditionDesc);
        }
        return filtered;
    }

    @Override
    public List<ApiExpectedSpeciesListResponse> queryExpectedSpeciesByFeign(String productLaunchBizId) {
        ApiExpectedSpeciesListRequest apiExpectedSpeciesListRequest = new ApiExpectedSpeciesListRequest();
        apiExpectedSpeciesListRequest.setProductLaunchBizId(productLaunchBizId);
        Result<List<ApiExpectedSpeciesListResponse>> result = apiExpectedSpeciesFeignClient.list(apiExpectedSpeciesListRequest);
        log.info("查询预计来佣规格queryExpectedSpeciesByFeign==========>,{}",JSON.toJSONString(result));
        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;
    }

    /**
     * 计算预计来佣港币金额
     *
     * @param premium             保费
     * @param commissionRatio     佣金比例
     * @param commissionBizType   佣金业务类型
     * @param amount              金额
     * @param currency            预计来佣的结算币种=产品绑定的来佣结算币种
     * @param policyCurrency      保单币种
     * @param defaultExchangeRate 默认结算汇率
     * @return 预计来佣金额
     */
    private BigDecimal calculateExpectedAmount(BigDecimal premium, BigDecimal commissionRatio, String commissionBizType,
                                               BigDecimal amount, String currency, String policyCurrency, BigDecimal defaultExchangeRate) {
        if ("R".equals(commissionBizType)) {
            // 关联保单应收单：保费 × 佣金比例 × 默认结算汇率 ÷ 100
            BigDecimal exchangeRate = defaultExchangeRate;
            BigDecimal exchangeRateHkd = queryExchangeRateByFeign(currency, "HKD");
            if (exchangeRate == null) {
                // 这里获取保单币种对预计来佣的结算币种的默认汇率
                exchangeRate = queryExchangeRateByFeign(policyCurrency, currency);
            }
            return premium
                    .multiply(commissionRatio)
                    .multiply(exchangeRate)
                    .multiply(exchangeRateHkd)
                    .divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP);
        } else {
            // 非关联保单应收单：金额 × 默认结算汇率
            BigDecimal exchangeRate = defaultExchangeRate;
            if (exchangeRate == null) {
                exchangeRate = queryExchangeRateByFeign(policyCurrency, currency);
            }
            return amount.multiply(exchangeRate);
        }
    }

    /**
     * 保单币种对预计来佣的结算币种的默认汇率
     *
     * @param policyCurrency 保单币种
     * @param currency       预计来佣的结算币种
     * @return 汇率
     */
    private BigDecimal queryExchangeRateByFeign(String policyCurrency, String currency) {
        if (policyCurrency.equalsIgnoreCase(currency)) {
            return BigDecimal.valueOf(1);
        }
        // 调用Feign客户端查询汇率
        Result<BigDecimal> result = apiExchangeRateFeignClient.getExchangeRate(policyCurrency, currency, "");
        if (result != null && result.getData() != null) {
            return result.getData();
        }
        return null;
    }

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

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

        // 后续期数
        cal.add(Calendar.YEAR, currentPeriod);

        return cal.getTime();
    }

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

    @Override
    public void testExpectedCommission(String policyNo,String effectiveDate,String coolingOffEndDate) throws IOException {
        PolicyFollow policyFollow = policyFollowService.queryOneByPolicyNo(policyNo);
        String productLaunchBizId = policyFollow.getProductLaunchBizId();

        if (StringUtils.isNotBlank(productLaunchBizId)) {
            Policy policy = convertPolicy(policyFollow,effectiveDate,coolingOffEndDate);


            String professionalInvestor = policyFollow.getProfessionalInvestor();

//            List<ApiExpectedSpeciesListResponse> expectedSpeciesList = queryExpectedSpeciesByFeign(productLaunchBizId);

            List<ApiExpectedSpeciesListResponse> expectedSpeciesList = new ArrayList<>();

            // 读取text
            try {
                ClassPathResource resource = new ClassPathResource("TestExpectedSpecies.txt");
                String text = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
                expectedSpeciesList = JSONUtil.toList(text, ApiExpectedSpeciesListResponse.class);
            } catch (IOException e) {
                throw new RuntimeException("初始化预期来佣规格列表失败", e);
            }

            if (CollUtil.isNotEmpty(expectedSpeciesList)) {
                // 匹配规格并获取不匹配的条件
                CommissionExpectedServiceImpl.MatchResult matchResult = matchExpectedSpecies(expectedSpeciesList, policy, professionalInvestor);

                if (matchResult.getMatchedList().isEmpty()) {
                    String errorMsg = matchResult.getUnmatchedConditions().isEmpty()
                            ? "未查询到预计来佣规格"
                            : "未查询到预计来佣规格，不匹配条件：" + String.join("、", matchResult.getUnmatchedConditions());

                    log.info("未查询到预计来佣规格，当前规格：{}", JSONUtil.toJsonStr(expectedSpeciesList));

                    throw new BusinessException(ResultCode.FAIL.getCode(), errorMsg);
                }
            }
        }
    }

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

        // 校验数据
        if (StringUtils.isBlank(commissionExpectedChangeStatusRequest.getStatus())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "状态不能为空");
        }
        // 转换为实体类
        CommissionExpected updateObj = new CommissionExpected();
        BeanUtil.copyProperties(commissionExpectedChangeStatusRequest, updateObj);
        updateObj.setId(commissionExpected.getId());

        // 更新
        return this.updateById(updateObj);
    }

    @Override
    public CommissionExpected queryOne(String commissionExpectedBizId) {
        return this.baseMapper.selectOne(new LambdaQueryWrapper<CommissionExpected>()
                .eq(CommissionExpected::getCommissionExpectedBizId,commissionExpectedBizId)
                .last(" limit 1")
        );
    }

    private Policy convertPolicy(PolicyFollow policyFollow,String effectiveDate,String coolingOffEndDate) {
        Policy policy = new Policy();
        BeanUtil.copyProperties(policyFollow, policy);

        policy.setPolicyNo(policyFollow.getPolicyNo());
        policy.setPolicyHolderAge(calculatePolicyHolderAge(policyFollow.getCustomerBizId()));
        policy.setCoolingOffEndDate(policyFollow.getCoolingOffEndDate());
        policy.setReconciliationCompanyBizId(policyFollow.getReconciliationCompanyBizId());
        policy.setReconciliationCompanyCode(policyFollow.getReconciliationCompanyCode());
        policy.setReconciliationCompany(policyFollow.getReconciliationCompany());
        policy.setInsuranceCompanyBizId(policyFollow.getInsuranceCompanyBizId());
        policy.setInsuranceCompany(policyFollow.getInsuranceCompany());
        policy.setProductName(policyFollow.getProductName());
        // 更新保单状态为生效
        policy.setStatus(PolicyStatusEnum.INFORCE.getItemValue());
        // 手动映射不同名的字段
        policy.setPaymentPremium(policyFollow.getInitialPremium());
        policy.setCurrency(policyFollow.getPolicyCurrency());
        policy.setPaymentTerm(policyFollow.getIssueNumber());

        log.info("effectiveDate:{}",DateUtil.parse(effectiveDate, DatePattern.NORM_DATE_PATTERN));
        policy.setEffectiveDate(DateUtil.parse(effectiveDate, DatePattern.NORM_DATE_PATTERN));

        //冷静期结束日期
        log.info("coolingOffEndDate:{}",DateUtil.parse(coolingOffEndDate, DatePattern.NORM_DATE_PATTERN));
        policy.setCoolingOffEndDate(DateUtil.parse(coolingOffEndDate, DatePattern.NORM_DATE_PATTERN));

        return policy;
    }

    private Integer calculatePolicyHolderAge(String customerBizId) {
        Customer customer = customerService.getByCustomerBizId(customerBizId);
        if (customer == null) {
            throw new BusinessException("客户不存在");
        }
        if (customer.getBirthday() == null) {
            throw new BusinessException("客户生日不能为空");
        }
        // 根据生日计算年龄
        return DateUtil.ageOfNow(customer.getBirthday());
    }

}




