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

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yd.auth.core.dto.AuthUserDto;
import com.yd.auth.core.utils.SecurityUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yd.base.feign.client.exchangerate.ApiExchangeRateFeignClient;
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.service.common.ErrorCode;
import com.yd.csf.service.component.CommissionAsyncService;
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.CommissionStatusEnum;
import com.yd.csf.service.enums.FortuneStatusEnum;
import com.yd.csf.service.model.*;
import com.yd.csf.service.service.*;
import com.yd.csf.service.audit.AuditContextHolder;
import com.yd.csf.service.audit.AuditHelper;
import com.yd.csf.service.audit.AuditService;
import com.yd.csf.service.audit.AuditTemplate;
import com.yd.csf.service.dao.CommissionMapper;
import com.yd.csf.service.vo.CommissionStatisticsVO;
import com.yd.csf.service.vo.CommissionVO;
import com.yd.insurance.base.feign.client.insurancereconciliationcompany.ApiInsuranceReconciliationCompanyFeignClient;
import com.yd.insurance.base.feign.request.insurancereconciliationcompany.ApiInsuranceReconciliationCompanyPageRequest;
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;

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

/**
 * @author Zhang Jianan
 * @description 针对表【commission(保单来佣表)】的数据库操作Service实现
 * @createDate 2025-09-19 16:08:05
 */
@Service
@Slf4j
public class CommissionServiceImpl extends ServiceImpl<CommissionMapper, Commission>
        implements CommissionService {

    @Resource
    private FortuneService fortuneService;
    @Resource
    private PolicyFollowService policyFollowService;
    @Resource
    private PolicyBrokerService policyBrokerService;
    @Resource
    private PolicyService policyService;
    @Resource
    private CommissionExpectedService commissionExpectedService;
    @Resource
    private IExpectedFortuneService iExpectedFortuneService;
    @Resource
    private CommissionEditRecordService commissionEditRecordService;
    @Resource
    private CommissionCompareRecordService commissionCompareRecordService;
    @Resource
    private CommissionAsyncService commissionAsyncService;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private ReceivableService receivableService;
    @Resource
    private ApiExchangeRateFeignClient apiExchangeRateFeignClient;
    @Resource
    private ApiInsuranceReconciliationCompanyFeignClient apiInsuranceReconciliationCompanyFeignClient;
    @Resource
    private PolicyPolicyholderService policyPolicyholderService;
    @Resource
    private AuditService auditService;
    @Resource
    private AuditHelper auditHelper;
    @Resource
    private AuditTemplate auditTemplate;


    @Override
    public QueryWrapper<Commission> getQueryWrapper(CommissionQueryRequest commissionQueryRequest) {
        QueryWrapper<Commission> queryWrapper = new QueryWrapper<>();
        if (commissionQueryRequest == null) {
            return queryWrapper;
        }

        String reconciliationYearMonth = commissionQueryRequest.getReconciliationYearMonth();
        List<String> statusList = commissionQueryRequest.getStatusList();
        String policyNo = commissionQueryRequest.getPolicyNo();
        List<String> insuranceCompanyBizIdList = commissionQueryRequest.getInsuranceCompanyBizIdList();
        List<String> reconciliationCompanyBizIdList = commissionQueryRequest.getReconciliationCompanyBizIdList();
        Date commissionDateStart = commissionQueryRequest.getCommissionDateStart();
        Date commissionDateEnd = commissionQueryRequest.getCommissionDateEnd();
        Date expectedDate = commissionQueryRequest.getExpectedDate();

        // 查询对账年月
        queryWrapper.eq(StringUtils.isNotBlank(reconciliationYearMonth), "reconciliation_year_month", reconciliationYearMonth);

        queryWrapper.in(CollectionUtils.isNotEmpty(statusList), "status", statusList);
        queryWrapper.like(StringUtils.isNotBlank(policyNo), "policy_no", policyNo);
        queryWrapper.in(CollectionUtils.isNotEmpty(insuranceCompanyBizIdList), "insurance_company_biz_id", insuranceCompanyBizIdList);
        queryWrapper.in(CollectionUtils.isNotEmpty(reconciliationCompanyBizIdList), "reconciliation_company_biz_id", reconciliationCompanyBizIdList);

        if (commissionDateStart != null && commissionDateEnd != null) {
            queryWrapper.between("commission_date", commissionDateStart, commissionDateEnd);
        }
        // 查询预计入账日期及之前的记录, 关联查询 commission_expected 表
        if (expectedDate != null) {
            queryWrapper.apply("EXISTS (SELECT 1 FROM commission_expected ce WHERE ce.commission_expected_biz_id = commission.commission_expected_biz_id AND ce.commission_date <= {0})",
                    expectedDate);
        }

        queryWrapper.orderByDesc("id");
        return queryWrapper;
    }

    @Override
    public Page<CommissionVO> getCommissionVOPage(Page<Commission> commissionPage) {
        List<Commission> commissionList = commissionPage.getRecords();
        Page<CommissionVO> commissionVOPage = new Page<>(commissionPage.getCurrent(), commissionPage.getSize(), commissionPage.getTotal());
        if (CollUtil.isEmpty(commissionList)) {
            return commissionVOPage;
        }

        // 1.关联查询保单信息
        Set<String> policyNoSet = commissionList.stream().map(Commission::getPolicyNo).collect(Collectors.toSet());
        QueryWrapper<Policy> queryWrapper = new QueryWrapper<Policy>();
        queryWrapper.select("policy_no", "payment_premium", "product_name", "insurance_company", "reconciliation_company");
        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));

        // 2.关联查询预计入账信息
        Set<String> commissionExpectedBizIdSet = commissionList.stream().map(Commission::getCommissionExpectedBizId).collect(Collectors.toSet());
        List<CommissionExpected> commissionExpectedList = commissionExpectedService.lambdaQuery()
                .select(CommissionExpected::getCommissionExpectedBizId,
                        CommissionExpected::getCommissionRatio,
                        CommissionExpected::getPaidAmount,
                        CommissionExpected::getPaidRatio,
                        CommissionExpected::getPendingRatio,
                        CommissionExpected::getStatus,
                        CommissionExpected::getReceivableNo,
                        CommissionExpected::getStatusDesc
                )
                .in(CommissionExpected::getCommissionExpectedBizId, commissionExpectedBizIdSet)
                .list();
        Map<String, CommissionExpected> commissionExpectedMap = commissionExpectedList.stream().collect(Collectors.toMap(CommissionExpected::getCommissionExpectedBizId, a -> a, (oldValue, newValue) -> newValue));

        // 3.关联查询投保人名称
        Map<String, PolicyFollow> policyFollowMap = policyFollowService.queryPolicyFollowMap(policyNoSet);

        // 4.关联查询转介人
        Map<String, PolicyBroker> policyBrokerMap = policyBrokerService.queryPolicyBrokerMap(policyNoSet);

        // 填充信息
        List<CommissionVO> commissionVOList = commissionList.stream().map(commission -> {
            CommissionVO commissionVO = CommissionVO.objToVo(commission);
            Policy policy = policyMap.get(commission.getPolicyNo());
            if (policy != null) {
                // 填充保费、产品名称、保险公司、对账公司
                commissionVO.setPremium(policy.getPaymentPremium());
                commissionVO.setProductName(policy.getProductName());
                commissionVO.setInsuranceCompany(policy.getInsuranceCompany());
                commissionVO.setReconciliationCompany(policy.getReconciliationCompany());
            }
            CommissionExpected commissionExpected = commissionExpectedMap.get(commission.getCommissionExpectedBizId());
            if (commissionExpected != null) {
                // 填充应收账款编号、预计入账状态、保单本期来佣率
                commissionVO.setReceivableNo(commissionExpected.getReceivableNo());
                commissionVO.setPaidRatio(commissionExpected.getPaidRatio());
                commissionVO.setPendingRatio(commissionExpected.getPendingRatio());
                commissionVO.setStatusDesc(commissionExpected.getStatusDesc());
                commissionVO.setCommissionExpectedStatus(commissionExpected.getStatus());
                commissionVO.setCommissionRatio(commissionExpected.getCommissionRatio());
            }
            PolicyFollow policyFollow = policyFollowMap.get(commission.getPolicyNo());
            if (policyFollow != null) {
                // 填充投保人名称
                commissionVO.setPolicyHolder(policyFollow.getPolicyHolder());
                commissionVO.setPolicyHolderEn(policyFollow.getPolicyHolderEn());
            }
            PolicyBroker policyBroker = policyBrokerMap.get(commission.getPolicyNo());
            if (policyBroker != null) {
                // 填充转介人名称
                commissionVO.setBroker(policyBroker.getBrokerName());
            }
            return commissionVO;
        }).collect(Collectors.toList());

        commissionVOPage.setRecords(commissionVOList);
        return commissionVOPage;
    }

    @Override
    public List<CommissionVO> getCommissionList(List<Commission> commissionList) {
        if (CollUtil.isEmpty(commissionList)) {
            return Collections.emptyList();
        }

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

        // 填充信息
        List<CommissionVO> commissionVOList = commissionList.stream().map(commission -> {
            CommissionVO commissionVO = CommissionVO.objToVo(commission);
            Policy policy = policyMap.get(commission.getPolicyNo());
            if (policy != null) {
                // 填充保费、产品名称、保险公司、对账公司
                commissionVO.setPremium(policy.getPaymentPremium());
                commissionVO.setProductName(policy.getProductName());
                commissionVO.setProductLaunchBizId(policy.getProductLaunchBizId());
                commissionVO.setInsuranceCompanyBizId(policy.getInsuranceCompanyBizId());
                commissionVO.setInsuranceCompany(policy.getInsuranceCompany());
                commissionVO.setReconciliationCompany(policy.getReconciliationCompany());
                commissionVO.setReconciliationCompanyCode(policy.getReconciliationCompanyCode());
                commissionVO.setReconciliationCompanyBizId(policy.getReconciliationCompanyBizId());
            }
            return commissionVO;
        }).collect(Collectors.toList());

        return commissionVOList;
    }

    @Override
    public void fillCommissionList(List<Commission> commissionList) {
        if (CollUtil.isEmpty(commissionList)) {
            return;
        }

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

        // 2.关联查询预计入账信息
        List<CommissionExpected> commissionExpectedList = commissionExpectedService.lambdaQuery()
                .in(CommissionExpected::getPolicyNo, policyNoSet)
                .select(CommissionExpected::getCommissionExpectedBizId,
                        CommissionExpected::getPolicyNo,
                        CommissionExpected::getCommissionBizType,
                        CommissionExpected::getReceivableNo,
                        CommissionExpected::getCommissionPeriod,
                        CommissionExpected::getTotalPeriod,
                        CommissionExpected::getCommissionName,
                        CommissionExpected::getCurrency,
                        CommissionExpected::getReconciliationCompanyBizId,
                        CommissionExpected::getStatus)
                .list();


        // 3.查询对账公司列表
        Set<String> reconciliationCompanySet = commissionList.stream()
                .map(Commission::getReconciliationCompany)
                .filter(Objects::nonNull).collect(Collectors.toSet());

        List<Map<String, Object>> reconciliationCompanyList = Collections.emptyList();
        if (!reconciliationCompanySet.isEmpty()) {
            reconciliationCompanyList = queryReconciliationCompanyListByFeign();
        }

        // 填充信息
        for (Commission commission : commissionList) {
            Policy policy = policyMap.get(commission.getPolicyNo());
            if (policy != null) {
                // 填充保费、产品名称、保险公司、对账公司
                commission.setPremium(String.valueOf(policy.getPaymentPremium()));
                commission.setPolicyCurrency(policy.getCurrency());
                commission.setProductLaunchBizId(policy.getProductLaunchBizId());
                commission.setInsuranceCompanyBizId(policy.getInsuranceCompanyBizId());
                commission.setReconciliationCompany(policy.getReconciliationCompany());
                commission.setReconciliationCompanyCode(policy.getReconciliationCompanyCode());
                commission.setReconciliationCompanyBizId(policy.getReconciliationCompanyBizId());
                // 本次入账比例
                commission.setCurrentCommissionRatio(
                        calculateCurrentCommissionRatio(
                                commission.getPremium(),
                                commission.getAmount(),
                                commission.getCurrency(),
                                commission.getExchangeRate(),
                                commission.getPolicyCurrency()
                        )
                );
            }
            // 匹配预计来佣记录
            CommissionExpected expected = findExpectedFromList(commission, commissionExpectedList);
            if (expected != null) {
                commission.setCommissionExpectedBizId(expected.getCommissionExpectedBizId());
                commission.setReceivableNo(expected.getReceivableNo());
                commission.setTotalPeriod(expected.getTotalPeriod());
            } else {
                commission.setRemark("未查询到预计来佣记录");
                commission.setStatus(CommissionStatusEnum.MATCH_FAILED.getItemValue());
            }
            // 设置对账公司信息
            if (!reconciliationCompanyList.isEmpty()) {
                setReconciliationCompanyInfo(commission, reconciliationCompanyList);
            }

            // 计算来佣金额（港币）
            commission.setHkdAmount(calculateHKDAmount(commission.getAmount(), commission.getCurrency()));
        }
    }

    private void setReconciliationCompanyInfo(Commission commission, List<Map<String, Object>> reconciliationCompanyList) {
        for (Map<String, Object> map : reconciliationCompanyList) {
            String name = (String) map.get("name");
            if (name.contains(commission.getReconciliationCompany())) {
                commission.setReconciliationCompany(Convert.toStr(map.get("name")));
                commission.setReconciliationCompanyBizId(Convert.toStr(map.get("reconciliationCompanyBizId")));
                commission.setReconciliationCompanyCode(Convert.toStr(map.get("code")));
                break;
            }
        }
    }

    public List<Map<String, Object>> queryReconciliationCompanyListByFeign() {
        ApiInsuranceReconciliationCompanyPageRequest reconciliationCompanyPageRequest = new ApiInsuranceReconciliationCompanyPageRequest();
        reconciliationCompanyPageRequest.setPageNo(1);
        reconciliationCompanyPageRequest.setPageSize(999);
        Result iPageResult = apiInsuranceReconciliationCompanyFeignClient.page(reconciliationCompanyPageRequest);

        // 解析响应获取对账公司编码
        if (iPageResult != null && iPageResult.getCode() == 200) {
            try {
                // Feign 返回的泛型会被反序列化为 LinkedHashMap，需要手动提取
                Object data = iPageResult.getData();
                if (data instanceof Map) {
                    Map<String, Object> dataMap = (Map<String, Object>) data;
                    Object recordsObj = dataMap.get("records");
                    if (recordsObj instanceof List) {
                        List<Map<String, Object>> records = (List<Map<String, Object>>) recordsObj;
                        return records;
                    }
                }
            } catch (Exception e) {
                log.error("解析对账公司响应失败: {}", e.getMessage(), e);
            }
        }
        return Collections.emptyList();
    }

    private CommissionExpected findExpectedFromList(Commission commission, List<CommissionExpected> commissionExpectedList) {
        log.info("commission: policyNo={}, commissionPeriod={}, commissionName={}, currency={}",
                commission.getPolicyNo(), commission.getCommissionPeriod(), commission.getCommissionName(), commission.getCurrency());

        for (CommissionExpected i : commissionExpectedList) {
            log.info("  expected: policyNo={}, commissionPeriod={}, commissionName={}, currency={}",
                    i.getPolicyNo(), i.getCommissionPeriod(), i.getCommissionName(), i.getCurrency());
            if ("R".equals(i.getCommissionBizType())) {
                if (Objects.equals(i.getPolicyNo(), commission.getPolicyNo())
                        && Objects.equals(i.getCommissionBizType(), commission.getCommissionBizType())
                        && Objects.equals(i.getCommissionPeriod(), commission.getCommissionPeriod())
                        && Objects.equals(i.getCommissionName(), commission.getCommissionName())
                ) {
                    return i;
                }
            } else {
                if (Objects.equals(i.getReconciliationCompanyBizId(), commission.getReconciliationCompanyBizId())
                        && Objects.equals(i.getCommissionName(), commission.getCommissionName())
                        && Objects.equals(i.getCommissionBizType(), commission.getCommissionBizType())
                ) {
                    return i;
                }
            }
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCommission(CommissionUpdateRequest commissionUpdateRequest) {
        String commissionBizId = commissionUpdateRequest.getCommissionBizId();

        // 查询旧数据
        Commission commission = this.getByCommissionBizId(commissionBizId);
        if (commission == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "未找到该来佣记录");
        }
        if (!Objects.equals(commission.getPolicyNo(), commissionUpdateRequest.getPolicyNo())) {
            throw new BusinessException("当前保单号不匹配");
        }
        String remark = commission.getRemark();
        Policy policy = null;
        if (StringUtils.isNotBlank(commissionUpdateRequest.getPolicyNo())) {
            policy = policyService.lambdaQuery().eq(Policy::getPolicyNo, commission.getPolicyNo()).one();
            if (policy == null) {
                throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "保单不存在:" + commission.getPolicyNo());
            }
            commission.setPolicyCurrency(policy.getCurrency());
        }

        BigDecimal requestAmount = commissionUpdateRequest.getAmount();
        // 重新关联预计来佣记录
        CommissionExpected commissionExpected = getCommissionExpectedBizId(commission);
        if (commissionExpected != null) {
            if ("R".equals(commissionUpdateRequest.getCommissionBizType())) {
                // 关联应收单，计算当前来佣比例
                BigDecimal currentCommissionRatio = this.calculateCurrentCommissionRatio(
                        commission.getPremium(),
                        requestAmount,
                        commissionUpdateRequest.getCurrency(),
                        commissionUpdateRequest.getExchangeRate(),
                        commission.getPolicyCurrency());
                commission.setCurrentCommissionRatio(currentCommissionRatio);
            }
        }
        // 计算来佣金额（港币）
        commission.setHkdAmount(calculateHKDAmount(requestAmount, commissionUpdateRequest.getCurrency()));

        commission.setManualRemark(commissionUpdateRequest.getManualRemark());
        commission.setRemark(remark);

        // 获取当前登录用户
        AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
        String loginUserId = currentLoginUser.getId().toString();

        // 保存修改记录
        saveUpdateCommissionRecord(commission, commissionUpdateRequest, currentLoginUser);

        // 更新属性
        BeanUtils.copyProperties(commissionUpdateRequest, commission, "commissionBizId");
        // 入账年月
        commission.setCommissionDate(DateUtil.parse(commissionUpdateRequest.getCommissionDate() + "-01"));
        if ("U".equals(commissionUpdateRequest.getCommissionBizType())) {
            commission.setPolicyNo(null);
        }
        commission.setUpdaterId(loginUserId);
        commission.setUpdateTime(new Date());
        // 执行更新操作（这个方法将在当前事务中执行）
        this.updateById(commission);

        // 2. 新事务，比对
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronization() {
                    @Override
                    public void afterCommit() {
                        try {
                            // 重新查询最新的数据，获取已提交的数据
                            commissionAsyncService.commissionCompare(commission);
                        } catch (Exception e) {
                            // 比对失败不影响主事务，记录日志即可
                            log.error("主事务提交后，比对操作执行失败，commissionBizId: {}",
                                    commissionUpdateRequest.getCommissionBizId(), e);
                        }
                    }
                }
        );
        return true;
    }

    private BigDecimal calculateHKDAmount(BigDecimal requestAmount, String currency) {
        if ("HKD".equalsIgnoreCase(currency)) {
            return requestAmount;
        }

        // 查询入账币种到港币的汇率
        BigDecimal exchangeRate = queryExchangeRateByFeign(currency, "HKD");

        return requestAmount.multiply(exchangeRate);
    }

    private CommissionExpected getCommissionExpectedBizId(Commission commission) {
        CommissionExpected commissionExpected = null;
        if ("R".equals(commission.getCommissionBizType())) {
            commissionExpected = commissionExpectedService.lambdaQuery()
                    .eq(CommissionExpected::getPolicyNo, commission.getPolicyNo())
                    .eq(CommissionExpected::getCommissionBizType, commission.getCommissionBizType())
                    .eq(CommissionExpected::getCommissionPeriod, commission.getCommissionPeriod())
                    .eq(CommissionExpected::getCommissionName, commission.getCommissionName())
                    .one();

        } else {
            // 从应收款管理查询到应收编号，如果没有应收编号，就需要同步到应收款管理
            commissionExpected = commissionExpectedService.lambdaQuery()
                    .eq(CommissionExpected::getCommissionBizType, commission.getCommissionBizType())
                    .eq(CommissionExpected::getReconciliationCompanyBizId, commission.getReconciliationCompanyBizId())
                    .eq(CommissionExpected::getCommissionName, commission.getCommissionName())
                    .one();
        }
        if (commissionExpected != null) {
            commission.setCommissionExpectedBizId(commissionExpected.getCommissionExpectedBizId());
            commission.setReceivableNo(commissionExpected.getReceivableNo());
        } else {
            commission.setStatus(CommissionStatusEnum.MATCH_FAILED.getItemValue());
        }
        return commissionExpected;
    }

    @Override
    public void validateCommissionUpdateRequest(CommissionUpdateRequest commissionUpdateRequest) {
        // 校验入参
        if (ObjectUtils.isEmpty(commissionUpdateRequest.getCommissionBizId())) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "来佣业务id不能为空");
        }
        if (ObjectUtils.isEmpty(commissionUpdateRequest.getCommissionName())) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "来佣名称不能为空");
        }
        if (ObjectUtils.isEmpty(commissionUpdateRequest.getCommissionType())) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "来佣类型不能为空");
        }
        if (ObjectUtils.isEmpty(commissionUpdateRequest.getAmount())) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "入账金额不能为空");
        }
        if (ObjectUtils.isEmpty(commissionUpdateRequest.getCurrency())) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "入账币种不能为空");
        }
//        if (ObjectUtils.isEmpty(commissionUpdateRequest.getExchangeRate())) {
//            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "结算汇率不能为空");
//        }
    }


    @Override
    public void saveUpdateCommissionRecord(Commission commission, CommissionUpdateRequest commissionUpdateRequest, AuthUserDto currentLoginUser) {
        // 保存修改记录
        List<CommissionEditRecord> commissionEditRecords = new ArrayList<>();

        if (!Objects.equals(commission.getPolicyNo(), commissionUpdateRequest.getPolicyNo())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("保单号", commission.getPolicyNo(), commissionUpdateRequest.getPolicyNo(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getReconciliationCompany(), commissionUpdateRequest.getReconciliationCompany())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("对账公司", commission.getReconciliationCompany(), commissionUpdateRequest.getReconciliationCompany(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getCommissionPeriod(), commissionUpdateRequest.getCommissionPeriod())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("佣金期数", commission.getCommissionPeriod(), commissionUpdateRequest.getCommissionPeriod(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getTotalPeriod(), commissionUpdateRequest.getTotalPeriod())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("总来佣期数", commission.getTotalPeriod(), commissionUpdateRequest.getTotalPeriod(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getCommissionName(), commissionUpdateRequest.getCommissionName())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("来佣名称", commission.getCommissionName(), commissionUpdateRequest.getCommissionName(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (commission.getAmount().compareTo(commissionUpdateRequest.getAmount()) != 0) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("来佣金额", commission.getAmount(), commissionUpdateRequest.getAmount(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getCurrency(), commissionUpdateRequest.getCurrency())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("币种", commission.getCurrency(), commissionUpdateRequest.getCurrency(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getExchangeRate(), commissionUpdateRequest.getExchangeRate())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("结算汇率", commission.getExchangeRate(), commissionUpdateRequest.getExchangeRate(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        String commissionDate = DateUtil.format(commission.getCommissionDate(), "yyyy-MM");
        String requestCommissionDate = commissionUpdateRequest.getCommissionDate();
        if (!Objects.equals(commissionDate, requestCommissionDate)) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("来佣年月", commissionDate, requestCommissionDate, commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getRemark(), commissionUpdateRequest.getRemark())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("备注", commission.getRemark(), commissionUpdateRequest.getRemark(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }

        if (CollectionUtils.isNotEmpty(commissionEditRecords)) {
            // 变更序号从1开始
            commissionEditRecords.forEach(commissionRecord -> commissionRecord.setSeq(commissionEditRecords.indexOf(commissionRecord) + 1));
            commissionEditRecordService.saveBatch(commissionEditRecords);
        }
    }

    private static CommissionEditRecord getCommissionEditRecord(String field, Object commissionPropertyValue, Object requestPropertyValue, String commissionBizId, AuthUserDto currentLoginUser) {
        CommissionEditRecord commissionRecord = new CommissionEditRecord();

        commissionRecord.setField(field);
        commissionRecord.setBeforeChange(commissionPropertyValue);
        commissionRecord.setAfterChange(requestPropertyValue);

        commissionRecord.setCommissionBizId(commissionBizId);
        commissionRecord.setUserBizId(currentLoginUser.getId().toString());
        commissionRecord.setUserName(currentLoginUser.getUsername());
        commissionRecord.setCreateTime(new Date());
        return commissionRecord;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean generateFortune(GenerateFortuneRequest generateFortuneRequest) {
        return auditTemplate.execute("应付款管理", 2, "生成可出账记录", ctx -> {
            List<String> commissionBizIdList = generateFortuneRequest.getCommissionBizIdList();
            List<Commission> commissions = this.lambdaQuery().in(Commission::getCommissionBizId, commissionBizIdList).list();

            // 校验来佣记录是否存在
            if (CollectionUtils.isEmpty(commissions)) {
                throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "未找到对应的来佣记录，请先创建来佣记录");
            }

            // 获取所有检核年月
            Set<String> reconciliationYearMonthSet = commissions.stream()
                    .map(Commission::getReconciliationYearMonth)
                    .collect(Collectors.toSet());

            // 校验检核年月是否一致
            if (reconciliationYearMonthSet.size() != 1) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "请选择相同的检核年月");
            }
            // 本次检核年月
            String reconciliationYearMonth = reconciliationYearMonthSet.iterator().next();

            for (Commission commission : commissions) {
                if ("U".equals(commission.getCommissionBizType())) {
                    throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "非关联保单应收单，不能点击生成可出账记录");
                }
                if (StringUtils.isBlank(commission.getPolicyNo())) {
                    throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "保单号不能为空");
                }
            }

            // 获取所有保单号
            Set<String> policyNoSet = commissions.stream()
                    .map(Commission::getPolicyNo)
                    .collect(Collectors.toSet());

            // 1.1 根据保单号查询的预计发佣记录
            List<ExpectedFortune> expectedFortuneList = iExpectedFortuneService.lambdaQuery()
                    .in(ExpectedFortune::getPolicyNo, policyNoSet)
                    .list();

            // 1.2 构建保单号+佣金期数的快速查找集合
            Set<String> commissionKeySet = commissions.stream()
                    .map(c -> c.getPolicyNo() + "_" + c.getCommissionPeriod())
                    .collect(Collectors.toSet());

            // 1.3 根据保单号+佣金期数筛选符合的预计发佣记录
            List<ExpectedFortune> filteredExpectedFortuneList1 = new ArrayList<>();
            for (ExpectedFortune expectedFortune : expectedFortuneList) {
                if (commissionKeySet.contains(expectedFortune.getPolicyNo() + "_" + expectedFortune.getFortunePeriod())) {
                    filteredExpectedFortuneList1.add(expectedFortune);
                }
            }
            if (CollectionUtils.isEmpty(filteredExpectedFortuneList1)) {
                throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "未找到保单对应的预计发佣记录，请先创建预计发佣记录");
            }

            // 2. 根据本次涉及的预计发佣记录，查询相关的 fortune 记录
            List<Fortune> fortuneList = fortuneService.lambdaQuery()
                    .in(Fortune::getExpectedFortuneBizId, filteredExpectedFortuneList1.stream().map(ExpectedFortune::getExpectedFortuneBizId).collect(Collectors.toList()))
                    .list();

            // 2.1 对 fortune 记录进行分类，已出账、已分期、手动加的记录不能删除，其他记录删除后根据预计发佣记录重新生成
            List<Fortune> deleteList = new ArrayList<>();
            List<Fortune> keepList = new ArrayList<>();
            for (Fortune fortune : fortuneList) {
                if (FortuneStatusEnum.SENT.getItemValue().equals(fortune.getStatus())
                        || !"系统生成".equals(fortune.getReconciliationOperator())
                        || 1 == fortune.getIsPart()) {
                    keepList.add(fortune);
                } else {
                    deleteList.add(fortune);
                }
            }

            // 2.1 物理删除
            if (CollectionUtils.isNotEmpty(deleteList)) {
                fortuneService.removeByIdsPhysical(deleteList.stream().map(Fortune::getId).collect(Collectors.toList()));
            }

            // 2.2 keepList 的记录，不重新生成
            Set<String> keepExpectedFortuneBizIdSet = keepList.stream().map(Fortune::getExpectedFortuneBizId).collect(Collectors.toSet());

            // 2.3 筛选出需要重新生成的记录
            List<ExpectedFortune> filteredExpectedFortuneList2 = new ArrayList<>();
            for (ExpectedFortune expectedFortune : filteredExpectedFortuneList1) {
                // 如果是 keep 记录，跳过
                if (keepExpectedFortuneBizIdSet.contains(expectedFortune.getExpectedFortuneBizId())) {
                    continue;
                }
                filteredExpectedFortuneList2.add(expectedFortune);
            }
            // 2.4 校验预计发佣记录是否有出账币种、默认结算汇率
            for (ExpectedFortune expectedFortune : filteredExpectedFortuneList2) {
                if (StringUtils.isBlank(expectedFortune.getRuleCurrency())) {
                    throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "预计发佣记录" + expectedFortune.getExpectedFortuneBizId() + "未配置保单币种");
                }
            }

            // 2.5 根据保单号、期数查询入账检核汇率
            Map<String, BigDecimal> exchangeRateMap = this.queryCommissionExchangeRateMap(commissions);

            // 审计：深拷贝预计发佣记录变更前快照
            Map<String, ExpectedFortune> beforeExpectedFortuneMap =
                    auditHelper.snapshot(filteredExpectedFortuneList2);

            // 3. 构建实际的初始发佣记录（使用入账检核汇率）
            List<Fortune> newFortuneList = buildNewFortunes(filteredExpectedFortuneList2, commissions, exchangeRateMap, reconciliationYearMonth);

            // 4. 保存发佣记录
            saveNewFortunes(newFortuneList);

            // 审计：fortune DELETE
            if (CollUtil.isNotEmpty(deleteList)) {
                Map<String, Fortune> deleteMap = deleteList.stream()
                        .collect(Collectors.toMap(Fortune::getFortuneBizId, Function.identity()));
                auditHelper.record("fortune", deleteMap, null, ctx);
            }

            // 审计：fortune INSERT
            Map<String, Fortune> insertMap = newFortuneList.stream()
                    .collect(Collectors.toMap(Fortune::getFortuneBizId, Function.identity()));
            auditHelper.record("fortune", null, insertMap, ctx);

            // 审计：expected_fortune UPDATE（重新查询 after 状态后 diff）
            List<String> efBizIds = new ArrayList<>(beforeExpectedFortuneMap.keySet());
            if (CollUtil.isNotEmpty(efBizIds)) {
                Map<String, ExpectedFortune> afterExpectedFortuneMap = iExpectedFortuneService.lambdaQuery()
                        .in(ExpectedFortune::getExpectedFortuneBizId, efBizIds)
                        .list().stream()
                        .collect(Collectors.toMap(ExpectedFortune::getExpectedFortuneBizId, Function.identity()));
                auditHelper.record("expected_fortune", beforeExpectedFortuneMap, afterExpectedFortuneMap, ctx);
            }

            return true;
        });
    }

    private Map<String, BigDecimal> queryCommissionExchangeRateMap(List<Commission> commissions) {
        if (CollectionUtils.isEmpty(commissions)) {
            return new HashMap<>();
        }

        // 1. 按入账日期降序排序
        List<Commission> commissionExchangeRateList = commissions.stream()
                .sorted(Comparator.comparing(Commission::getCommissionDate).reversed())
                .collect(Collectors.toList());

        // 2. 按 policyNo + commissionPeriod 分组，取每组的第一条（最新的）
        Map<String, BigDecimal> exchangeRateMap = commissionExchangeRateList.stream()
                .collect(Collectors.groupingBy(
                        commission -> buildPolicyPeriodKey(commission.getPolicyNo(), commission.getCommissionPeriod())
                ))
                .entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue().get(0).getExchangeRate()
                ));

        // 3. 确保所有 policyNo + commissionPeriod 组合都在 Map 中，没有记录的设为 null
        Map<String, BigDecimal> result = new HashMap<>();
        for (Commission commission : commissions) {
            String key = buildPolicyPeriodKey(commission.getPolicyNo(), commission.getCommissionPeriod());
            result.put(key, exchangeRateMap.getOrDefault(key, null));
        }

        return result;
    }

    /**
     * 保存新的发佣记录
     */
    private void saveNewFortunes(List<Fortune> newFortuneList) {
        if (CollectionUtils.isEmpty(newFortuneList)) {
            throw new BusinessException(ResultCode.FAIL.getCode(), "没有可保存的发佣记录");
        }

        boolean saveSuccess = fortuneService.saveBatch(newFortuneList);
        if (!saveSuccess) {
            throw new BusinessException(ResultCode.FAIL.getCode(), "保存发佣记录失败");
        }
    }

    /**
     * 构建新的发佣记录
     */
    private List<Fortune> buildNewFortunes(List<ExpectedFortune> expectedFortuneList,
                                           List<Commission> commissionList,
                                           Map<String, BigDecimal> exchangeRateMap,
                                           String reconciliationYearMonth) {
        if (CollectionUtils.isEmpty(expectedFortuneList)) {
            return new ArrayList<>();
        }
        // 构建来佣记录映射，用于快速查找
        Map<String, Commission> commissionByPolicyPeriod = commissionList.stream()
                .collect(Collectors.toMap(
                        commission -> buildPolicyPeriodKey(commission.getPolicyNo(), commission.getCommissionPeriod()),
                        Function.identity(),
                        (oldValue, newValue) -> newValue  // 遇到重复时使用新值
                ));

        // 当前登录用户
        AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
        String loginUserId = currentLoginUser.getId().toString();

        Date now = new Date();

        // 创建新的发佣记录
        List<Fortune> newFortuneList = new ArrayList<>();
        // 更新预计发佣记录的港币金额
        List<ExpectedFortune> updatedExpectedFortuneList = new ArrayList<>();
        // 更新预计发佣记录的状态
        List<Long> updatedExpectedFortuneIdList = new ArrayList<>();
        for (ExpectedFortune expectedFortune : expectedFortuneList) {

            updatedExpectedFortuneIdList.add(expectedFortune.getId());

            Fortune fortune = new Fortune();
            BeanUtils.copyProperties(expectedFortune, fortune);

            fortune.setFortuneBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_FORTUNE.getCode()));
            fortune.setId(null);
            fortune.setFortuneBizType("R");
            fortune.setReconciliationYearMonth(reconciliationYearMonth);

            // 优先使用入账检核汇率，如果没有则使用默认汇率
            String key = buildPolicyPeriodKey(expectedFortune.getPolicyNo(), expectedFortune.getFortunePeriod());
            BigDecimal exchangeRate = exchangeRateMap.get(key);
            if (exchangeRate != null) {
                // 入账检核汇率 — 仅审计追溯，始终写入
                fortune.setExchangeRate(exchangeRate);

                // 判断 expectedFortune.originalCurrency 、入账币种-fortune.currency 是否都等于 HKD
                Commission matchedCommission = commissionByPolicyPeriod.get(key);
                boolean isAllHkd = matchedCommission != null
                        && "HKD".equalsIgnoreCase(expectedFortune.getOriginalCurrency())
                        && "HKD".equalsIgnoreCase(matchedCommission.getCurrency());

                if (isAllHkd) {
                    // 原币种 = HKD 时，exchangeRate = 保单币种 → 港币，可安全使用
                    fortune.setOriginalToHkdRate(exchangeRate);
                    BigDecimal hkdAmount = fortune.getRuleAmount().multiply(exchangeRate);
                    fortune.setHkdAmount(hkdAmount);
                    fortune.setCurrentPaymentAmount(fortune.getRuleAmount());
                    fortune.setCurrentPaymentHkdAmount(hkdAmount);
                    BigDecimal payoutAmount = hkdAmount.multiply(expectedFortune.getHkdToPayoutRate());
                    fortune.setPayoutAmount(payoutAmount);

                    ExpectedFortune update = new ExpectedFortune();
                    update.setId(expectedFortune.getId());
                    update.setDefaultExchangeRate(exchangeRate);
                    update.setOriginalToHkdRate(exchangeRate);
                    update.setHkdAmount(hkdAmount);
                    update.setUnpaidAmount(hkdAmount);
                    update.setUnpaidRuleAmountHkd(hkdAmount);
                    update.setPayoutAmount(payoutAmount);
                    updatedExpectedFortuneList.add(update);
                } else {
                    // 入账币种 ≠ HKD，无法推导保单币种 → 港币，用 ExpectedFortune 已有默认值
                    fortune.setExchangeRate(expectedFortune.getDefaultExchangeRate());
                    fortune.setCurrentPaymentAmount(expectedFortune.getOriginalAmount());
                    fortune.setCurrentPaymentHkdAmount(expectedFortune.getHkdAmount());
                }
            } else {
                fortune.setExchangeRate(expectedFortune.getDefaultExchangeRate());
                fortune.setCurrentPaymentAmount(expectedFortune.getOriginalAmount());
                fortune.setCurrentPaymentHkdAmount(expectedFortune.getHkdAmount());
            }

            fortune.setExpectedFortuneBizId(expectedFortune.getExpectedFortuneBizId());
            fortune.setStatus(FortuneStatusEnum.CAN_SEND.getItemValue());
            fortune.setIsPart(0);

            // 关联来佣业务ID
            Commission matchedCommission = commissionByPolicyPeriod.get(key);
            if (matchedCommission != null) {
                fortune.setCommissionBizId(matchedCommission.getCommissionBizId());
                fortune.setCommissionExpectedBizId(matchedCommission.getCommissionExpectedBizId());
            } else {
                fortune.setStatus(FortuneStatusEnum.MATCH_FAIL.getItemValue());
                fortune.setRemark("未找到当前预计发佣对应的来佣");
            }

            fortune.setCreateTime(now);
            fortune.setUpdateTime(now);
            fortune.setReconciliationOperator("系统生成");
            fortune.setCreatorId(loginUserId);
            fortune.setUpdaterId(loginUserId);

            newFortuneList.add(fortune);
        }

        // 更新预计发佣记录
        if (CollectionUtils.isNotEmpty(updatedExpectedFortuneList)) {
            boolean updateSuccess = iExpectedFortuneService.updateBatchById(updatedExpectedFortuneList);
            if (!updateSuccess) {
                throw new BusinessException(ResultCode.FAIL.getCode(), "更新预计发佣记录港币金额失败");
            }
        }

        // 更新预计发佣记录的状态
        if (CollectionUtils.isNotEmpty(updatedExpectedFortuneIdList)) {
            boolean updateSuccess = iExpectedFortuneService.lambdaUpdate()
                    .set(ExpectedFortune::getStatus, FortuneStatusEnum.CAN_SEND.getItemValue())
                    .in(ExpectedFortune::getId, updatedExpectedFortuneIdList)
                    .update();

            if (!updateSuccess) {
                throw new BusinessException(ResultCode.FAIL.getCode(), "更新预计发佣记录状态失败");
            }
        }

        return newFortuneList;
    }

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

    /**
     * 构建保单号+期数的唯一键
     */
    @Override
    public String buildPolicyPeriodKey(String policyNo, Object period) {
        return (policyNo == null ? "" : policyNo) + "|" + (period == null ? "" : period.toString());
    }

    @Override
    public Commission getByCommissionBizId(String commissionBizId) {
        return this.getOne(new QueryWrapper<Commission>().eq("commission_biz_id", commissionBizId));
    }

    public BigDecimal calculateCurrentCommissionRatio(String premium, BigDecimal amount, String currentCurrency, BigDecimal exchangeRate, String policyCurrency) {
        if (ObjectUtils.isEmpty(premium)) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "保单保费不能为空");
        }
        if (ObjectUtils.isEmpty(amount)) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "当前入账金额不能为空");
        }
        if (ObjectUtils.isEmpty(exchangeRate)) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "当前结算汇率不能为空");
        }

        // 如果当前入账币种等于保单币种，直接计算来佣比例
        if (StringUtils.equalsIgnoreCase(currentCurrency, policyCurrency)) {
            return amount.divide(new BigDecimal(premium), 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal(100));
        } else {
            // 将入账金额从入账币种转换为保单币种
            BigDecimal amountInPolicyCurrency = amount.divide(exchangeRate, 4, RoundingMode.HALF_UP);
            // 计算佣金比例
            return amountInPolicyCurrency.divide(new BigDecimal(premium), 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100"));
        }

    }

    @Override
    public void saveCompareRecord(Commission commission, CommissionExpected expected, AuthUserDto currentLoginUser) {
        CommissionCompareRecord commissionCompareRecord = new CommissionCompareRecord();
        commissionCompareRecord.setCommissionExpectedBizId(expected.getCommissionExpectedBizId());
        commissionCompareRecord.setCommissionBizId(commission.getCommissionBizId());
        commissionCompareRecord.setCommissionPeriod(commission.getCommissionPeriod());
        commissionCompareRecord.setTotalPeriod(commission.getTotalPeriod());
        commissionCompareRecord.setAmount(commission.getAmount());
        commissionCompareRecord.setCurrentCommissionRatio(commission.getCurrentCommissionRatio());
        commissionCompareRecord.setCurrency(commission.getCurrency());
        commissionCompareRecord.setExchangeRate(Convert.toStr(commission.getExchangeRate()));
        commissionCompareRecord.setStatus(commission.getStatus());
        commissionCompareRecord.setRemark(commission.getRemark());
        commissionCompareRecord.setCreateTime(commission.getCreateTime());
        commissionCompareRecordService.save(commissionCompareRecord);
    }

    @Override
    public CommissionCompareRecord getNewCompareRecord(Commission commission, CommissionExpected expected, AuthUserDto currentLoginUser) {
        CommissionCompareRecord commissionCompareRecord = new CommissionCompareRecord();
        commissionCompareRecord.setCommissionExpectedBizId(expected.getCommissionExpectedBizId());
        commissionCompareRecord.setCommissionBizId(commission.getCommissionBizId());
        commissionCompareRecord.setCommissionPeriod(commission.getCommissionPeriod());
        commissionCompareRecord.setTotalPeriod(commission.getTotalPeriod());
        commissionCompareRecord.setAmount(commission.getAmount());
        commissionCompareRecord.setCurrency(commission.getCurrency());
        commissionCompareRecord.setExchangeRate(Convert.toStr(commission.getExchangeRate()));
        commissionCompareRecord.setStatus(commission.getStatus());
        commissionCompareRecord.setRemark(commission.getRemark());
        commissionCompareRecord.setOperatorName(currentLoginUser.getUsername());
        commissionCompareRecord.setCreateTime(commission.getCreateTime());
        return commissionCompareRecord;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Commission> addCommissionBatch(List<CommissionAddRequest> customerAddRequestList) {
        if (CollectionUtils.isEmpty(customerAddRequestList)) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账数据不能为空");
        }

        return auditTemplate.execute("来佣管理", 1, "导入入账记录", ctx -> {
            validateAddCommissionBatch(customerAddRequestList);

            Set<String> policyNoSet = customerAddRequestList.stream()
                    .map(CommissionAddRequest::getPolicyNo)
                    .filter(StringUtils::isNotBlank).collect(Collectors.toSet());

            // 关联查询保单信息、预计入账信息
            Map<String, Policy> policyMap = new HashMap<>();
            List<CommissionExpected> commissionExpectedList = new ArrayList<>();
            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<Commission> commissionList = new ArrayList<>();
            for (CommissionAddRequest request : customerAddRequestList) {
                Commission commission = new Commission();
                BeanUtils.copyProperties(request, commission);
                commission.setManualRemark(request.getManualRemark());

                // 入账年月
                commission.setCommissionDate(DateUtil.parse(request.getCommissionDate() + "-01"));
                // 计算来佣金额（港币）
                commission.setHkdAmount(calculateHKDAmount(request.getAmount(), request.getCurrency()));
                // 入账业务id
                commission.setCommissionBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_COMMISSION.getCode()));
                // 关联业务id
                if ("R".equals(request.getCommissionBizType())) {
                    Policy policy = policyMap.get(request.getPolicyNo());
                    if (policy != null) {
                        commission.setReconciliationCompany(policy.getReconciliationCompany());
                        commission.setReconciliationCompanyBizId(policy.getReconciliationCompanyBizId());
                        commission.setProductLaunchBizId(policy.getProductLaunchBizId());
                        commission.setInsuranceCompanyBizId(policy.getInsuranceCompanyBizId());
                        commission.setPremium(Convert.toStr(policy.getPaymentPremium()));
                        commission.setPolicyCurrency(policy.getCurrency());
                        // 本次入账比例
                        commission.setCurrentCommissionRatio(calculateCurrentCommissionRatio(
                                commission.getPremium(),
                                commission.getAmount(),
                                commission.getCurrency(),
                                commission.getExchangeRate(),
                                commission.getPolicyCurrency())
                        );
                    } else {
//                    throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "保单不存在, policyNo: " + request.getPolicyNo());
                        throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "保单号不存在");
                    }
                } else {
                    commission.setPolicyNo(null);
                }
                // 关联预计来佣信息
                CommissionExpected expected = getCommissionExpectedBizIdBatch(request, policyNoSet, commission);
                if (expected != null) {
                    commission.setCommissionExpectedBizId(expected.getCommissionExpectedBizId());
                    commission.setReceivableNo(expected.getReceivableNo());
                    commission.setTotalPeriod(expected.getTotalPeriod());
                }

                commissionList.add(commission);
            }
            // 1. 先保存主数据
            saveOrUpdateBatch(commissionList);

            // 审计：commission INSERT
            if (CollUtil.isNotEmpty(commissionList)) {
                Map<String, Commission> insertMap = commissionList.stream()
                        .collect(Collectors.toMap(Commission::getCommissionBizId, Function.identity()));
                auditHelper.record("commission", null, insertMap, ctx);
            }

            // 2. 事务提交后执行比对
            TransactionSynchronizationManager.registerSynchronization(
                    new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            try {
                                commissionAsyncService.commissionCompareBatch(commissionList, ctx.getRequestId());
                            } catch (Exception e) {
                                log.error("比对更新失败", e);
                            }
                        }
                    }
            );

            return commissionList;
        });
    }

    private CommissionExpected getCommissionExpectedBizIdBatch(CommissionAddRequest request, Set<String> policyNoSet, Commission commission) {
        CommissionExpected expected = null;
        if ("R".equals(request.getCommissionBizType())) {
            // 查询预计入账信息
            List<CommissionExpected> commissionExpectedList = new ArrayList<>();
            if (CollUtil.isNotEmpty(policyNoSet)) {
                commissionExpectedList = commissionExpectedService.lambdaQuery().in(CommissionExpected::getPolicyNo, policyNoSet).list();
            }
            if (CollectionUtils.isNotEmpty(commissionExpectedList)) {
                // 根据保单号、期数、入账名称，查询预计来佣记录
                expected = commissionExpectedList.stream()
                        .filter(item -> item.getPolicyNo().equals(request.getPolicyNo())
                                && item.getCommissionBizType().equals(request.getCommissionBizType())
                                && item.getCommissionPeriod().equals(request.getCommissionPeriod())
                                && item.getCommissionName().equals(request.getCommissionName()))
                        .findFirst()
                        .orElse(null);
            }
        } else {
            // 查询预计来佣信息
            List<CommissionExpected> commissionExpectedList = commissionExpectedService.lambdaQuery()
                    .eq(CommissionExpected::getReconciliationCompanyBizId, request.getReconciliationCompanyBizId())
                    .eq(CommissionExpected::getCommissionBizType, request.getCommissionBizType())
                    .eq(CommissionExpected::getCommissionName, request.getCommissionName())
                    .list();

            if (CollectionUtils.isNotEmpty(commissionExpectedList)) {
                expected = commissionExpectedList.stream()
                        .filter(item -> item.getReconciliationCompanyBizId().equals(request.getReconciliationCompanyBizId())
                                && item.getCommissionName().equals(request.getCommissionName())
                                && item.getCommissionBizType().equals(request.getCommissionBizType()))
                        .findFirst()
                        .orElse(null);
            }
        }
        if (expected != null) {
            commission.setCommissionExpectedBizId(expected.getCommissionExpectedBizId());
            commission.setReceivableNo(expected.getReceivableNo());
            commission.setTotalPeriod(expected.getTotalPeriod());
        } else {
            commission.setRemark("未查询到预计来佣记录");
            commission.setStatus(CommissionStatusEnum.MATCH_FAILED.getItemValue());
        }
        return expected;
    }

    private void validateAddCommissionBatch(List<CommissionAddRequest> customerAddRequestList) {
        for (CommissionAddRequest request : customerAddRequestList) {
            // 校验数据
            if (StringUtils.isBlank(request.getCommissionType())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账项目类型不能为空");
            }
            // 检核年月不能为空
            if (StringUtils.isBlank(request.getReconciliationYearMonth())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "检核年月不能为空");
            }
            // commissionType 只能是数字
            if (!StringUtils.isNumeric(request.getCommissionType())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账项目类型只能是字典值");
            }
            // commissionName 不能为空
            if (StringUtils.isBlank(request.getCommissionName())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账项目名称不能为空");
            }
            if (ObjectUtils.isEmpty(request.getAmount())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账金额不能为空");
            }
//            if (ObjectUtils.isEmpty(request.getExchangeRate())) {
//                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "结算汇率不能为空");
//            }
            if ("R".equals(request.getCommissionBizType())) {
                // 校验保单号是否存在
                if (ObjectUtils.isEmpty(request.getExchangeRate())) {
                    throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "关联保单号记录，结算汇率不能为空");
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addToExpected(AddToExpectedCommissionRequest addToExpectedCommissionRequest) {
        if (StringUtils.isBlank(addToExpectedCommissionRequest.getCommissionBizId())) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "来佣业务id不能为空");
        }
        Commission commission = this.getByCommissionBizId(addToExpectedCommissionRequest.getCommissionBizId());
        if (commission == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "来佣记录不存在");
        }
        if (StringUtils.isNotBlank(commission.getCommissionExpectedBizId())) {
            CommissionExpected commissionExpected = commissionExpectedService.queryOne(commission.getCommissionExpectedBizId());
            if (commissionExpected != null) {
                throw new BusinessException("已经同步过了，无需再次同步");
            }
        }
        // 获取当前登录用户
        AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
        String loginUserId = currentLoginUser.getId().toString();

        CommissionExpected expected = new CommissionExpected();
        BeanUtils.copyProperties(commission, expected, "id", "remark");
        expected.setCommissionExpectedBizId(RandomStringGenerator.generateBizId16("commission_expected"));
        expected.setPremium(commission.getPremium() != null ? new BigDecimal(commission.getPremium()) : BigDecimal.ZERO);

        // 生成应收单编号
        expected.setReceivableNo(receivableService.generateReceivableNo(
                commission.getCommissionBizType(),
                commission.getReconciliationCompanyCode(),
                commission.getReconciliationCompany()));
        // 设置预计入账金额、已来佣金额、待入账金额
        expected.setCommissionRatio(commission.getCurrentCommissionRatio());
        expected.setExpectedAmount(commission.getHkdAmount());
        expected.setPaidAmount(commission.getHkdAmount());
        expected.setPaidRatio(commission.getCurrentCommissionRatio());
        expected.setDefaultExchangeRate(commission.getExchangeRate());
        expected.setCommissionDate(commission.getCommissionDate());
        expected.setStatus(CommissionExpectedStatusEnum.COMPARED.getItemValue());
        expected.setStatusDesc("比对成功，通过手动同步预计来佣"); // 设置状态描述为比对成功
        expected.setRemark(expected.getStatusDesc());

        expected.setCreatorId(loginUserId);
        expected.setCreateTime(new Date());
        expected.setUpdaterId(loginUserId);
        expected.setUpdateTime(new Date());
        // 保存预计来佣记录
        commissionExpectedService.save(expected);

        // 更新来佣记录
        this.lambdaUpdate()
                .set(Commission::getCommissionExpectedBizId, expected.getCommissionExpectedBizId())
                .set(Commission::getReceivableNo, expected.getReceivableNo())
                .set(Commission::getStatus, CommissionStatusEnum.COMPARE_SUCCESS.getItemValue())
                .set(Commission::getStatusDesc, expected.getStatusDesc())
                .set(Commission::getRemark, expected.getStatusDesc())
                .eq(Commission::getId, commission.getId())
                .update();

        return true;
    }

    private String queryReconciliationCompany(String insuranceCompanyBizId) {
        if (ObjectUtils.isNotEmpty(insuranceCompanyBizId)) {

        }
        return null;
    }

    @Override
    public int updateStatusBatchById(List<Commission> existingCommissions) {
        return this.baseMapper.updateStatusBatchById(existingCommissions);
    }

    @Override
    public boolean deleteByIdPhysical(Long id) {
        return baseMapper.deleteByIdPhysical(id) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteCommission(Commission oldCommission) {
        // 操作数据库
        boolean result = this.deleteByIdPhysical(oldCommission.getId());
        if (!result) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR.getCode(), ErrorCode.OPERATION_ERROR.getMessage());
        }
        String commissionBizId = oldCommission.getCommissionBizId();

        // 删除关联来佣比对记录
        commissionCompareRecordService.removeByCommissionId(commissionBizId);

        // 更新预计来佣记录
        String commissionExpectedBizId = oldCommission.getCommissionExpectedBizId();
        if (StringUtils.isNotBlank(commissionExpectedBizId)) {
            // 查询该预计来佣下的所有剩余来佣记录
            List<Commission> remainingCommissions = this.lambdaQuery()
                    .eq(Commission::getCommissionExpectedBizId, commissionExpectedBizId)
                    .list();

            // 计算新的 paidAmount 和 paidRatio
            BigDecimal paidRatio = BigDecimal.ZERO;
            BigDecimal paidAmount = BigDecimal.ZERO;
            for (Commission item : remainingCommissions) {
                paidRatio = paidRatio.add(item.getCurrentCommissionRatio());
                paidAmount = paidAmount.add(item.getHkdAmount());
            }

            // 获取预计来佣记录
            CommissionExpected commissionExpected = commissionExpectedService.lambdaQuery()
                    .eq(CommissionExpected::getCommissionExpectedBizId, commissionExpectedBizId)
                    .one();

            if (commissionExpected != null) {
                // 根据 paidRatio 与 commissionRatio 比较确定状态
                String newStatus;
                if (CollectionUtils.isEmpty(remainingCommissions)) {
                    // 没有剩余来佣时，恢复到初始状态
                    newStatus = CommissionExpectedStatusEnum.PENDING.getItemValue();
                } else if (paidRatio.compareTo(commissionExpected.getCommissionRatio()) == 0) {
                    newStatus = CommissionExpectedStatusEnum.COMPARED.getItemValue();
                } else {
                    newStatus = CommissionExpectedStatusEnum.PARTIAL.getItemValue();
                }

                // 更新预计来佣记录
                commissionExpectedService.lambdaUpdate()
                        .set(CommissionExpected::getPaidAmount, paidAmount.setScale(4, RoundingMode.HALF_UP))
                        .set(CommissionExpected::getPaidRatio, paidRatio)
                        .set(CommissionExpected::getStatus, newStatus)
                        .eq(CommissionExpected::getCommissionExpectedBizId, commissionExpectedBizId)
                        .update();
            }
        }

        return true;
    }

    @Override
    public BigDecimal queryCommissionExchangeRate(String policyNo, Integer commissionPeriod) {
        // 查询当前期数入账记录的结算汇率
        Commission commissionRecord = this.getOne(
                new QueryWrapper<Commission>()
                        .eq("policy_no", policyNo)
                        .eq("commission_period", commissionPeriod)
                        .orderByDesc("commission_date")
                        .last("LIMIT 1")
        );
        if (ObjectUtils.isEmpty(commissionRecord)) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "保单号为" + policyNo + "的佣金期数为" + commissionPeriod + "的入账记录不存在");
        }
        return commissionRecord.getExchangeRate();
    }

    @Override
    public Long queryCount(String commissionExpectedBizId) {
        return this.baseMapper.selectCount(new LambdaQueryWrapper<Commission>()
                .eq(Commission::getCommissionExpectedBizId, commissionExpectedBizId)
                .eq(Commission::getIsDeleted, 0)
        );
    }


    /**
     * 查询列表
     *
     * @param dto
     * @return
     */
    @Override
    public List<Commission> queryList(CommissionDto dto) {
        List<Commission> list = baseMapper.selectList(new LambdaQueryWrapper<Commission>()
                .in(CollectionUtils.isNotEmpty(dto.getCommissionBizIdList()), Commission::getCommissionBizId, dto.getCommissionBizIdList())
        );
        return list;
    }

    /**
     * 查询来佣保单转介人关系信息
     *
     * @param dto
     * @return
     */
    @Override
    public List<CommissionBindPolicyBrokerDto> queryCommissionBindPolicyBrokerList(CommissionDto dto) {
        return baseMapper.queryCommissionBindPolicyBrokerList(dto);
    }

    @Override
    public CommissionStatisticsVO getCommissionStatistics(List<Long> commissionIds) {
        if (CollectionUtils.isEmpty(commissionIds)) {
            CommissionStatisticsVO commissionStatisticsVO = new CommissionStatisticsVO();
            commissionStatisticsVO.setTotalPaidAmount(BigDecimal.ZERO);
            commissionStatisticsVO.setExpectePaidAmount(BigDecimal.ZERO);
            commissionStatisticsVO.setPendingPaidAmount(BigDecimal.ZERO);
            commissionStatisticsVO.setDifferenceAmount(BigDecimal.ZERO);
            commissionStatisticsVO.setTotalPolicyCount(0);
            commissionStatisticsVO.setTotalPremium(BigDecimal.ZERO);
            commissionStatisticsVO.setReconciliationCompanyCount(0);
            commissionStatisticsVO.setTotalCompareCommissionCount(0);
            commissionStatisticsVO.setSuccessCompareCommissionCount(0);
            commissionStatisticsVO.setFailedCompareCommissionCount(0);
            return commissionStatisticsVO;
        }
        // 自定义统计数据
        CommissionStatisticsVO commissionStatistics = baseMapper.getCommissionStatistics(commissionIds);

        // 确保所有字段都有值，避免null值
        if (commissionStatistics.getTotalPaidAmount() == null) {
            commissionStatistics.setTotalPaidAmount(BigDecimal.ZERO);
        }
        if (commissionStatistics.getExpectePaidAmount() == null) {
            commissionStatistics.setExpectePaidAmount(BigDecimal.ZERO);
        }
        if (commissionStatistics.getPendingPaidAmount() == null) {
            commissionStatistics.setPendingPaidAmount(BigDecimal.ZERO);
        }
        if (commissionStatistics.getDifferenceAmount() == null) {
            commissionStatistics.setDifferenceAmount(BigDecimal.ZERO);
        }
        if (commissionStatistics.getTotalPremium() == null) {
            commissionStatistics.setTotalPremium(BigDecimal.ZERO);
        }

        // 计算差额（估-实）
        BigDecimal differenceAmount = commissionStatistics.getExpectePaidAmount()
                .subtract(commissionStatistics.getTotalPaidAmount());
        commissionStatistics.setDifferenceAmount(differenceAmount);

        // 如果待入账金额为0，重新计算（预计入账金额 - 实际入账金额）
        if (commissionStatistics.getPendingPaidAmount().compareTo(BigDecimal.ZERO) == 0) {
            commissionStatistics.setPendingPaidAmount(differenceAmount);
        }

        return commissionStatistics;
    }
}




