package com.seer.teach.pay.admin.withdrawal.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.seer.teach.common.constants.CommonConstant;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.enums.pay.WithdrawalApplyStatusEnum;
import com.seer.teach.common.exception.CommonException;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.common.utils.MoneyUtil;
import com.seer.teach.common.utils.OrderIdGenerator;
import com.seer.teach.pay.admin.withdrawal.controller.request.PayWithdrawalApplyReq;
import com.seer.teach.pay.admin.withdrawal.controller.request.PayWithdrawalAuditReq;
import com.seer.teach.pay.admin.withdrawal.service.IAdminPayMerchantWithdrawalApplyService;
import com.seer.teach.pay.entity.PayMerchantAccountEntity;
import com.seer.teach.pay.entity.PayMerchantRevenueDetailEntity;
import com.seer.teach.pay.entity.PayMerchantRevenueUsageEntity;
import com.seer.teach.pay.entity.PayMerchantWithdrawalApplyEntity;
import com.seer.teach.pay.entity.PayMerchantWithdrawalOperationLogEntity;
import com.seer.teach.pay.entity.PayOfflineTransferRecordEntity;
import com.seer.teach.pay.entity.PayWithdrawalConfigEntity;
import com.seer.teach.pay.enums.MerchantRevenueUsageStatusEnum;
import com.seer.teach.pay.enums.MerchantRevenueWithdrawStatusEnum;
import com.seer.teach.pay.enums.MerchantWithdrawTransferStatusEnum;
import com.seer.teach.pay.service.IPayMerchantAccountService;
import com.seer.teach.pay.service.IPayMerchantRevenueDetailService;
import com.seer.teach.pay.service.IPayMerchantRevenueUsageService;
import com.seer.teach.pay.service.IPayMerchantWithdrawalApplyService;
import com.seer.teach.pay.service.IPayMerchantWithdrawalOperationLogService;
import com.seer.teach.pay.service.IPayOfflineTransferRecordService;
import com.seer.teach.pay.service.IPayWithdrawalConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <p>
 * 支付模块-提现申请核心服务实现类
 * </p>
 *
 * @author ZS
 * @since 2025-10-16
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class AdminPayMerchantWithdrawalApplyServiceImpl implements IAdminPayMerchantWithdrawalApplyService {

    private final IPayMerchantWithdrawalApplyService payMerchantWithdrawalApplyService;

    private final IPayMerchantAccountService payMerchantAccountService;

    private final IPayWithdrawalConfigService payWithdrawalConfigService;

    private final IPayMerchantRevenueDetailService payMerchantRevenueDetailService;

    private final IPayMerchantRevenueUsageService payMerchantRevenueUsageService;

    private final IPayMerchantWithdrawalOperationLogService payWithdrawalOperationLogService;

    private final IPayOfflineTransferRecordService payOfflineTransferRecordService;

    @Transactional(rollbackFor = Exception.class, timeout = 1200)
    @Override
    public String applyWithdrawal(Long userId, PayWithdrawalApplyReq payWithdrawalApply) {
        log.info("用户[{}]申请提现开始", userId);

        // 1. 验证账户信息
        PayMerchantAccountEntity account = validateAccount(userId);

        // 2. 验证余额和配置以及是否有审核中的提现申请
        BigDecimal applyAmount = MoneyUtil.yuanToCentWithBigDecimal(payWithdrawalApply.getApplyAmount());
        PayWithdrawalConfigEntity config = validateBalanceAndConfig(account, applyAmount, userId);

        // 3. 计算费用信息
        FeeCalculationResult feeResult = calculateFees(applyAmount, config, account.getTotalWithdrawnAmount());

        // 4. 生成提现申请单号
        String withdrawalNo = OrderIdGenerator.generateOrderId(OrderIdGenerator.MALL_MERCHANT_ORDER_PREFIX);
        log.info("提现申请单号:{}", withdrawalNo);

        // 5. 处理收益明细拆分
        RevenueSplitResult splitResult = processRevenueSplit(userId, applyAmount, withdrawalNo);

        // 6. 检查剩余金额
        validateRemainingAmount(splitResult.getRemainingAmount());

        // 7. 执行批量保存和更新操作
        executeBatchOperations(splitResult);

        // 8. 创建并保存提现申请记录
        PayMerchantWithdrawalApplyEntity apply = createWithdrawalApply(withdrawalNo, userId, account, applyAmount, feeResult, splitResult);
        payMerchantWithdrawalApplyService.save(apply);

        // 9. 更新账户余额（减少可用余额，增加冻结余额，增加提现总额）
        payMerchantAccountService.freezeBalanceForWithdrawal(account.getUserId(), applyAmount);

        // 10. 记录提现申请操作日志
        recordApplyOperation(withdrawalNo, userId, applyAmount);

        log.info("用户[{}]提现申请成功，申请单号:{}", userId, withdrawalNo);
        return withdrawalNo;
    }

    @Override
    public boolean auditWithdrawal(Integer id, PayWithdrawalAuditReq auditRequest, Long auditorUserId) {
        log.info("管理员[{}]审核提现申请开始，申请ID:{}", auditorUserId, id);

        // 1. 获取提现申请记录
        PayMerchantWithdrawalApplyEntity apply = payMerchantWithdrawalApplyService.getById(id);
        AssertUtils.notNull(apply, ResultCodeEnum.WITHDRAWAL_APPLY_NOT_FOUND);

        // 2. 检查申请状态是否为待审核
        if (!apply.getApplyStatus().equals(WithdrawalApplyStatusEnum.PENDING_REVIEW.getCode())) {
            throw new CommonException(ResultCodeEnum.WITHDRAWAL_APPLY_STATUS_ERROR, "当前申请状态不支持审核操作");
        }

        // 3. 更新审核信息
        apply.setAuditUserId(auditorUserId);
        apply.setAuditTime(LocalDateTime.now());
        apply.setAuditRemark(auditRequest.getAuditRemark());

        // 4. 根据审核状态处理
        if (auditRequest.getAuditStatus().equals(1)) {
            // 审核通过
            apply.setApplyStatus(WithdrawalApplyStatusEnum.APPROVED.getCode());
            log.info("提现申请[{}]审核通过", id);

            PayOfflineTransferRecordEntity transferRecord = new PayOfflineTransferRecordEntity();
            transferRecord.setWithdrawalNo(apply.getWithdrawalNo());
            transferRecord.setTransferAmount(apply.getActualAmount());
            transferRecord.setPayeeAccountId(apply.getAccountId());
            transferRecord.setTransferStatus(MerchantWithdrawTransferStatusEnum.PENDING_TRANSFER.getCode());
            boolean saved = payOfflineTransferRecordService.save(transferRecord);
            log.info("保存线下转账记录:{}", saved);
        } else if (auditRequest.getAuditStatus().equals(2)) {
            // 审核拒绝
            apply.setApplyStatus(WithdrawalApplyStatusEnum.REJECTED.getCode());
            // 解冻账户余额
            revertAccountBalance(apply);
            // 更新收益使用记录状态为取消
            updateRevenueUsageStatus(apply.getWithdrawalNo(), MerchantRevenueUsageStatusEnum.CANCELLED.getCode());
            log.info("提现申请[{}]审核拒绝", id);
        } else {
            throw new CommonException(ResultCodeEnum.WITHDRAWAL_AUDIT_STATUS_ERROR, "不支持的审核状态");
        }

        // 5. 保存审核结果
        boolean updated = payMerchantWithdrawalApplyService.updateById(apply);

        // 6. 记录操作日志
        recordAuditOperation(apply.getWithdrawalNo(), auditorUserId, auditRequest);

        log.info("管理员[{}]审核提现申请完成，申请ID:{}, 结果:{}", auditorUserId, id, updated);
        return updated;
    }

    /**
     * 记录提现申请操作日志
     */
    private void recordApplyOperation(String withdrawalNo, Long operatorId, BigDecimal applyAmount) {
        PayMerchantWithdrawalOperationLogEntity logEntity = new PayMerchantWithdrawalOperationLogEntity();
        logEntity.setWithdrawalNo(withdrawalNo);
        logEntity.setOperatorType(1);
        logEntity.setOperatorId(operatorId);
        logEntity.setOperationContent("发起提现申请，申请金额：" + applyAmount);
        logEntity.setOperationTime(LocalDateTime.now());
        payWithdrawalOperationLogService.save(logEntity);
    }

    /**
     * 审核拒绝时解冻账户余额
     */
    private void revertAccountBalance(PayMerchantWithdrawalApplyEntity apply) {
        boolean result = payMerchantAccountService.unfreezeBalanceForWithdrawalReject(apply.getUserId(), apply.getApplyAmount());
        log.info("解冻账户余额结果:{}", result);

        // 恢复收益明细的提现状态
        revertRevenueDetailStatus(apply);
    }

    /**
     * 审核拒绝时恢复收益明细的提现状态
     */
    private void revertRevenueDetailStatus(PayMerchantWithdrawalApplyEntity apply) {
        // 获取与该提现申请相关的所有收益使用记录
        List<PayMerchantRevenueUsageEntity> usageRecords = payMerchantRevenueUsageService.list(new LambdaQueryWrapper<PayMerchantRevenueUsageEntity>().eq(PayMerchantRevenueUsageEntity::getWithdrawalApplyId, apply.getWithdrawalNo()));

        if (CollUtil.isEmpty(usageRecords)) {
            return;
        }

        // 收集收益明细ID
        List<Integer> detailIds = usageRecords.stream().map(PayMerchantRevenueUsageEntity::getRevenueDetailId).distinct().collect(Collectors.toList());

        // 获取收益明细
        List<PayMerchantRevenueDetailEntity> revenueDetails = payMerchantRevenueDetailService.listByIds(detailIds);

        // 更新收益明细的提现状态为未提现
        List<PayMerchantRevenueDetailEntity> updatedDetails = revenueDetails.stream().map(detail -> {
            detail.setWithdrawStatus(MerchantRevenueWithdrawStatusEnum.NOT_WITHDRAWN.getCode());
            return detail;
        }).collect(Collectors.toList());

        // 批量更新收益明细
        payMerchantRevenueDetailService.updateBatchById(updatedDetails);
        log.info("恢复{}条收益明细的提现状态为未提现", updatedDetails.size());
    }

    /**
     * 记录审核操作日志
     */
    private void recordAuditOperation(String withdrawalNo, Long operatorId, PayWithdrawalAuditReq auditRequest) {
        PayMerchantWithdrawalOperationLogEntity logEntity = new PayMerchantWithdrawalOperationLogEntity();
        logEntity.setWithdrawalNo(withdrawalNo);
        logEntity.setOperatorType(2);
        logEntity.setOperatorId(operatorId);
        logEntity.setOperationContent(auditRequest.getAuditStatus().equals(1) ? "审核通过" : "审核拒绝");
        logEntity.setOperationTime(LocalDateTime.now());
        payWithdrawalOperationLogService.save(logEntity);
    }

    /**
     * 更新收益使用记录状态
     */
    private void updateRevenueUsageStatus(String withdrawalNo, String status) {
        List<PayMerchantRevenueUsageEntity> usageRecords = payMerchantRevenueUsageService.list(new LambdaQueryWrapper<PayMerchantRevenueUsageEntity>().eq(PayMerchantRevenueUsageEntity::getWithdrawalApplyId, withdrawalNo));

        if (CollUtil.isNotEmpty(usageRecords)) {
            usageRecords.forEach(record -> record.setStatus(status));

            payMerchantRevenueUsageService.updateBatchById(usageRecords);
            log.info("更新{}条收益使用记录状态为{}", usageRecords.size(), status);
        }
    }

    /**
     * 验证账户信息
     */
    private PayMerchantAccountEntity validateAccount(Long userId) {
        PayMerchantAccountEntity account = payMerchantAccountService.getMyAccount(userId);
        if (CommonConstant.ACCOUNT_LOCKED.intValue() == account.getIsBlock()) {
            throw new CommonException(ResultCodeEnum.MERCHANT_ACCOUNT_IS_LOCKED);
        }
        return account;
    }

    /**
     * 验证余额和配置以及是否有审核中的提现申请
     */
    private PayWithdrawalConfigEntity validateBalanceAndConfig(PayMerchantAccountEntity account, BigDecimal applyAmount, Long userId) {
        // 检查是否存在审核中的提现申请
        checkPendingWithdrawalApplications(userId);

        // 检查余额是否充足
        if (account.getAvailableBalance().compareTo(applyAmount) < 0) {
            throw new CommonException(ResultCodeEnum.MERCHANT_ACCOUNT_NOT_ENOUGH);
        }

        // 获取用户类型并查询对应配置
        PayWithdrawalConfigEntity config = payWithdrawalConfigService.getActiveAndLatestConfig();
        if (config == null || config.getStatus() != 1) {
            throw new CommonException(ResultCodeEnum.WITHDRAWAL_CONFIG_NOT_FOUND);
        }

        // 验证金额限制
        BigDecimal minWithdrawalAmount = MoneyUtil.yuanToCentWithBigDecimal(config.getMinWithdrawalAmount());
        if (applyAmount.compareTo(minWithdrawalAmount) < 0) {
            throw new CommonException(ResultCodeEnum.WITHDRAWAL_AMOUNT_LESS_THAN_MIN, "提现金额不能低于最低提现金额：" + config.getMinWithdrawalAmount());
        }
        BigDecimal maxWithdrawalAmount = MoneyUtil.yuanToCentWithBigDecimal(config.getMaxWithdrawalAmount());
        if (applyAmount.compareTo(maxWithdrawalAmount) > 0) {
            throw new CommonException(ResultCodeEnum.WITHDRAWAL_AMOUNT_EXCEEDS_MAX, "提现金额不能超过单日最高提现金额：" + config.getMaxWithdrawalAmount());
        }

        return config;
    }

    /**
     * 检查是否存在审核中的提现申请
     *
     * @param userId 用户ID
     */
    private void checkPendingWithdrawalApplications(Long userId) {
        // 查询用户是否存在待审核的提现申请
        List<PayMerchantWithdrawalApplyEntity> pendingApplications = payMerchantWithdrawalApplyService.list(
                new LambdaQueryWrapper<PayMerchantWithdrawalApplyEntity>()
                        .eq(PayMerchantWithdrawalApplyEntity::getUserId, userId)
                        .eq(PayMerchantWithdrawalApplyEntity::getApplyStatus, WithdrawalApplyStatusEnum.PENDING_REVIEW.getCode())
        );

        if (CollUtil.isNotEmpty(pendingApplications)) {
            throw new CommonException(ResultCodeEnum.WITHDRAWAL_APPLY_STATUS_ERROR, "您有正在审核中的提现申请，请等待审核完成后再提交新的申请");
        }
    }


    /**
     * 计算手续费和税费
     */
    private FeeCalculationResult calculateFees(BigDecimal applyAmount, PayWithdrawalConfigEntity config, BigDecimal totalWithdrawnAmount) {
        // 计算平台手续费
        BigDecimal platformFee = BigDecimal.ZERO;
        
        // 判断收费模式
        BigDecimal chargeBaseAmount = applyAmount;
        if (config.getPlatformFeeChargeMode() != null && config.getPlatformFeeChargeMode() == 2) {
            // 按累计提现总额收费
            chargeBaseAmount = totalWithdrawnAmount.add(applyAmount);
        }
        
        // 判断是否超过起征金额
        BigDecimal platformFeeThreshold = MoneyUtil.yuanToCentWithBigDecimal(config.getPlatformFeeThreshold());
        if (config.getPlatformFeeThreshold().compareTo(BigDecimal.ZERO) <= 0 
                || chargeBaseAmount.compareTo(platformFeeThreshold) > 0) {
            // 如果起征金额为0，或者申请金额超过起征金额，则收取手续费
            // 只对超过起征金额的部分计算手续费
            BigDecimal taxableAmount = applyAmount;
            if (config.getPlatformFeeThreshold().compareTo(BigDecimal.ZERO) > 0) {
                // 起征金额大于0时，只对超出部分收费
                taxableAmount = applyAmount.subtract(platformFeeThreshold).max(BigDecimal.ZERO);
            }
            platformFee = taxableAmount.multiply(config.getPlatformFeeRate().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_DOWN));
        }
        
        BigDecimal taxAmount = BigDecimal.ZERO;
        if (config.getTaxRate() != null) {
            taxAmount = applyAmount.multiply(config.getTaxRate().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_DOWN));
        }
        BigDecimal actualAmount = applyAmount.subtract(platformFee).subtract(taxAmount);

        return new FeeCalculationResult(platformFee, taxAmount, actualAmount);
    }

    /**
     * 处理收益明细拆分
     */
    private RevenueSplitResult processRevenueSplit(Long userId, BigDecimal applyAmount, String withdrawalNo) {
        // 获取未退款的收益明细用于拆分
        List<PayMerchantRevenueDetailEntity> revenueDetails = payMerchantRevenueDetailService.getRevenueDetailsByMerchantUserId(userId);

        List<PayMerchantRevenueUsageEntity> usages = new ArrayList<>();
        List<PayMerchantRevenueDetailEntity> updatedDetails = new ArrayList<>();
        BigDecimal remainingAmount = applyAmount;
        List<String> usedDetailIds = new ArrayList<>();

        // 1. 优先处理部分提现的收益明细
        Optional<PayMerchantRevenueDetailEntity> partiallyWithdrawnDetail = revenueDetails.stream()
                .filter(detail -> MerchantRevenueWithdrawStatusEnum.PARTIALLY_WITHDRAWN.getCode().equals(detail.getWithdrawStatus()))
                .findFirst();

        // 2. 获取未提现的收益明细
        List<PayMerchantRevenueDetailEntity> notWithdrawnDetails = revenueDetails.stream()
                .filter(detail -> MerchantRevenueWithdrawStatusEnum.NOT_WITHDRAWN.getCode().equals(detail.getWithdrawStatus()))
                .collect(Collectors.toList());

        // 3. 获取所有相关收益明细的使用记录
        BigDecimal partUsage = BigDecimal.ZERO;
        PayMerchantRevenueDetailEntity detail = null;
        if (partiallyWithdrawnDetail.isPresent()) {
            detail = partiallyWithdrawnDetail.get();
            BigDecimal totalUsage = payMerchantRevenueUsageService.list(new LambdaQueryWrapper<PayMerchantRevenueUsageEntity>()
                    .eq(PayMerchantRevenueUsageEntity::getRevenueDetailId, detail.getId())
                    .eq(PayMerchantRevenueUsageEntity::getStatus, MerchantRevenueUsageStatusEnum.SUCCESS.getCode()))
                    .stream()
                    .map(PayMerchantRevenueUsageEntity::getUsedAmount)
                    .reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
            partUsage = detail.getActualRevenue().subtract(totalUsage);
        }

        // 4. 先处理部分提现的收益明细
        if (partUsage.compareTo(BigDecimal.ZERO) > 0) {
            // 如果当前明细可用金额大于剩余需要提现的金额，则部分使用,直接返回
            if (partUsage.compareTo(remainingAmount) > 0) {
                // 创建使用记录
                PayMerchantRevenueUsageEntity usage = createRevenueUsage(detail.getId(), withdrawalNo, remainingAmount, remainingAmount);
                usages.add(usage);
                usedDetailIds.add(String.valueOf(detail.getId()));

                remainingAmount = BigDecimal.ZERO;
                // 返回使用记录和需要更新的收益明细
                return new RevenueSplitResult(usages, updatedDetails, usedDetailIds, remainingAmount);
            } else {
                // 当前明细金额小于等于剩余需要提现的金额，全部使用
                PayMerchantRevenueUsageEntity usage = createRevenueUsage(detail.getId(), withdrawalNo, partUsage, remainingAmount);
                usages.add(usage);
                usedDetailIds.add(String.valueOf(detail.getId()));
                remainingAmount = remainingAmount.subtract(partUsage);
                // 更新收益明细的提现状态为已提现
                detail.setWithdrawStatus(MerchantRevenueWithdrawStatusEnum.FULLY_WITHDRAWN.getCode());
                updatedDetails.add(detail);
            }

        }
        // 5 如果还有剩余金额，继续处理未提现的收益明细
        if (remainingAmount.compareTo(BigDecimal.ZERO) > 0) {
            for (PayMerchantRevenueDetailEntity nonWithdrawnDetail : notWithdrawnDetails) {
                // 如果剩余需要提现的金额已经为0，则跳出循环
                if (remainingAmount.compareTo(BigDecimal.ZERO) <= 0) {
                    break;
                }
                BigDecimal availableAmount = nonWithdrawnDetail.getActualRevenue();

                // 如果该明细无可使用金额，跳过
                if (availableAmount.compareTo(BigDecimal.ZERO) <= 0) {
                    continue;
                }

                // 如果当前明细可用金额大于剩余需要提现的金额，则部分使用
                if (availableAmount.compareTo(remainingAmount) > 0) {
                    // 创建使用记录
                    PayMerchantRevenueUsageEntity usage = createRevenueUsage(nonWithdrawnDetail.getId(), withdrawalNo, remainingAmount, remainingAmount);
                    usages.add(usage);
                    usedDetailIds.add(String.valueOf(nonWithdrawnDetail.getId()));

                    // 更新收益明细的提现状态为部分提现
                    nonWithdrawnDetail.setWithdrawStatus(MerchantRevenueWithdrawStatusEnum.PARTIALLY_WITHDRAWN.getCode());
                    updatedDetails.add(nonWithdrawnDetail);

                    remainingAmount = BigDecimal.ZERO;

                    return new RevenueSplitResult(usages, updatedDetails, usedDetailIds, remainingAmount);
                } else {
                    // 当前明细金额小于等于剩余需要提现的金额，全部使用
                    PayMerchantRevenueUsageEntity usage = createRevenueUsage(nonWithdrawnDetail.getId(), withdrawalNo, availableAmount, remainingAmount);
                    usages.add(usage);
                    usedDetailIds.add(String.valueOf(nonWithdrawnDetail.getId()));
                    remainingAmount = remainingAmount.subtract(availableAmount);

                    // 更新收益明细的提现状态为已提现
                    nonWithdrawnDetail.setWithdrawStatus(MerchantRevenueWithdrawStatusEnum.FULLY_WITHDRAWN.getCode());
                    updatedDetails.add(nonWithdrawnDetail);
                }
            }
        }
        // 返回使用记录和需要更新的收益明细
        return new RevenueSplitResult(usages, updatedDetails, usedDetailIds, remainingAmount);
    }

    /**
     * 创建收益使用记录
     */
    private PayMerchantRevenueUsageEntity createRevenueUsage(Integer revenueDetailId, String withdrawalNo, BigDecimal usedAmount, BigDecimal availableBalanceBefore) {
        PayMerchantRevenueUsageEntity usage = new PayMerchantRevenueUsageEntity();
        usage.setRevenueDetailId(revenueDetailId);
        usage.setWithdrawalApplyId(withdrawalNo);
        usage.setUsedAmount(usedAmount);
        usage.setAvailableAmountBefore(availableBalanceBefore);
        BigDecimal newAvailableBalance = availableBalanceBefore.subtract(usedAmount);
        usage.setAvailableAmountAfter(newAvailableBalance);
        usage.setStatus(MerchantRevenueUsageStatusEnum.SUCCESS.getCode());
        usage.setRemark("用于提现申请 " + withdrawalNo + (usedAmount.compareTo(availableBalanceBefore) < 0 ? " (全部使用)" : " (部分使用)"));
        return usage;
    }

    /**
     * 执行批量操作
     */
    private void executeBatchOperations(RevenueSplitResult splitResult) {
        // 执行收益使用记录的保存操作
        if (!splitResult.getUsages().isEmpty()) {
            payMerchantRevenueUsageService.saveBatch(splitResult.getUsages());
        }

        // 更新收益明细的提现状态
        if (!splitResult.getDetailsToUpdate().isEmpty()) {
            payMerchantRevenueDetailService.updateBatchById(splitResult.getDetailsToUpdate());
        }
    }

    /**
     * 验证剩余金额
     */
    private void validateRemainingAmount(BigDecimal remainingAmount) {
        if (remainingAmount.compareTo(BigDecimal.ZERO) > 0) {
            throw new CommonException(ResultCodeEnum.REVENUE_NOT_ENOUGH, "收益明细不足以覆盖申请金额，差额：" + remainingAmount);
        }
    }

    /**
     * 创建提现申请记录
     */
    private PayMerchantWithdrawalApplyEntity createWithdrawalApply(String withdrawalNo, Long userId, PayMerchantAccountEntity account, BigDecimal applyAmount, FeeCalculationResult feeResult, RevenueSplitResult splitResult) {
        PayMerchantWithdrawalApplyEntity apply = new PayMerchantWithdrawalApplyEntity();
        apply.setWithdrawalNo(withdrawalNo);
        apply.setUserId(userId);
        apply.setAccountId(account.getId());
        apply.setApplyAmount(applyAmount);
        apply.setApplyTime(LocalDateTime.now());
        apply.setPlatformFee(feeResult.getPlatformFee());
        apply.setTaxAmount(feeResult.getTaxAmount());
        apply.setActualAmount(feeResult.getActualAmount());
        apply.setAmountSplitDesc("按时间顺序从前到后使用收益明细");
        apply.setSettlementIds(String.join(",", splitResult.getUsedDetailIds()));
        apply.setApplyStatus(0);
        return apply;
    }

    /**
     * 费用计算结果
     */
    private static class FeeCalculationResult {
        private final BigDecimal platformFee;
        private final BigDecimal taxAmount;
        private final BigDecimal actualAmount;

        public FeeCalculationResult(BigDecimal platformFee, BigDecimal taxAmount, BigDecimal actualAmount) {
            this.platformFee = platformFee;
            this.taxAmount = taxAmount;
            this.actualAmount = actualAmount;
        }

        // Getters
        public BigDecimal getPlatformFee() {
            return platformFee;
        }

        public BigDecimal getTaxAmount() {
            return taxAmount;
        }

        public BigDecimal getActualAmount() {
            return actualAmount;
        }
    }

    /**
     * 收益拆分结果
     */
    private static class RevenueSplitResult {
        private final List<PayMerchantRevenueUsageEntity> usages;
        private final List<PayMerchantRevenueDetailEntity> detailsToUpdate;
        private final List<String> usedDetailIds;
        private final BigDecimal remainingAmount;

        public RevenueSplitResult(List<PayMerchantRevenueUsageEntity> usages, List<PayMerchantRevenueDetailEntity> detailsToUpdate, List<String> usedDetailIds, BigDecimal remainingAmount) {
            this.usages = usages;
            this.detailsToUpdate = detailsToUpdate;
            this.usedDetailIds = usedDetailIds;
            this.remainingAmount = remainingAmount;
        }

        public List<PayMerchantRevenueUsageEntity> getUsages() {
            return usages;
        }

        public List<PayMerchantRevenueDetailEntity> getDetailsToUpdate() {
            return detailsToUpdate;
        }

        public List<String> getUsedDetailIds() {
            return usedDetailIds;
        }

        public BigDecimal getRemainingAmount() {
            return remainingAmount;
        }
    }
}