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

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yd.base.feign.client.bank.ApiBankFeignClient;
import com.yd.base.feign.client.exchangerate.ApiExchangeRateFeignClient;
import com.yd.base.feign.request.bank.ApiBankListRequest;
import com.yd.base.feign.request.exchangerate.ApiExchangeRateConvertRequest;
import com.yd.base.feign.response.bank.ApiBankDetailResponse;
import com.yd.base.feign.response.exchangerate.ApiExchangeRateConvertResponse;
import com.yd.common.enums.CommonEnum;
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.csf.api.service.ApiExpectedFortuneService;
import com.yd.csf.api.service.ApiPremiumReconciliationService;
import com.yd.csf.api.service.ApiPremiumRemittanceService;
import com.yd.csf.feign.dto.premiumreconciliation.ApiPremiumReconciliationDto;
import com.yd.csf.feign.dto.premiumremittance.ApiPremiumRemittanceDto;
import com.yd.csf.feign.enums.ReconciliationStatusEnum;
import com.yd.csf.feign.request.expectedfortune.ApiGenerateExpectedFortuneRequest;
import com.yd.csf.feign.request.premiumreconciliation.ApiCalculateRemainingUnpaidAmountRequest;
import com.yd.csf.feign.request.premiumreconciliation.ApiPremiumReconciliationAddRequest;
import com.yd.csf.feign.request.premiumreconciliation.ApiPremiumReconciliationPageRequest;
import com.yd.csf.feign.request.premiumreconciliation.ApiPremiumReconciliationResultEditRequest;
import com.yd.csf.feign.response.expectedfortune.ApiGenerateExpectedFortuneResponse;
import com.yd.csf.feign.response.premiumreconciliation.ApiCalculateRemainingUnpaidAmountResponse;
import com.yd.csf.feign.response.premiumreconciliation.ApiPremiumReconciliationDetailResponse;
import com.yd.csf.feign.response.premiumreconciliation.ApiPremiumReconciliationPageResponse;
import com.yd.csf.feign.response.team.ApiTeamPageResponse;
import com.yd.csf.service.dto.ChangePolicyFollowStatusRequest;
import com.yd.csf.service.dto.PremiumReconciliationDto;
import com.yd.csf.service.dto.QueryPolicyAndBrokerDto;
import com.yd.csf.service.dto.QueryPolicyDto;
import com.yd.csf.service.enums.PolicyFollowStatusEnum;
import com.yd.csf.service.model.CommissionRuleBinding;
import com.yd.csf.service.model.Policy;
import com.yd.csf.service.model.PolicyFollow;
import com.yd.csf.service.model.PremiumReconciliation;
import com.yd.csf.service.service.CommissionExpectedService;
import com.yd.csf.service.service.IPremiumReconciliationService;
import com.yd.csf.service.service.PolicyFollowService;
import com.yd.csf.service.service.PolicyService;
import com.yd.feign.config.FeignTokenInterceptor;
import com.yd.product.feign.response.expectedspecies.ApiExpectedSpeciesListResponse;
import com.yd.user.feign.client.sysdict.ApiSysDictFeignClient;
import com.yd.user.feign.request.sysdict.GetDictTypeListRequest;
import com.yd.user.feign.response.sysdict.GetDictItemListByDictTypeResponse;
import com.yd.user.feign.response.sysdict.GetDictTypeListResponse;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
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.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ApiPremiumReconciliationServiceImpl implements ApiPremiumReconciliationService {

    @Autowired
    private PolicyService policyService;

    @Autowired
    private IPremiumReconciliationService iPremiumReconciliationService;

    @Autowired
    private ApiPremiumRemittanceService apiPremiumRemittanceService;

    @Autowired
    private ApiExchangeRateFeignClient apiExchangeRateFeignClient;

    @Autowired
    private PolicyFollowService policyFollowService;

    @Autowired
    private ApiSysDictFeignClient apiSysDictFeignClient;

    @Autowired
    private ApiBankFeignClient apiBankFeignClient;

    @Resource
    private CommissionExpectedService commissionExpectedService;

    @Resource
    private ApiExpectedFortuneService apiExpectedFortuneService;

    @Autowired
    private ApplicationContext applicationContext;

    private ApiPremiumReconciliationService getSelf() {
        return applicationContext.getBean(ApiPremiumReconciliationService.class);
    }

    /**
     * 分页列表查询-保费对账记录信息
     * @param request
     * @return
     */
    @Override
    public Result<IPage<ApiPremiumReconciliationPageResponse>> page(ApiPremiumReconciliationPageRequest request) {
        Page<ApiPremiumReconciliationPageResponse> page = new Page<>(request.getPageNo(), request.getPageSize());
        IPage<ApiPremiumReconciliationPageResponse> iPage = iPremiumReconciliationService.page(page, request);

        // 如果没有数据，直接返回
        if (iPage == null || CollectionUtils.isEmpty(iPage.getRecords())) {
            return Result.success(iPage);
        }

        log.info("开始处理分页数据，共{}条记录", iPage.getRecords().size());

        // 获取缴费方式字典数据
        Map<String, String> paymentMethodDictMap = getPaymentMethodDict();

        // 获取所有银行ID，准备翻译银行名称
        Set<String> bankBizIdSet = new HashSet<>();
        // 收集返回数据的保费对账记录表唯一业务ID列表
        List<String> premiumReconciliationBizIdList = new ArrayList<>();
        // 收集保单号列表
        List<String> policyNoList = new ArrayList<>();

        // 收集所有银行ID并翻译缴费方式
        for (ApiPremiumReconciliationPageResponse item : iPage.getRecords()) {
            // 收集返回数据的保费对账记录表唯一业务ID列表
            premiumReconciliationBizIdList.add(item.getPremiumReconciliationBizId());
            policyNoList.add(item.getPolicyNo());

            // 翻译缴费方式
            if (StringUtils.isNotBlank(item.getPaymentMethod())) {
                String translated = translatePaymentMethod(item.getPaymentMethod(), paymentMethodDictMap);
                item.setPaymentMethod(translated);
            }

            // 收集银行ID（payingBank字段）
            if (StringUtils.isNotBlank(item.getPayingBank())) {
                // 分割多个银行ID（用分号分隔）
                String[] bankIds = item.getPayingBank().split(";");
                for (String bankId : bankIds) {
                    if (StringUtils.isNotBlank(bankId.trim())) {
                        bankBizIdSet.add(bankId.trim());
                    }
                }
            }
        }

        log.info("收集到{}个对账记录ID，{}个保单号", premiumReconciliationBizIdList.size(), policyNoList.size());

        // 翻译银行名称
        if (!bankBizIdSet.isEmpty()) {
            Map<String, String> bankNameMap = getBankNames(bankBizIdSet);

            // 翻译银行名称字段
            for (ApiPremiumReconciliationPageResponse item : iPage.getRecords()) {
                if (StringUtils.isNotBlank(item.getPayingBank())) {
                    String translated = translateBankNames(item.getPayingBank(), bankNameMap);
                    item.setPayingBank(translated);
                }
            }
        }

        // 汇总统计付款金额和付款币种
        if (!CollectionUtils.isEmpty(premiumReconciliationBizIdList)) {
            log.info("开始汇总统计付款金额，对账记录ID数量: {}", premiumReconciliationBizIdList.size());

            // 收集返回数据的保费对账记录表唯一业务ID列表查询返回关联的汇款记录列表
            List<ApiPremiumRemittanceDto> apiPremiumRemittanceDtoList = apiPremiumRemittanceService.list(premiumReconciliationBizIdList);
            log.info("查询到{}条汇款记录", apiPremiumRemittanceDtoList != null ? apiPremiumRemittanceDtoList.size() : 0);

            // 查询保单列表信息
            List<PolicyFollow> policyFollowList = policyFollowService.queryList(policyNoList);
            log.info("查询到{}条保单记录", policyFollowList != null ? policyFollowList.size() : 0);

            // 构建保单号到保单币种的映射
            Map<String, String> policyNoToCurrencyMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(policyFollowList)) {
                for (PolicyFollow policyFollow : policyFollowList) {
                    if (StringUtils.isNotBlank(policyFollow.getPolicyNo()) && StringUtils.isNotBlank(policyFollow.getPolicyCurrency())) {
                        policyNoToCurrencyMap.put(policyFollow.getPolicyNo(), policyFollow.getPolicyCurrency());
                        log.debug("保单 {} 的币种: {}", policyFollow.getPolicyNo(), policyFollow.getPolicyCurrency());
                    }
                }
            }

            // 构建对账记录ID到保单号的映射
            Map<String, String> reconciliationBizIdToPolicyNoMap = new HashMap<>();
            for (ApiPremiumReconciliationPageResponse item : iPage.getRecords()) {
                reconciliationBizIdToPolicyNoMap.put(item.getPremiumReconciliationBizId(), item.getPolicyNo());
                log.debug("对账记录 {} -> 保单 {}", item.getPremiumReconciliationBizId(), item.getPolicyNo());
            }

            // 按对账记录ID分组汇款记录
            Map<String, List<ApiPremiumRemittanceDto>> reconciliationRemittanceMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(apiPremiumRemittanceDtoList)) {
                for (ApiPremiumRemittanceDto remittanceDto : apiPremiumRemittanceDtoList) {
                    String reconciliationBizId = remittanceDto.getPremiumReconciliationBizId();
                    if (StringUtils.isNotBlank(reconciliationBizId) &&
                            StringUtils.isNotBlank(remittanceDto.getPaymentCurrency()) &&
                            remittanceDto.getPaymentAmount() != null) {
                        reconciliationRemittanceMap
                                .computeIfAbsent(reconciliationBizId, k -> new ArrayList<>())
                                .add(remittanceDto);
                        log.debug("汇款记录: 对账ID={}, 金额={}, 币种={}",
                                reconciliationBizId, remittanceDto.getPaymentAmount(), remittanceDto.getPaymentCurrency());
                    }
                }
            }

            log.info("分组后的汇款记录: {}个分组", reconciliationRemittanceMap.size());

            // 为每个对账记录计算总付款金额（转换为保单币种）
            Map<String, BigDecimal> totalPaymentAmounts = new HashMap<>();
            Map<String, String> paymentCurrencies = new HashMap<>();

            // 首先收集所有需要转换的请求
            List<ApiExchangeRateConvertRequest> convertRequests = new ArrayList<>();
            // 改为使用列表保存转换信息，按顺序匹配
            List<ConvertInfo> convertInfoList = new ArrayList<>();

            // 调试：记录每个对账记录的详细信息
            for (Map.Entry<String, List<ApiPremiumRemittanceDto>> entry : reconciliationRemittanceMap.entrySet()) {
                String reconciliationBizId = entry.getKey();
                List<ApiPremiumRemittanceDto> remittanceDtos = entry.getValue();
                String policyNo = reconciliationBizIdToPolicyNoMap.get(reconciliationBizId);

                if (StringUtils.isBlank(policyNo)) {
                    log.warn("找不到对账记录ID: {} 对应的保单号", reconciliationBizId);
                    continue;
                }

                String policyCurrency = policyNoToCurrencyMap.get(policyNo);
                if (StringUtils.isBlank(policyCurrency)) {
                    log.warn("保单号: {} 的币种信息为空", policyNo);
                    continue;
                }

                log.info("处理对账记录: {}, 保单: {}, 保单币种: {}, 汇款记录数: {}",
                        reconciliationBizId, policyNo, policyCurrency, remittanceDtos.size());

                // 打印所有汇款记录详情
                for (int i = 0; i < remittanceDtos.size(); i++) {
                    ApiPremiumRemittanceDto dto = remittanceDtos.get(i);
                    log.info("汇款记录 {}: ID={}, 金额={}, 币种={}, 日期={}",
                            i, dto.getPremiumRemittanceBizId(), dto.getPaymentAmount(),
                            dto.getPaymentCurrency(), dto.getPaymentDate());
                }

                // 初始化总金额
                BigDecimal totalAmount = BigDecimal.ZERO;
                String paymentCurrency = policyCurrency;

                // 首先处理相同币种的汇款记录
                int sameCurrencyCount = 0;
                for (ApiPremiumRemittanceDto remittanceDto : remittanceDtos) {
                    String remittanceCurrency = remittanceDto.getPaymentCurrency();
                    BigDecimal amount = remittanceDto.getPaymentAmount();

                    if (policyCurrency.equalsIgnoreCase(remittanceCurrency)) {
                        totalAmount = totalAmount.add(amount);
                        sameCurrencyCount++;
                        log.info("相同币种汇款记录: {} {}", amount, remittanceCurrency);
                    }
                }

                log.info("相同币种汇款记录数: {}, 累计金额: {}", sameCurrencyCount, totalAmount);

                // 然后处理需要转换的汇款记录
                int convertCount = 0;
                for (ApiPremiumRemittanceDto remittanceDto : remittanceDtos) {
                    String remittanceCurrency = remittanceDto.getPaymentCurrency();
                    BigDecimal amount = remittanceDto.getPaymentAmount();

                    // 如果币种相同，已经在上面处理过了
                    if (policyCurrency.equalsIgnoreCase(remittanceCurrency)) {
                        continue;
                    }

                    convertCount++;
                    log.info("需要转换的汇款记录: ID={}, 金额={} {}, 目标币种={}",
                            remittanceDto.getPremiumRemittanceBizId(), amount, remittanceCurrency, policyCurrency);

                    // 构建转换请求
                    ApiExchangeRateConvertRequest convertRequest = new ApiExchangeRateConvertRequest();
                    convertRequest.setAmount(amount);
                    convertRequest.setFromCurrency(remittanceCurrency);
                    convertRequest.setToCurrency(policyCurrency);

                    // 如果有付款日期，使用付款日期
//                    if (remittanceDto.getPaymentDate() != null) {
//                        try {
//                            Date paymentDate = Date.from(remittanceDto.getPaymentDate()
//                                    .atZone(java.time.ZoneId.systemDefault()).toInstant());
//                            convertRequest.setTransactionDate(paymentDate);
//                        } catch (Exception e) {
//                            log.warn("转换付款日期失败: {}", remittanceDto.getPaymentDate(), e);
//                        }
//                    }

                    // 生成唯一请求ID - 但汇率服务可能不返回，所以我们主要依赖顺序匹配
                    String requestId = reconciliationBizId + "_" +
                            (StringUtils.isNotBlank(remittanceDto.getPremiumRemittanceBizId()) ?
                                    remittanceDto.getPremiumRemittanceBizId() : UUID.randomUUID().toString());
                    convertRequest.setRequestId(requestId);

                    convertRequests.add(convertRequest);

                    // 保存转换信息到列表（按顺序）
                    ConvertInfo info = new ConvertInfo();
                    info.reconciliationBizId = reconciliationBizId;
                    info.originalAmount = amount;
                    info.originalCurrency = remittanceCurrency;
                    info.targetCurrency = policyCurrency;
                    info.requestId = requestId; // 保存requestId，如果汇率服务返回则使用
                    convertInfoList.add(info);

                    log.debug("添加转换请求: requestId={}, {} {} -> {}",
                            requestId, amount, remittanceCurrency, policyCurrency);
                }

                log.info("需要转换的汇款记录数: {}", convertCount);

                // 先保存相同币种的累计金额
                totalAmount = totalAmount.setScale(2, RoundingMode.HALF_EVEN);
                totalPaymentAmounts.put(reconciliationBizId, totalAmount);
                paymentCurrencies.put(reconciliationBizId, paymentCurrency);

                log.info("对账记录 {} 初始总金额: {} {}", reconciliationBizId, totalAmount, policyCurrency);
            }

            log.info("总共需要转换 {} 条汇款记录", convertRequests.size());

            // 批量处理汇率转换
            if (!CollectionUtils.isEmpty(convertRequests)) {
                try {
                    // 分批处理，避免请求过大
                    int batchSize = 50;
                    for (int i = 0; i < convertRequests.size(); i += batchSize) {
                        int end = Math.min(convertRequests.size(), i + batchSize);
                        List<ApiExchangeRateConvertRequest> batch = convertRequests.subList(i, end);
                        List<ConvertInfo> batchConvertInfos = convertInfoList.subList(i, end);

                        log.info("发送第 {} 批汇率转换请求，共 {} 条", i/batchSize + 1, batch.size());

                        // 记录每个请求的详细信息
                        for (ApiExchangeRateConvertRequest req : batch) {
                            log.info("转换请求: requestId={}, 金额={}, 从{}到{}",
                                    req.getRequestId(), req.getAmount(), req.getFromCurrency(), req.getToCurrency());
                        }

                        Result<List<ApiExchangeRateConvertResponse>> batchResult =
                                apiExchangeRateFeignClient.batchConvert(batch);

                        log.info("汇率转换服务返回: code={}, message={}, 数据量={}",
                                batchResult != null ? batchResult.getCode() : "null",
                                batchResult != null ? batchResult.getMsg() : "null",
                                batchResult != null && batchResult.getData() != null ? batchResult.getData().size() : 0);

                        if (batchResult != null && batchResult.getCode() == 200 &&
                                !CollectionUtils.isEmpty(batchResult.getData())) {

                            log.info("收到第 {} 批汇率转换响应，共 {} 条", i/batchSize + 1, batchResult.getData().size());

                            // 处理转换结果 - 使用顺序匹配
                            List<ApiExchangeRateConvertResponse> responses = batchResult.getData();

                            // 记录每个响应的详细信息
                            for (ApiExchangeRateConvertResponse resp : responses) {
                                log.info("转换响应: requestId={}, 原金额={} {}, 转换金额={} {}",
                                        resp.getRequestId(), resp.getOriginalAmount(), resp.getOriginalCurrency(),
                                        resp.getConvertedAmount(), resp.getTargetCurrency());
                            }

                            // 确保响应数量与请求数量一致
                            if (responses.size() != batch.size()) {
                                log.warn("汇率转换响应数量({})与请求数量({})不一致，可能无法正确匹配",
                                        responses.size(), batch.size());
                            }

                            // 处理每个转换结果
                            for (int j = 0; j < Math.min(responses.size(), batch.size()); j++) {
                                ApiExchangeRateConvertResponse convertResponse = responses.get(j);
                                ConvertInfo info = null;

                                // 首先尝试通过requestId匹配
                                if (StringUtils.isNotBlank(convertResponse.getRequestId())) {
                                    // 如果汇率服务返回了requestId，则从整个列表中查找
                                    for (ConvertInfo ci : convertInfoList) {
                                        if (convertResponse.getRequestId().equals(ci.requestId)) {
                                            info = ci;
                                            log.info("通过requestId匹配成功: requestId={}, 对账记录ID={}",
                                                    convertResponse.getRequestId(), info.reconciliationBizId);
                                            break;
                                        }
                                    }
                                }

                                // 如果通过requestId没有找到，则使用顺序匹配
                                if (info == null && j < batchConvertInfos.size()) {
                                    info = batchConvertInfos.get(j);
                                    log.info("尝试顺序匹配: 批次索引={}, 对账记录ID={}", j, info.reconciliationBizId);
                                }

                                if (info != null && convertResponse.getConvertedAmount() != null) {
                                    BigDecimal currentTotal = totalPaymentAmounts.getOrDefault(info.reconciliationBizId, BigDecimal.ZERO);
                                    BigDecimal convertedAmount = convertResponse.getConvertedAmount();

                                    log.info("汇率转换结果: {} {} -> {} {}, 汇率={}",
                                            convertResponse.getOriginalAmount(), convertResponse.getOriginalCurrency(),
                                            convertedAmount, convertResponse.getTargetCurrency(), convertResponse.getExchangeRate());

                                    // 设置精度并累加
                                    convertedAmount = convertedAmount.setScale(2, RoundingMode.HALF_EVEN);
                                    BigDecimal newTotal = currentTotal.add(convertedAmount);
                                    totalPaymentAmounts.put(info.reconciliationBizId, newTotal);

                                    log.info("对账记录 {} 累加后总金额: {} (之前: {} + 转换: {})",
                                            info.reconciliationBizId, newTotal, currentTotal, convertedAmount);
                                } else {
                                    log.warn("转换结果缺少必要信息或无法匹配: requestId={}, info={}, convertedAmount={}",
                                            convertResponse.getRequestId(), info, convertResponse.getConvertedAmount());

                                    // 尝试通过其他方式匹配
                                    if (convertResponse.getOriginalAmount() != null &&
                                            StringUtils.isNotBlank(convertResponse.getOriginalCurrency()) &&
                                            StringUtils.isNotBlank(convertResponse.getTargetCurrency())) {
                                        // 通过金额、原币种和目标币种匹配
                                        for (ConvertInfo ci : convertInfoList) {
                                            if (convertResponse.getOriginalAmount().compareTo(ci.originalAmount) == 0 &&
                                                    convertResponse.getOriginalCurrency().equalsIgnoreCase(ci.originalCurrency) &&
                                                    convertResponse.getTargetCurrency().equalsIgnoreCase(ci.targetCurrency)) {
                                                info = ci;
                                                BigDecimal convertedAmount = convertResponse.getConvertedAmount();
                                                if (convertedAmount != null) {
                                                    BigDecimal currentTotal = totalPaymentAmounts.getOrDefault(info.reconciliationBizId, BigDecimal.ZERO);
                                                    convertedAmount = convertedAmount.setScale(2, RoundingMode.HALF_EVEN);
                                                    BigDecimal newTotal = currentTotal.add(convertedAmount);
                                                    totalPaymentAmounts.put(info.reconciliationBizId, newTotal);
                                                    log.info("通过金额和币种匹配成功: 对账记录={}, 累加金额={}",
                                                            info.reconciliationBizId, convertedAmount);
                                                }
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        } else {
                            log.error("批量汇率转换失败，code: {}, msg: {}",
                                    batchResult != null ? batchResult.getCode() : "null",
                                    batchResult != null ? batchResult.getMsg() : "null");
                        }
                    }
                } catch (Exception e) {
                    log.error("汇率转换处理异常", e);
                }
            }

            // 调试：打印所有对账记录的总付款金额
            for (Map.Entry<String, BigDecimal> entry : totalPaymentAmounts.entrySet()) {
                log.info("对账记录 {} 最终总付款金额: {}", entry.getKey(), entry.getValue());
            }

            // 更新分页响应
            int updatedCount = 0;
            for (ApiPremiumReconciliationPageResponse item : iPage.getRecords()) {
                String reconciliationBizId = item.getPremiumReconciliationBizId();

                if (totalPaymentAmounts.containsKey(reconciliationBizId)) {
                    BigDecimal totalAmount = totalPaymentAmounts.get(reconciliationBizId);
                    String paymentCurrency = paymentCurrencies.get(reconciliationBizId);

                    log.info("更新对账记录 {}: 付款金额={} {}, 原paymentAmount={} {}, 原paymentCurrency={}",
                            reconciliationBizId, totalAmount, paymentCurrency,
                            item.getPaymentAmount(), item.getPaymentCurrency(), item.getPaymentCurrency());

                    item.setPaymentAmount(totalAmount);

                    if (StringUtils.isNotBlank(paymentCurrency)) {
                        item.setPaymentCurrency(paymentCurrency);
                    }
                    updatedCount++;
                } else {
                    log.info("对账记录 {} 没有找到付款金额汇总", reconciliationBizId);
                }
            }

            log.info("共更新了 {} 条记录的付款金额", updatedCount);
        }

        return Result.success(iPage);
    }

    // 辅助类
    private static class ConvertInfo {
        String reconciliationBizId;
        BigDecimal originalAmount;
        String originalCurrency;
        String targetCurrency;
        String requestId; // 添加requestId字段
    }

    /**
     * 获取缴费方式字典数据
     */
    private Map<String, String> getPaymentMethodDict() {
        Map<String, String> dictMap = new HashMap<>();
        try {
            GetDictTypeListRequest dictRequest = new GetDictTypeListRequest();
            dictRequest.setTypeList(Collections.singletonList("csf_ap_first_issue"));
            List<GetDictTypeListResponse> dictTypeResponses = apiSysDictFeignClient.getByDictTypeList(dictRequest).getData();

            if (dictTypeResponses != null && !dictTypeResponses.isEmpty()) {
                for (GetDictTypeListResponse dictTypeResponse : dictTypeResponses) {
                    if ("csf_ap_first_issue".equals(dictTypeResponse.getDictType())
                            && dictTypeResponse.getDictItemList() != null) {
                        for (GetDictItemListByDictTypeResponse dictItem : dictTypeResponse.getDictItemList()) {
                            dictMap.put(dictItem.getItemValue(), dictItem.getItemLabel());
                        }
                        break;
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取缴费方式字典数据失败", e);
        }
        return dictMap;
    }

    /**
     * 获取银行名称映射
     */
    private Map<String, String> getBankNames(Set<String> bankBizIdSet) {
        Map<String, String> bankNameMap = new HashMap<>();
        try {
            ApiBankListRequest bankRequest = new ApiBankListRequest();
            bankRequest.setBankBizIdList(new ArrayList<>(bankBizIdSet));
            Result<List<ApiBankDetailResponse>> bankResult = apiBankFeignClient.list(bankRequest);

            if (bankResult != null && bankResult.getCode() == 200 && !CollectionUtils.isEmpty(bankResult.getData())) {
                for (ApiBankDetailResponse bankDetail : bankResult.getData()) {
                    // 优先使用银行简称，如果没有则使用银行全称
                    String bankName = StringUtils.isNotBlank(bankDetail.getBankName())
                            ? bankDetail.getBankName()
                            : bankDetail.getBankShortName();
                    bankNameMap.put(bankDetail.getBankBizId(), bankName);
                }
            }
        } catch (Exception e) {
            log.error("获取银行名称失败", e);
        }
        return bankNameMap;
    }

    /**
     * 翻译缴费方式
     * 处理多个缴费方式（用分号分隔）的情况
     */
    private String translatePaymentMethod(String paymentMethod, Map<String, String> dictMap) {
        if (StringUtils.isBlank(paymentMethod)) {
            return paymentMethod;
        }

        String[] methods = paymentMethod.split(";");
        StringBuilder translated = new StringBuilder();

        for (int i = 0; i < methods.length; i++) {
            String method = methods[i].trim();
            String label = dictMap.get(method);

            if (label != null) {
                translated.append(label);
            } else {
                translated.append(method); // 如果找不到对应的字典项，保留原值
            }

            if (i < methods.length - 1) {
                translated.append(";");
            }
        }

        return translated.toString();
    }

    /**
     * 翻译银行名称
     * 处理多个银行（用分号分隔）的情况
     */
    private String translateBankNames(String payingBank, Map<String, String> bankNameMap) {
        if (StringUtils.isBlank(payingBank)) {
            return payingBank;
        }

        String[] bankIds = payingBank.split(";");
        StringBuilder translated = new StringBuilder();

        for (int i = 0; i < bankIds.length; i++) {
            String bankId = bankIds[i].trim();
            String bankName = bankNameMap.get(bankId);

            if (bankName != null) {
                translated.append(bankName);
            } else {
                translated.append(bankId); // 如果找不到对应的银行，保留原ID
            }

            if (i < bankIds.length - 1) {
                translated.append(";");
            }
        }

        return translated.toString();
    }

    /**
     * 添加-保费对账记录信息
     * @param request
     * @return
     */
    @Override
    public Result add(ApiPremiumReconciliationAddRequest request) {
        //根据当前Policy保单信息里面的生效日期、付款频率、缴费宽限期，校验当天是否在缴费期内，不在缴费期内不能保费对账 TODO 校验待定
        //保费对账信息
        ApiPremiumReconciliationDto apiPremiumReconciliationDto = request.getApiPremiumReconciliationDto();
        //校验-保单所有期数的保费对账是否对账完成（全部对账完成就不能新增录入对账信息了）
//        Result<Boolean> result = checkReconciliationComplete(apiPremiumReconciliationDto.getPolicyNo());
//        if (!result.getData()) {
//            throw new BusinessException(result.getMsg());
//        }
        //校验保单信息是否存在
        PolicyFollow policyFollow = policyFollowService.queryOneByPolicyNo(apiPremiumReconciliationDto.getPolicyNo());
        if (Objects.isNull(policyFollow)) {
            throw new BusinessException("保单信息不存在");
        }
        PremiumReconciliation premiumReconciliation = new PremiumReconciliation();
        //计算当前期数
        String currentIssueNumber = calculateCurrentIssueNumber(policyFollow.getPolicyNo(),Integer.parseInt(policyFollow.getIssueNumber().toString()));
        //根据计算的当前期数和保单号查询最新的记录，如果无记录那么新增的对账记录的待付金额为保单保费的金额，否则为最新记录的待付金额。
        PremiumReconciliation newDto = iPremiumReconciliationService.queryLatestOneByPolicyNo(policyFollow.getPolicyNo(),currentIssueNumber);
        if (Objects.isNull(newDto)) {
            //无记录那么新增的对账记录的待付金额为保单保费的金额
            premiumReconciliation.setRemainingUnpaidCurrency(policyFollow.getPolicyCurrency());
            premiumReconciliation.setRemainingUnpaidAmount(policyFollow.getEachIssuePremium());
        }else {
            //否则为最新记录的待付金额。
            premiumReconciliation.setRemainingUnpaidCurrency(newDto.getRemainingUnpaidCurrency());
            premiumReconciliation.setRemainingUnpaidAmount(newDto.getRemainingUnpaidAmount());
        }
        //申请人
        premiumReconciliation.setApplicant(apiPremiumReconciliationDto.getApplicant());
        //当前期数
        premiumReconciliation.setCurrentIssueNumber(currentIssueNumber);
        //保单受保人（被保人）
        premiumReconciliation.setInsured(policyFollow.getInsured());
        //保险公司名称
        premiumReconciliation.setInsuranceCompany(policyFollow.getInsuranceCompany());
        //保单号
        premiumReconciliation.setPolicyNo(policyFollow.getPolicyNo());
        premiumReconciliation.setReconciliationType(apiPremiumReconciliationDto.getReconciliationType());
        //保费对账记录表唯一业务ID
        premiumReconciliation.setPremiumReconciliationBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_PREMIUM_RECONCILIATION.getCode()));
        //对账状态 - 保司对账中
        premiumReconciliation.setReconciliationStatus(ReconciliationStatusEnum.BS_DZZ.getItemValue());
        iPremiumReconciliationService.saveOrUpdate(premiumReconciliation);

        //添加-保费对账汇款记录列表
        apiPremiumRemittanceService.addPremiumRemittanceList(request.getApiPremiumRemittanceDtoList(),
                premiumReconciliation.getPremiumReconciliationBizId());

        return Result.success();
    }

    /**
     * 计算当前期数
     * @param policyNo
     * @return
     */
    public String calculateCurrentIssueNumber(String policyNo,Integer paymentTerm) {
        //保单号查询对账记录无数据，说明第一期。有数据：1、最新的记录的待付金额大于0，当前期数为最新的记录期数。2、最新的记录的待付金额小于等于0，当前期数 = 最新的记录期数 + 1 <= 保单的供款年期
        //保单号查询对账记录无数据，说明第一期
        //根据保单号查询最新对账记录
        PremiumReconciliation premiumReconciliation = iPremiumReconciliationService.queryLatestOneByPolicyNo(policyNo,"");
        if (Objects.isNull(premiumReconciliation)) {
            return "1";
        }
        if (ReconciliationStatusEnum.BS_DZZ.getItemValue().equals(premiumReconciliation.getReconciliationStatus())) {
            //当前保单号的记录的对账状态为对账中，请先对账完成再发起新的对账
            throw new BusinessException("当前保单号的最新的对账记录的对账状态为对账中，请先设置认定结果，再发起新的对账");
        }
        //有数据，最新的记录的待付金额大于0，当前期数为最新的记录期数
        if (premiumReconciliation.getRemainingUnpaidAmount().compareTo(BigDecimal.ZERO) > 0) {
            return premiumReconciliation.getCurrentIssueNumber();
        }
        //最新的记录的待付金额小于等于0，当前期数 = 最新的记录期数 + 1 <= 保单的供款年期
        if (premiumReconciliation.getRemainingUnpaidAmount().compareTo(BigDecimal.ZERO) <= 0) {
            //最新的记录期数 + 1
            Integer thisQs = Integer.parseInt(premiumReconciliation.getCurrentIssueNumber()) + 1;
            if (thisQs > paymentTerm) {
                //最新的记录期数 + 1 > 保单的供款年期，提示
                throw new BusinessException("当前保单保费所有期数已经全部对账完成，不能对账了");
            }
            return thisQs.toString();
        }
        return "1";
    }

    /**
     * 编辑-单个保费对账记录信息
     * @param request
     * @return
     */
    @Override
    public Result edit(ApiPremiumReconciliationDto request) {
        if (StringUtils.isBlank(request.getPremiumReconciliationBizId())) {
            throw new BusinessException("保费对账记录表唯一业务ID不能为空");
        }
        //校验保费对账记录信息是否存在
        Result<PremiumReconciliation> result = checkPremiumReconciliationIsExist(request.getPremiumReconciliationBizId());
        PremiumReconciliation premiumReconciliation = result.getData();
        BeanUtils.copyProperties(request,premiumReconciliation);
        iPremiumReconciliationService.saveOrUpdate(premiumReconciliation);
        return Result.success();
    }

    /**
     * 详情-保费对账记录信息
     * @param premiumReconciliationBizId 保费对账记录表唯一业务ID
     * @return
     */
    @Override
    public Result<ApiPremiumReconciliationDetailResponse> detail(String premiumReconciliationBizId) {
        ApiPremiumReconciliationDetailResponse response = new ApiPremiumReconciliationDetailResponse();
        //校验保费对账记录信息是否存在
        Result<PremiumReconciliation> result = checkPremiumReconciliationIsExist(premiumReconciliationBizId);
        PremiumReconciliation premiumReconciliation = result.getData();
        ApiPremiumReconciliationDto apiPremiumReconciliationDto = new ApiPremiumReconciliationDto();
        BeanUtils.copyProperties(premiumReconciliation,apiPremiumReconciliationDto);
        response.setApiPremiumReconciliationDto(apiPremiumReconciliationDto);
        //保费对账-汇款记录列表
        List<ApiPremiumRemittanceDto> apiPremiumRemittanceDtoList = apiPremiumRemittanceService.apiPremiumRemittanceDtoList(premiumReconciliationBizId);
        response.setApiPremiumRemittanceDtoList(apiPremiumRemittanceDtoList);
        return Result.success(response);
    }

    /**
     * 计算待付金额-保费对账记录信息
     * @param request
     * @return
     */
    @Override
    public Result<ApiCalculateRemainingUnpaidAmountResponse> calculateRemainingUnpaidAmount(ApiCalculateRemainingUnpaidAmountRequest request) {
        //校验保费对账记录信息是否存在
        Result<PremiumReconciliation> result = checkPremiumReconciliationIsExist(request.getPremiumReconciliationBizId());
        PremiumReconciliation premiumReconciliation = result.getData();

        //查询保单信息
        PolicyFollow policyFollow = policyFollowService.queryOneByPolicyNo(premiumReconciliation.getPolicyNo());
        if (Objects.isNull(policyFollow)) {
            throw new BusinessException("保单信息不存在");
        }

        //获取保单币种
        String policyCurrency = policyFollow.getPolicyCurrency();
        if (StringUtils.isBlank(policyCurrency)) {
            throw new BusinessException("保单币种不能为空");
        }

        //获取当次认定币种和金额
        String recognizedCurrency = request.getRecognizedCurrency();
        if (StringUtils.isBlank(recognizedCurrency)) {
            throw new BusinessException("当次保司认定币种不能为空");
        }

        BigDecimal currentRecognizedAmount = request.getRecognizedAmount();
        if (currentRecognizedAmount == null) {
            throw new BusinessException("当次保司认定金额不能为空");
        }

        log.info("计算待付金额 - 保单号: {}, 保单币种: {}, 认定币种: {}, 认定金额: {}",
                premiumReconciliation.getPolicyNo(), policyCurrency, recognizedCurrency, currentRecognizedAmount);

        // 构建转换请求列表（与其他对账记录一起批量转换）
        List<ApiExchangeRateConvertRequest> convertRequests = new ArrayList<>();
        List<ConvertInfo> convertInfoList = new ArrayList<>();

        //首先处理当前认定金额的转换
        if (!recognizedCurrency.equalsIgnoreCase(policyCurrency)) {
            ApiExchangeRateConvertRequest currentConvertRequest = new ApiExchangeRateConvertRequest();
            currentConvertRequest.setAmount(currentRecognizedAmount);
            currentConvertRequest.setFromCurrency(recognizedCurrency);
            currentConvertRequest.setToCurrency(policyCurrency);
            currentConvertRequest.setRequestId("current_" + request.getPremiumReconciliationBizId());

            ConvertInfo currentInfo = new ConvertInfo();
            currentInfo.reconciliationBizId = request.getPremiumReconciliationBizId();
            currentInfo.originalAmount = currentRecognizedAmount;
            currentInfo.originalCurrency = recognizedCurrency;
            currentInfo.targetCurrency = policyCurrency;
            currentInfo.requestId = currentConvertRequest.getRequestId();

            convertRequests.add(currentConvertRequest);
            convertInfoList.add(currentInfo);

            log.info("添加当前认定金额转换请求: {} {} -> {}, requestId: {}",
                    currentRecognizedAmount, recognizedCurrency, policyCurrency, currentConvertRequest.getRequestId());
        }

        //获取其他对账记录需要转换的金额
        List<PremiumReconciliation> premiumReconciliationList = iPremiumReconciliationService.queryList(PremiumReconciliationDto.builder()
                .premiumReconciliationBizId(request.getPremiumReconciliationBizId())
                .policyNo(premiumReconciliation.getPolicyNo())
                .currentIssueNumber(premiumReconciliation.getCurrentIssueNumber())
                .isExcludeMy(true)
                .build());

        if (!CollectionUtils.isEmpty(premiumReconciliationList)) {
            log.info("找到 {} 条其他对账记录需要处理", premiumReconciliationList.size());

            for (int i = 0; i < premiumReconciliationList.size(); i++) {
                PremiumReconciliation pr = premiumReconciliationList.get(i);

                if (pr.getRecognizedAmount() != null && StringUtils.isNotBlank(pr.getRecognizedCurrency())) {
                    String otherCurrency = pr.getRecognizedCurrency();
                    BigDecimal otherAmount = pr.getRecognizedAmount();

                    if (!otherCurrency.equalsIgnoreCase(policyCurrency)) {
                        // 需要汇率转换
                        ApiExchangeRateConvertRequest otherConvertRequest = new ApiExchangeRateConvertRequest();
                        otherConvertRequest.setAmount(otherAmount);
                        otherConvertRequest.setFromCurrency(otherCurrency);
                        otherConvertRequest.setToCurrency(policyCurrency);
                        otherConvertRequest.setRequestId("other_" + pr.getPremiumReconciliationBizId());

                        ConvertInfo otherInfo = new ConvertInfo();
                        otherInfo.reconciliationBizId = request.getPremiumReconciliationBizId(); // 注意：这里使用当前对账ID，用于累加
                        otherInfo.originalAmount = otherAmount;
                        otherInfo.originalCurrency = otherCurrency;
                        otherInfo.targetCurrency = policyCurrency;
                        otherInfo.requestId = otherConvertRequest.getRequestId();

                        convertRequests.add(otherConvertRequest);
                        convertInfoList.add(otherInfo);

                        log.info("添加其他记录转换请求[{}]: {} {} -> {}, requestId: {}",
                                i, otherAmount, otherCurrency, policyCurrency, otherConvertRequest.getRequestId());
                    }
                }
            }
        }

        //执行汇率转换
        BigDecimal totalRecognizedAmountInPolicyCurrency = BigDecimal.ZERO;

        // 先累加币种相同的金额
        // 当前认定金额（如果币种相同）
        if (recognizedCurrency.equalsIgnoreCase(policyCurrency)) {
            totalRecognizedAmountInPolicyCurrency = totalRecognizedAmountInPolicyCurrency.add(currentRecognizedAmount);
            log.info("当前认定金额币种相同，直接累加: {}", currentRecognizedAmount);
        }

        // 其他记录的币种相同金额
        if (!CollectionUtils.isEmpty(premiumReconciliationList)) {
            for (PremiumReconciliation pr : premiumReconciliationList) {
                if (pr.getRecognizedAmount() != null && StringUtils.isNotBlank(pr.getRecognizedCurrency())) {
                    if (pr.getRecognizedCurrency().equalsIgnoreCase(policyCurrency)) {
                        totalRecognizedAmountInPolicyCurrency = totalRecognizedAmountInPolicyCurrency.add(pr.getRecognizedAmount());
                        log.info("其他记录[{}]币种相同，直接累加: {}", pr.getPremiumReconciliationBizId(), pr.getRecognizedAmount());
                    }
                }
            }
        }

        // 批量转换需要转换的金额
        if (!CollectionUtils.isEmpty(convertRequests)) {
            try {
                log.info("开始批量汇率转换，共 {} 条请求", convertRequests.size());

                Result<List<ApiExchangeRateConvertResponse>> batchResult =
                        apiExchangeRateFeignClient.batchConvert(convertRequests);

                if (batchResult != null && batchResult.getCode() == 200 &&
                        !CollectionUtils.isEmpty(batchResult.getData())) {

                    List<ApiExchangeRateConvertResponse> responses = batchResult.getData();
                    log.info("汇率转换返回 {} 条结果", responses.size());

                    // 匹配转换结果
                    for (ApiExchangeRateConvertResponse convertResponse : responses) {
                        if (convertResponse.getConvertedAmount() != null) {
                            // 查找匹配的ConvertInfo
                            ConvertInfo matchedInfo = null;

                            // 先尝试通过requestId匹配
                            if (StringUtils.isNotBlank(convertResponse.getRequestId())) {
                                for (ConvertInfo info : convertInfoList) {
                                    if (convertResponse.getRequestId().equals(info.requestId)) {
                                        matchedInfo = info;
                                        break;
                                    }
                                }
                            }

                            // 如果通过requestId没有匹配到，尝试通过金额和币种匹配
                            if (matchedInfo == null) {
                                for (ConvertInfo info : convertInfoList) {
                                    if (convertResponse.getOriginalAmount() != null &&
                                            convertResponse.getOriginalAmount().compareTo(info.originalAmount) == 0 &&
                                            convertResponse.getOriginalCurrency().equalsIgnoreCase(info.originalCurrency) &&
                                            convertResponse.getTargetCurrency().equalsIgnoreCase(info.targetCurrency)) {
                                        matchedInfo = info;
                                        break;
                                    }
                                }
                            }

                            if (matchedInfo != null) {
                                BigDecimal convertedAmount = convertResponse.getConvertedAmount()
                                        .setScale(2, RoundingMode.HALF_EVEN);
                                totalRecognizedAmountInPolicyCurrency = totalRecognizedAmountInPolicyCurrency.add(convertedAmount);

                                log.info("汇率转换成功: {} {} -> {} {}, 汇率: {}, 转换后金额: {}",
                                        convertResponse.getOriginalAmount(), convertResponse.getOriginalCurrency(),
                                        convertedAmount, convertResponse.getTargetCurrency(),
                                        convertResponse.getExchangeRate(), convertedAmount);
                            } else {
                                log.warn("无法匹配转换结果: requestId={}, 原金额={} {}, 目标币种={}",
                                        convertResponse.getRequestId(), convertResponse.getOriginalAmount(),
                                        convertResponse.getOriginalCurrency(), convertResponse.getTargetCurrency());
                            }
                        }
                    }
                } else {
                    log.error("批量汇率转换失败: code={}, msg={}",
                            batchResult != null ? batchResult.getCode() : "null",
                            batchResult != null ? batchResult.getMsg() : "null");
                    // 如果汇率转换失败，可以尝试使用单个转换作为备选方案
                    return fallbackSingleConvert(request, premiumReconciliation, policyFollow, policyCurrency,
                            recognizedCurrency, currentRecognizedAmount, premiumReconciliationList);
                }
            } catch (Exception e) {
                log.error("批量汇率转换异常", e);
                // 异常情况下的备选方案
                return fallbackSingleConvert(request, premiumReconciliation, policyFollow, policyCurrency,
                        recognizedCurrency, currentRecognizedAmount, premiumReconciliationList);
            }
        }

        // 计算总保费和剩余待付金额
        BigDecimal paymentPremium = policyFollow.getEachIssuePremium() != null ?
                policyFollow.getEachIssuePremium() : BigDecimal.ZERO;

        BigDecimal policyLevy = BigDecimal.ZERO;
        if (StringUtils.isNotBlank(policyFollow.getPolicyLevy())) {
            try {
                policyLevy = new BigDecimal(policyFollow.getPolicyLevy().trim());
            } catch (NumberFormatException e) {
                log.error("保单征费格式错误: {}", policyFollow.getPolicyLevy(), e);
            }
        }

        BigDecimal totalPremium = paymentPremium.add(policyLevy);
        BigDecimal remainingUnpaidAmount = totalPremium.subtract(totalRecognizedAmountInPolicyCurrency);

        // 设置精度
        remainingUnpaidAmount = remainingUnpaidAmount.setScale(2, RoundingMode.HALF_EVEN);

        log.info("计算结果 - 总保费: {}, 总认定金额: {}, 剩余待付金额: {}",
                totalPremium, totalRecognizedAmountInPolicyCurrency, remainingUnpaidAmount);

        //构建响应对象
        ApiCalculateRemainingUnpaidAmountResponse response = new ApiCalculateRemainingUnpaidAmountResponse();
        response.setRemainingUnpaidAmount(remainingUnpaidAmount);
        response.setRemainingUnpaidCurrency(policyCurrency);

        return Result.success(response);
    }

    /**
     * 备选方案：使用单次汇率转换
     */
    private Result<ApiCalculateRemainingUnpaidAmountResponse> fallbackSingleConvert(
            ApiCalculateRemainingUnpaidAmountRequest request,
            PremiumReconciliation premiumReconciliation,
            PolicyFollow policyFollow,
            String policyCurrency,
            String recognizedCurrency,
            BigDecimal currentRecognizedAmount,
            List<PremiumReconciliation> premiumReconciliationList) {

        log.info("使用备选方案：单次汇率转换");

        BigDecimal totalRecognizedAmountInPolicyCurrency = BigDecimal.ZERO;

        // 1. 转换当前认定金额
        BigDecimal currentConvertedAmount;
        if (recognizedCurrency.equalsIgnoreCase(policyCurrency)) {
            currentConvertedAmount = currentRecognizedAmount;
        } else {
            ApiExchangeRateConvertRequest currentRequest = new ApiExchangeRateConvertRequest();
            currentRequest.setAmount(currentRecognizedAmount);
            currentRequest.setFromCurrency(recognizedCurrency);
            currentRequest.setToCurrency(policyCurrency);

            Result<ApiExchangeRateConvertResponse> currentResult = apiExchangeRateFeignClient.convert(currentRequest);
            if (currentResult.getCode() != 200 || currentResult.getData() == null) {
                throw new BusinessException("当前认定金额汇率转换失败: " + currentResult.getMsg());
            }
            currentConvertedAmount = currentResult.getData().getConvertedAmount();
        }
        totalRecognizedAmountInPolicyCurrency = totalRecognizedAmountInPolicyCurrency.add(currentConvertedAmount);

        // 2. 转换其他记录认定金额
        if (!CollectionUtils.isEmpty(premiumReconciliationList)) {
            for (PremiumReconciliation pr : premiumReconciliationList) {
                if (pr.getRecognizedAmount() != null && StringUtils.isNotBlank(pr.getRecognizedCurrency())) {
                    BigDecimal otherConvertedAmount;

                    if (pr.getRecognizedCurrency().equalsIgnoreCase(policyCurrency)) {
                        otherConvertedAmount = pr.getRecognizedAmount();
                    } else {
                        ApiExchangeRateConvertRequest otherRequest = new ApiExchangeRateConvertRequest();
                        otherRequest.setAmount(pr.getRecognizedAmount());
                        otherRequest.setFromCurrency(pr.getRecognizedCurrency());
                        otherRequest.setToCurrency(policyCurrency);

                        Result<ApiExchangeRateConvertResponse> otherResult = apiExchangeRateFeignClient.convert(otherRequest);
                        if (otherResult.getCode() == 200 && otherResult.getData() != null) {
                            otherConvertedAmount = otherResult.getData().getConvertedAmount();
                        } else {
                            log.warn("其他记录汇率转换失败，跳过: {}", pr.getPremiumReconciliationBizId());
                            continue;
                        }
                    }

                    totalRecognizedAmountInPolicyCurrency = totalRecognizedAmountInPolicyCurrency.add(otherConvertedAmount);
                }
            }
        }

        // 3. 计算剩余待付金额
        BigDecimal paymentPremium = policyFollow.getEachIssuePremium() != null ?
                policyFollow.getEachIssuePremium() : BigDecimal.ZERO;

        BigDecimal policyLevy = BigDecimal.ZERO;
        if (StringUtils.isNotBlank(policyFollow.getPolicyLevy())) {
            try {
                policyLevy = new BigDecimal(policyFollow.getPolicyLevy().trim());
            } catch (NumberFormatException e) {
                log.error("保单征费格式错误", e);
            }
        }

        BigDecimal totalPremium = paymentPremium.add(policyLevy);
        BigDecimal remainingUnpaidAmount = totalPremium.subtract(totalRecognizedAmountInPolicyCurrency);
        remainingUnpaidAmount = remainingUnpaidAmount.setScale(2, RoundingMode.HALF_EVEN);

        ApiCalculateRemainingUnpaidAmountResponse response = new ApiCalculateRemainingUnpaidAmountResponse();
        response.setRemainingUnpaidAmount(remainingUnpaidAmount);
        response.setRemainingUnpaidCurrency(policyCurrency);

        return Result.success(response);
    }

    /**
     * 设置认定结果-保费对账记录信息
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result editResult(ApiPremiumReconciliationResultEditRequest request) {
        //校验保费对账记录信息是否存在
        Result<PremiumReconciliation> result = checkPremiumReconciliationIsExist(request.getPremiumReconciliationBizId());
        PremiumReconciliation premiumReconciliation = result.getData();
        BeanUtils.copyProperties(request,premiumReconciliation);
        //对账状态->保司对账成功
        premiumReconciliation.setReconciliationStatus(ReconciliationStatusEnum.BS_DZ_CG.getItemValue());
        //更新保费对账记录信息
        iPremiumReconciliationService.saveOrUpdate(premiumReconciliation);

        //校验当期剩余待付金额小于等于0并且当前期数是第一期首期，才会去更新保单生效日期和保单状态
        if (premiumReconciliation.getCurrentIssueNumber().equals("1")) {
            //当前期数是第一期首期
            if (request.getRemainingUnpaidAmount().compareTo(BigDecimal.ZERO) <= 0) {
                //校验生效日期、核保日期必填
                if (Objects.isNull(request.getEffectiveDate())) {
                    throw new BusinessException("生效日期不能为空");
                }
                if (Objects.isNull(request.getUnderwritingDate())) {
                    throw new BusinessException("核保日期不能为空");
                }
                PolicyFollow policyFollow = policyFollowService.queryOneByPolicyNo(premiumReconciliation.getPolicyNo());
                if (Objects.isNull(policyFollow)) {
                    throw new BusinessException("新单跟进数据不存在");
                }
                ChangePolicyFollowStatusRequest statusRequest = new ChangePolicyFollowStatusRequest();
                statusRequest.setEffectiveDate(request.getEffectiveDate());
                statusRequest.setUnderwritingDate(request.getUnderwritingDate());
                statusRequest.setPolicyBizId(policyFollow.getPolicyBizId());
                statusRequest.setStatus("TAKE_EFFECT");
                //遍历保单转介人列表信息 -> 调用基本法算出预计发佣列表
                // 通过代理对象调用
                getSelf().execute(statusRequest);
                Result<Boolean> result1 = changePolicyFollowStatus(statusRequest);
                if (result1.getCode() != 200) {
                    throw new BusinessException(result1.getMsg());
                }
            }else {
                //大于0，只更新新单跟进：新单状态——>保费对账成功，核保中
                PolicyFollow policyFollow = policyFollowService.queryOneByPolicyNo(premiumReconciliation.getPolicyNo());
                if (!Objects.isNull(policyFollow)) {
                    //新单跟进状态——>保费对账成功，核保中
                    policyFollow.setStatus("UNDERWRITING_PROGRESS");
                    policyFollowService.saveOrUpdate(policyFollow);
                }
            }
        }
        return Result.success();
    }

    @Override
    @Async("commonAsyncExecutor")
    public void execute(ChangePolicyFollowStatusRequest changePolicyFollowStatusRequest) {
        changePolicyFollowStatus(changePolicyFollowStatusRequest);
    }

    /**
     * 修改跟进状态
     *
     * @param changePolicyFollowStatusRequest
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> changePolicyFollowStatus(ChangePolicyFollowStatusRequest changePolicyFollowStatusRequest) {
        // 通过 RequestContextHolder 获取 HttpServletRequest
        HttpServletRequest request = ((ServletRequestAttributes)
                RequestContextHolder.currentRequestAttributes()).getRequest();
        if (changePolicyFollowStatusRequest == null || StringUtils.isBlank(changePolicyFollowStatusRequest.getPolicyBizId())) {
            return Result.fail(ResultCode.PARAMS_ERROR.getCode(), "policyBizId不能为空");
        }
        if (ObjectUtils.isEmpty(changePolicyFollowStatusRequest.getEffectiveDate())) {
            return Result.fail(ResultCode.PARAMS_ERROR.getCode(), "生效日期不能为空");
        }
        if (ObjectUtils.isEmpty(changePolicyFollowStatusRequest.getUnderwritingDate())) {
            return Result.fail(ResultCode.PARAMS_ERROR.getCode(), "核保日期不能为空");
        }

        String policyBizId = changePolicyFollowStatusRequest.getPolicyBizId();
        PolicyFollow policyFollow = policyFollowService.getByPolicyBizId(policyBizId);
        if (policyFollow == null) {
            return Result.fail(ResultCode.NULL_ERROR.getCode(), ResultCode.NULL_ERROR.getMessage());
        }

        PolicyFollowStatusEnum currentStatusEnum = PolicyFollowStatusEnum.getEnumByValue(changePolicyFollowStatusRequest.getStatus());
        // 修改为生效时需要校验、同步预计发佣
        if (PolicyFollowStatusEnum.EFFECTIVE.equals(currentStatusEnum)) {
            String productLaunchBizId = policyFollow.getProductLaunchBizId();
            // 校验产品是否维护预计来佣数据
            if (ObjectUtils.isEmpty(productLaunchBizId)) {
                return Result.fail(ResultCode.NULL_ERROR.getCode(), "新单跟进记录中，productLaunchBizId不能为空");
            }
            List<ApiExpectedSpeciesListResponse> expectedSpeciesList = commissionExpectedService.queryExpectedSpeciesByFeign(productLaunchBizId);
            if (ObjectUtils.isEmpty(expectedSpeciesList)) {
                return Result.fail(ResultCode.NULL_ERROR.getCode(), "产品未维护预计来佣数据");
            }
            // 校验产品是否维护发佣信息
            Boolean hasCommissionInfo = commissionExpectedService.checkProductExpectedFortune(productLaunchBizId);
            if (!hasCommissionInfo) {
                return Result.fail(ResultCode.NULL_ERROR.getCode(), "产品未维护发佣信息");
            }
        }

        // 修改逻辑
        policyFollowService.changePolicyFollowStatus(changePolicyFollowStatusRequest, policyFollow);

        // 修改为生效时需要同步预计发佣
        if (PolicyFollowStatusEnum.EFFECTIVE.equals(currentStatusEnum)) {
            // 获取Token
            String token = request.getHeader("Authorization");
            log.info("修改跟进状态获取token：{}", token);
            // 同步：根据保单生成预计出账记录
            generateExpectedFortuneSync(token, policyFollow.getPolicyNo());
        }
        return Result.success(true);
    }

    /**
     * 同步生成预计出账记录
     *
     * @param token 认证Token
     * @param policyNo 保单号
     */
    private void generateExpectedFortuneSync(String token, String policyNo) {
        // 设置ThreadLocal Token
        FeignTokenInterceptor.setThreadLocalToken(token);

        // 调用 ApiExpectedFortuneService 的 generateSyncWithLogAndRedis（同步版本，包含日志和Redis处理）
        ApiGenerateExpectedFortuneRequest generateExpectedFortuneRequest = new ApiGenerateExpectedFortuneRequest();
        generateExpectedFortuneRequest.setPolicyNo(policyNo);
        log.info("生成预计发佣generateSyncWithLogAndRedis——>PolicyNo：{}", policyNo);
        Result<ApiGenerateExpectedFortuneResponse> result = apiExpectedFortuneService.generateSyncWithLogAndRedis(generateExpectedFortuneRequest);
        if (result != null && result.getCode() == 200) {
            log.info("新单跟进-同步生成预计出账记录成功:保单号={}", policyNo);
        }
    }

    /**
     * 校验-保单所有期数的保费对账是否对账完成（全部对账完成就不能新增录入对账信息了）
     * @param policyNo
     * @return
     */
    @Override
    public Result<Boolean> checkReconciliationComplete(String policyNo) {
        //查询保单信息
        PolicyFollow policyFollow = policyFollowService.queryOneByPolicyNo(policyNo);
        if (Objects.isNull(policyFollow)) {
            throw new BusinessException("保单信息不存在");
        }
        //获取保单供款年期
        String paymentTerm = String.valueOf(policyFollow.getIssueNumber());
        //根据保单号查询最新对账记录
        PremiumReconciliation premiumReconciliation = iPremiumReconciliationService.queryLatestOneByPolicyNo(policyNo,"");
        if (Objects.isNull(premiumReconciliation)) {
            //无数据，说明还没有对账记录，可以对账。
            return Result.success(true);
        }
        if (ReconciliationStatusEnum.BS_DZZ.getItemValue().equals(premiumReconciliation.getReconciliationStatus())) {
            //当前保单号的记录的对账状态为对账中，请先对账完成再发起新的对账
            return Result.success(false,"当前保单号的最新的对账记录的对账状态为对账中，请先设置认定结果，再发起新的对账");
        }
        //有数据
        //校验最新对账记录的待付金额是否小于等于0并且当前期数等于保单的供款年期，如果是说明对账所有期数已经全部完成不能对账了。
        if (premiumReconciliation.getRemainingUnpaidAmount().compareTo(BigDecimal.ZERO) <= 0
                && premiumReconciliation.getCurrentIssueNumber().equals(paymentTerm)) {
            return Result.success(false,"当前保单保费所有期数已经全部对账完成，不能对账了");
        }
        return Result.success(true);
    }

    /**
     * 校验保费对账记录信息是否存在
     * @param premiumReconciliationBizId
     * @return
     */
    @Override
    public Result<PremiumReconciliation> checkPremiumReconciliationIsExist(String premiumReconciliationBizId) {
        PremiumReconciliation premiumReconciliation = iPremiumReconciliationService.queryOne(premiumReconciliationBizId);
        if (Objects.isNull(premiumReconciliation)) {
            //数据不存在
            throw new BusinessException("保费对账记录信息不存在");
        }
        return Result.success(premiumReconciliation);
    }

}