package com.ruoyi.app.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.app.utils.ConstantUtil;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.system.domain.InfoUser;
import com.ruoyi.system.domain.PointsTransaction;
import com.ruoyi.system.domain.UserBilling;
import com.ruoyi.system.domain.UserWallet;
import com.ruoyi.system.service.IInfoUserService;
import com.ruoyi.system.service.IPointsTransactionService;
import com.ruoyi.system.service.IUserBillingService;
import com.ruoyi.system.service.IUserWalletService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Component
public class WalletService {
    @Autowired
    private IUserWalletService userWalletService;
    @Autowired
    private IPointsTransactionService pointsTransactionService;
    @Autowired
    private IInfoUserService userService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private IUserBillingService billingService;

    // 锁超时时间（秒）
    private static final int LOCK_TIMEOUT = 20;
    // 锁等待时间（秒）
    private static final int LOCK_WAIT_TIME = 10;

    /**
     * 订单取消、退款成功返回积分
     *
     * @param userId
     * @param ddId
     * @param points
     */

    /**
     * 订单取消、退款成功返回积分
     *
     * @param userId
     * @param ddId
     * @param points
     */
    @Transactional(rollbackFor = Exception.class)
    public void returnPoints(Long userId, Long ddId, Long points) {
        // 1. 参数校验
        if (userId == null || ddId == null || points == null || points <= 0) {
            throw new ServiceException(MessageUtils.message("no.wallet.common.cs.error"));
        }

        InfoUser user = userService.getById(userId);
        if (user == null) {
            throw new ServiceException(MessageUtils.message("no.wallet.noexist.userinfo"));
        }
        String lockKey = "wallet:lock:" + userId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁
            if (lock.tryLock(LOCK_WAIT_TIME, LOCK_TIMEOUT, TimeUnit.SECONDS)) {
                boolean releaseInFinally = true;
                try {
                    // 2. 获取用户钱包
                    UserWallet userWallet = userWalletService.selectByUserId(userId);
                    if (userWallet == null) {
                        throw new ServiceException(MessageUtils.message("no.user.wallet.not.exist"));
                    }

                    // 3. 检查是否已经退过积分（防重复）
                    PointsTransaction existingTransaction = pointsTransactionService.getOne(
                            new LambdaQueryWrapper<PointsTransaction>()
                                    .eq(PointsTransaction::getDdId, ddId.toString())
                                    .eq(PointsTransaction::getType, "2")
                    );
                    if (existingTransaction != null) {
                        throw new ServiceException("该订单积分已退回，请勿重复操作");
                    }

                    // 4. 先创建积分流水记录（重要：先记录后更新）
                    Long newBalance = userWallet.getPointsWallet() + points;
                    createPointTransaction(userId, points.toString(), newBalance.toString(), ddId.toString(), "2");

                    // 5. 乐观锁更新钱包
                    LambdaQueryWrapper<UserWallet> updateQuery = new LambdaQueryWrapper<>();
                    updateQuery.eq(UserWallet::getUserId, userId)
                            .eq(UserWallet::getVersion, userWallet.getVersion())
                            .isNull(UserWallet::getStoreId);

                    userWallet.setPointsWallet(newBalance);
                    userWallet.setVersion(userWallet.getVersion() + 1);

                    boolean updateSuccess = userWalletService.update(userWallet, updateQuery);
                    if (!updateSuccess) {
                        throw new ServiceException(MessageUtils.message("no.wallet.update.faile"));
                    }
                    releaseInFinally = false;
                    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            if (lock.isHeldByCurrentThread()) {
                                lock.unlock();
                            }
                        }
                    });
                } finally {
                    if (releaseInFinally && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                throw new ServiceException(MessageUtils.message("no.system.busy.try.again"));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ServiceException(MessageUtils.message("no.operation.interrupted.try.again"));
        }
    }

    /**
     * 扣除积分（订单支付等场景）
     *
     * @param userId 用户ID
     * @param ddId   订单ID
     * @param points 扣除积分数量
     */
    @Transactional(rollbackFor = Exception.class)
    public void deductPoints(Long userId, Long ddId, Long points) {
        // 1. 参数校验
        if (userId == null || ddId == null || points == null || points <= 0) {
            throw new ServiceException(MessageUtils.message("no.wallet.common.cs.error"));
        }
        InfoUser user = userService.getById(userId);
        if (user == null) {
            throw new ServiceException(MessageUtils.message("no.wallet.noexist.userinfo"));
        }

        String lockKey = ConstantUtil.WalletPointLock + userId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁
            if (lock.tryLock(LOCK_WAIT_TIME, LOCK_TIMEOUT, TimeUnit.SECONDS)) {
                boolean releaseInFinally = true;
                try {
                    // 2. 获取用户钱包
                    UserWallet userWallet = userWalletService.selectByUserId(userId);
                    if (userWallet == null) {
                        throw new ServiceException(MessageUtils.message("no.user.wallet.not.exist"));
                    }

                    // 3. 检查积分是否足够
                    if (userWallet.getPointsWallet() < points) {
                        throw new ServiceException("积分余额不足");
                    }

                    // 4. 检查是否已经扣过积分（防重复）
                    PointsTransaction existingTransaction = pointsTransactionService.getOne(
                            new LambdaQueryWrapper<PointsTransaction>()
                                    .eq(PointsTransaction::getDdId, ddId.toString())
                                    .eq(PointsTransaction::getType, "1")
                    );
                    if (existingTransaction != null) {
                        throw new ServiceException("该订单积分已扣除，请勿重复操作");
                    }

                    // 5. 先创建积分流水记录
                    Long newBalance = userWallet.getPointsWallet() - points;
                    createPointTransaction(userId, points.toString(), newBalance.toString(), ddId.toString(), "1");

                    // 6. 乐观锁更新钱包
                    LambdaQueryWrapper<UserWallet> updateQuery = new LambdaQueryWrapper<>();
                    updateQuery.eq(UserWallet::getUserId, userId)
                            .eq(UserWallet::getVersion, userWallet.getVersion())
                            .isNull(UserWallet::getStoreId);

                    userWallet.setPointsWallet(newBalance);
                    userWallet.setVersion(userWallet.getVersion() + 1);

                    boolean updateSuccess = userWalletService.update(userWallet, updateQuery);
                    if (!updateSuccess) {
                        throw new ServiceException(MessageUtils.message("no.wallet.update.faile"));
                    }
                    releaseInFinally = false;
                    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            if (lock.isHeldByCurrentThread()) {
                                lock.unlock();
                            }
                        }
                    });
                } finally {
                    if (releaseInFinally && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                throw new ServiceException(MessageUtils.message("no.system.busy.try.again"));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ServiceException(MessageUtils.message("no.operation.interrupted.try.again"));
        }
    }

    /**
     * 增加余额
     *
     * @param userId 用户ID
     * @param amount 增加金额
     */
    @Transactional(rollbackFor = Exception.class)
    public void addBalance(Long userId, BigDecimal amount, UserBilling billing) {
        // 1. 参数校验
        if (userId == null || amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException(MessageUtils.message("no.wallet.common.cs.error"));
        }
        InfoUser user = userService.getById(userId);
        if (user == null) {
            throw new ServiceException(MessageUtils.message("no.wallet.noexist.userinfo"));
        }
        String lockKey = ConstantUtil.WalletBalanceLock + userId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁
            if (lock.tryLock(LOCK_WAIT_TIME, LOCK_TIMEOUT, TimeUnit.SECONDS)) {
                boolean releaseInFinally = true;
                try {
                    // 2. 获取用户钱包
                    UserWallet userWallet = userWalletService.selectByUserId(userId);
                    if (userWallet == null) {
                        throw new ServiceException(MessageUtils.message("no.user.wallet.not.exist"));
                    }
                    Double behalfAmount = billing.getBehalfAmount();
                    // 3. 更新余额
                    BigDecimal newBalance = userWallet.getBalanceWallet().add(amount);
                    if (behalfAmount != null) {
                        //该订单存在冻结金额，解冻金额
                        long blockedCount = billingService.count(new LambdaQueryWrapper<UserBilling>().eq(UserBilling::getUserId, userId).eq(UserBilling::getDdId, billing.getDdId()).eq(UserBilling::getType, "4"));
                        if (blockedCount > 0) {
                            BigDecimal newBlocked = userWallet.getBlockedFunds().subtract(BigDecimal.valueOf(behalfAmount));
                            userWallet.setBlockedFunds(newBlocked);
                            createUserBill(userId, billing.getDdId(), "5", BigDecimal.valueOf(behalfAmount), newBlocked, user.getUserType(), "release blocked founds", null);
                        }
                    }

                    // 4. 乐观锁更新钱包
                    LambdaUpdateWrapper<UserWallet> updateQuery = new LambdaUpdateWrapper<>();
                    updateQuery.eq(UserWallet::getUserId, userId)
                            .eq(UserWallet::getVersion, userWallet.getVersion())
                            .isNull(UserWallet::getStoreId);
                    userWallet.setBalanceWallet(newBalance);
                    userWallet.setVersion(userWallet.getVersion() + 1);

                    boolean updateSuccess = userWalletService.update(userWallet, updateQuery);
                    createUserBill(billing, userWallet.getBalanceWallet());
                    if (!updateSuccess) {
                        throw new ServiceException(MessageUtils.message("no.wallet.update.faile"));
                    }
                    releaseInFinally = false;
                    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            if (lock.isHeldByCurrentThread()) {
                                lock.unlock();
                            }
                        }
                    });
                } finally {
                    if (releaseInFinally && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                throw new ServiceException(MessageUtils.message("no.system.busy.try.again"));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ServiceException(MessageUtils.message("no.operation.interrupted.try.again"));
        }
    }

    /**
     * 增加摊位余额
     *
     * @param storeId 摊位ID
     * @param amount  增加金额
     * @param billing 账单信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void addStallBalance(Long storeId, BigDecimal amount, UserBilling billing) {
        // 1. 参数校验
        if (storeId == null || amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException(MessageUtils.message("no.wallet.common.cs.error"));
        }
        String lockKey = "wallet:stall:lock:" + storeId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁
            if (lock.tryLock(LOCK_WAIT_TIME, LOCK_TIMEOUT, TimeUnit.SECONDS)) {
                boolean releaseInFinally = true;
                try {
                    // 2. 获取摊位钱包
                    UserWallet stallWallet = userWalletService.selectByStoreId(storeId);
                    if (stallWallet == null) {
                        throw new ServiceException(MessageUtils.message("no.user.wallet.not.exist"));
                    }

                    // 3. 更新余额
                    BigDecimal newBalance = stallWallet.getBalanceWallet().add(amount);

                    // 4. 乐观锁更新钱包
                    LambdaUpdateWrapper<UserWallet> updateQuery = new LambdaUpdateWrapper<>();
                    updateQuery.eq(UserWallet::getStoreId, storeId)
                            .eq(UserWallet::getVersion, stallWallet.getVersion());

                    stallWallet.setBalanceWallet(newBalance);
                    stallWallet.setVersion(stallWallet.getVersion() + 1);

                    boolean updateSuccess = userWalletService.update(stallWallet, updateQuery);
                    createUserBill(billing, stallWallet.getBalanceWallet());
                    if (!updateSuccess) {
                        throw new ServiceException(MessageUtils.message("no.wallet.update.faile"));
                    }
                    releaseInFinally = false;
                    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            if (lock.isHeldByCurrentThread()) {
                                lock.unlock();
                            }
                        }
                    });
                } finally {
                    if (releaseInFinally && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                throw new ServiceException(MessageUtils.message("no.system.busy.try.again"));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ServiceException(MessageUtils.message("no.operation.interrupted.try.again"));
        }
    }

    /**
     * 增加余额
     *
     * @param userId 用户ID
     * @param amount 增加金额
     */
    @Transactional(rollbackFor = Exception.class)
    public void addBalance(Long userId, String ddId, String type, BigDecimal amount, BigDecimal behalfAmount) {
        // 1. 参数校验
        if (userId == null || amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException(MessageUtils.message("no.wallet.common.cs.error"));
        }
        InfoUser user = userService.getById(userId);
        if (user == null) {
            throw new ServiceException(MessageUtils.message("no.wallet.noexist.userinfo"));
        }
        String lockKey = ConstantUtil.WalletBalanceLock + userId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁
            if (lock.tryLock(LOCK_WAIT_TIME, LOCK_TIMEOUT, TimeUnit.SECONDS)) {
                boolean releaseInFinally = true;
                try {
                    // 2. 获取用户钱包
                    UserWallet userWallet = userWalletService.selectByUserId(userId);
                    if (userWallet == null) {
                        throw new ServiceException(MessageUtils.message("no.user.wallet.not.exist"));
                    }
                    // 3. 更新余额
                    BigDecimal newBalance = userWallet.getBalanceWallet().add(amount);

                    // 4. 乐观锁更新钱包
                    LambdaUpdateWrapper<UserWallet> updateQuery = new LambdaUpdateWrapper<>();
                    updateQuery.eq(UserWallet::getUserId, userId)
                            .eq(UserWallet::getVersion, userWallet.getVersion())
                            .isNull(UserWallet::getStoreId);

                    userWallet.setBalanceWallet(newBalance);
                    userWallet.setVersion(userWallet.getVersion() + 1);
                    //该订单存在冻结金额，解冻金额
                    long blockedCount = billingService.count(new LambdaQueryWrapper<UserBilling>().eq(UserBilling::getUserId, userId).eq(UserBilling::getDdId, ddId).eq(UserBilling::getType, "4"));
                    if (blockedCount > 0) {
                        BigDecimal newBlocked = userWallet.getBlockedFunds().subtract(behalfAmount);
                        userWallet.setBlockedFunds(newBlocked);
                        createUserBill(userId, ddId, "5", behalfAmount, newBlocked, user.getUserType(), "release blocked founds", null);
                    }
                    boolean updateSuccess = userWalletService.update(userWallet, updateQuery);
                    createUserBill(userId, ddId, type, amount, userWallet.getBalanceWallet(), user.getUserType(), "", behalfAmount);

                    if (!updateSuccess) {
                        throw new ServiceException(MessageUtils.message("no.wallet.update.faile"));
                    }
                    releaseInFinally = false;
                    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            if (lock.isHeldByCurrentThread()) {
                                lock.unlock();
                            }
                        }
                    });
                } finally {
                    if (releaseInFinally && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                throw new ServiceException(MessageUtils.message("no.system.busy.try.again"));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ServiceException(MessageUtils.message("no.operation.interrupted.try.again"));
        }
    }

    /**
     * 扣除余额
     *
     * @param userId 用户ID
     * @param ddId   订单ID
     * @param amount 扣除金额
     */
    @Transactional(rollbackFor = Exception.class)
    public void deductBalance(Long userId, String ddId, BigDecimal amount, String remark, String type) {
        // 1. 参数校验
        if (userId == null || ddId == null || amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException(MessageUtils.message("no.wallet.common.cs.error"));
        }
        InfoUser user = userService.getById(userId);
        if (user == null) {
            throw new ServiceException(MessageUtils.message("no.wallet.noexist.userinfo"));
        }
        String lockKey = ConstantUtil.WalletBalanceLock + userId;
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁
            if (lock.tryLock(LOCK_WAIT_TIME, LOCK_TIMEOUT, TimeUnit.SECONDS)) {
                boolean releaseInFinally = true;
                try {
                    // 2. 获取用户钱包
                    UserWallet userWallet = getUserWallet(userId);
                    if (userWallet == null) {
                        throw new ServiceException(MessageUtils.message("no.user.wallet.not.exist"));
                    }
                    // 3. 检查余额是否足够
                    if (userWallet.getBalanceWallet().compareTo(amount) < 0) {
                        throw new ServiceException(MessageUtils.message("no.user.wallet.insufficient.balance"));
                    }
                    // 4. 更新余额
                    BigDecimal newBalance = userWallet.getBalanceWallet().subtract(amount);
                    // 5. 乐观锁更新钱包
                    LambdaUpdateWrapper<UserWallet> updateQuery = new LambdaUpdateWrapper<>();
                    updateQuery.eq(UserWallet::getUserId, userId)
                            .eq(UserWallet::getVersion, userWallet.getVersion())
                            .isNull(UserWallet::getStoreId);
                    userWallet.setBalanceWallet(newBalance);
                    userWallet.setVersion(userWallet.getVersion() + 1);
                    boolean updateSuccess = userWalletService.update(userWallet, updateQuery);
                    if (!updateSuccess) {
                        throw new ServiceException(MessageUtils.message("no.wallet.update.faile"));
                    }
                    // 6. 钱包更新成功后再创建账单记录
                    createUserBill(userId, ddId, type, amount, newBalance, user.getUserType(), remark, null);
                    releaseInFinally = false;
                    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            if (lock.isHeldByCurrentThread()) {
                                lock.unlock();
                            }
                        }
                    });
                } finally {
                    if (releaseInFinally && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                throw new ServiceException(MessageUtils.message("no.system.busy.try.again"));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ServiceException(MessageUtils.message("no.operation.interrupted.try.again"));
        }
    }

    /**
     * 获取用户钱包信息
     *
     * @param userId 用户ID
     * @return 用户钱包
     */
    public UserWallet getUserWallet(Long userId) {
        if (userId == null) {
            throw new ServiceException("用户ID不能为空");
        }
        LambdaQueryWrapper<UserWallet> walletQuery = new LambdaQueryWrapper<>();
        UserWallet userWallet = userWalletService.selectByUserId(userId);
        if (userWallet == null) {
            throw new ServiceException(MessageUtils.message("no.user.wallet.not.exist"));
        }
        return userWallet;
    }

    /**
     * 增加冻结金额（不回滚外层事务）
     *
     * @param userId 用户ID
     * @param amount 增加金额
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void addBlockFunds(Long userId, BigDecimal amount, String ddId) {
        addBlockedFundsDetail(userId, amount, ddId);
    }

    /**
     * 解冻冻结金额不操作钱包余额
     *
     * @param userId
     * @param amount
     * @param ddId
     */
    public void deduceBlocked(Long userId, BigDecimal amount, String ddId) {
        // 1. 参数校验
        if (userId == null || amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException(MessageUtils.message("no.wallet.common.cs.error"));
        }
        InfoUser user = userService.getById(userId);
        if (user == null) {
            throw new ServiceException(MessageUtils.message("no.wallet.noexist.userinfo"));
        }

        String lockKey = ConstantUtil.WalletBalanceLock + userId;
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁
            if (lock.tryLock(LOCK_WAIT_TIME, LOCK_TIMEOUT, TimeUnit.SECONDS)) {
                boolean releaseInFinally = true;
                try {
                    // 2. 获取用户钱包
                    UserWallet userWallet = userWalletService.selectByUserId(userId);
                    if (userWallet == null) {
                        throw new ServiceException(MessageUtils.message("no.user.wallet.not.exist"));
                    }
                    BigDecimal balance = userWallet.getBlockedFunds().subtract(amount);
                    //钱包余额小于订单需要冻结的金额
                    if (balance.compareTo(BigDecimal.ZERO) < 0) {
                        throw new ServiceException(MessageUtils.message("no.wallet.blockamount.jd.exception.message"));
                    }
                    // 3. 更新余额
                    BigDecimal newBalance = userWallet.getBlockedFunds().subtract(amount);

                    // 4. 乐观锁更新钱包
                    LambdaUpdateWrapper<UserWallet> updateQuery = new LambdaUpdateWrapper<>();
                    updateQuery.eq(UserWallet::getUserId, userId)
                            .eq(UserWallet::getVersion, userWallet.getVersion())
                            .isNull(UserWallet::getStoreId);
                    userWallet.setBlockedFunds(newBalance);
                    userWallet.setVersion(userWallet.getVersion() + 1);
                    boolean updateSuccess = userWalletService.update(userWallet, updateQuery);
                    createUserBill(userId, ddId, "5", amount, newBalance, user.getUserType(), "release blocked founds", null);
                    if (!updateSuccess) {
                        throw new ServiceException(MessageUtils.message("no.wallet.update.faile"));
                    }
                    releaseInFinally = false;
                    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            if (lock.isHeldByCurrentThread()) {
                                lock.unlock();
                            }
                        }
                    });
                } finally {
                    if (releaseInFinally && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                throw new ServiceException(MessageUtils.message("no.system.busy.try.again"));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ServiceException(MessageUtils.message("no.operation.interrupted.try.again"));
        }
    }

    /**
     * 回滚外层事务
     *
     * @param userId
     * @param amount
     * @param ddId
     */
    @Transactional(rollbackFor = Exception.class)
    public void addBlockFundsBackTransaction(Long userId, BigDecimal amount, String ddId) {
        addBlockedFundsDetail(userId, amount, ddId);
    }

    private void addBlockedFundsDetail(Long userId, BigDecimal amount, String ddId) {
        // 1. 参数校验
        if (userId == null || amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException(MessageUtils.message("no.wallet.common.cs.error"));
        }
        InfoUser user = userService.getById(userId);
        if (user == null) {
            throw new ServiceException(MessageUtils.message("no.wallet.noexist.userinfo"));
        }

        String lockKey = ConstantUtil.WalletBalanceLock + userId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁
            if (lock.tryLock(LOCK_WAIT_TIME, LOCK_TIMEOUT, TimeUnit.SECONDS)) {
                boolean releaseInFinally = true;
                try {
                    // 2. 获取用户钱包
                    UserWallet userWallet = userWalletService.selectByUserId(userId);
                    if (userWallet == null) {
                        throw new ServiceException(MessageUtils.message("no.user.wallet.not.exist"));
                    }
                    BigDecimal balance = userWallet.getBalanceWallet().subtract(userWallet.getBlockedFunds()).subtract(amount);
                    //钱包余额小于订单需要冻结的金额
                    if (balance.compareTo(BigDecimal.ZERO) < 0) {
                        String message = MessageUtils.message("no.wallet.balance.less.than.order.amount");
                        message = StrUtil.format(message, amount);
                        throw new ServiceException(message);
                    }
                    // 3. 更新余额
                    BigDecimal newBalance = userWallet.getBlockedFunds().add(amount);

                    // 4. 乐观锁更新钱包
                    LambdaUpdateWrapper<UserWallet> updateQuery = new LambdaUpdateWrapper<>();
                    updateQuery.eq(UserWallet::getUserId, userId)
                            .eq(UserWallet::getVersion, userWallet.getVersion())
                            .isNull(UserWallet::getStoreId);

                    userWallet.setBlockedFunds(newBalance);
                    userWallet.setVersion(userWallet.getVersion() + 1);
                    boolean updateSuccess = userWalletService.update(userWallet, updateQuery);
                    createUserBill(userId, ddId, "4", amount, newBalance, user.getUserType(), "blocked funds", null);
                    if (!updateSuccess) {
                        throw new ServiceException(MessageUtils.message("no.wallet.update.faile"));
                    }
                    releaseInFinally = false;
                    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            if (lock.isHeldByCurrentThread()) {
                                lock.unlock();
                            }
                        }
                    });
                } finally {
                    if (releaseInFinally && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                throw new ServiceException(MessageUtils.message("no.system.busy.try.again"));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ServiceException(MessageUtils.message("no.operation.interrupted.try.again"));
        }
    }


    /**
     * 创建积分流水
     */
    private void createPointTransaction(Long userid, String pointsChange, String currentPoints, String ddId, String type) {
        PointsTransaction pointsTransaction = new PointsTransaction();
        pointsTransaction.setUserId(userid);
        if (type.equals("1")) {
            pointsTransaction.setPointsChange("-" + pointsChange);
            pointsTransaction.setType("1");
        }
        if (type.equals("2")) {
            pointsTransaction.setPointsChange("+" + pointsChange);
            pointsTransaction.setType("2");
        }
        pointsTransaction.setCurrentPoints(currentPoints);
        pointsTransaction.setDdId(ddId);
        pointsTransaction.setCreateTime(new Date());
        pointsTransactionService.save(pointsTransaction);
    }

    private void createUserBill(Long userId, String ddId, String type, BigDecimal change, BigDecimal current, String userType, String remark, BigDecimal behalfAmount) {
        try {
            UserBilling bill = new UserBilling();
            bill.setUserId(userId);
            bill.setType(type);
            bill.setState("0");
            bill.setUserType(userType);
            bill.setDdId(ddId);
            bill.setAmount(change.doubleValue());
            bill.setWalletBalance(current);
            bill.setCretim(new Date());
            bill.setIllustrate(remark);
            if (behalfAmount != null) {
                bill.setBehalfAmount(behalfAmount.doubleValue());
            }
            billingService.saveOrUpdate(bill);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }

    private void createUserBill(UserBilling bill, BigDecimal current) {
        bill.setWalletBalance(current);
        billingService.saveOrUpdate(bill);
    }
}
