package com.kexue.skills.service.impl;

import com.kexue.skills.entity.Account;
import com.kexue.skills.entity.AccountFrozen;
import com.kexue.skills.entity.SysUser;
import com.kexue.skills.entity.dto.AccountFrozenDto;
import com.kexue.skills.entity.dto.AccountReleaseDto;
import com.kexue.skills.entity.dto.ModelPriceDto;
import com.kexue.skills.exception.BizException;
import com.kexue.skills.mapper.AccountFrozenMapper;
import com.kexue.skills.mapper.AccountMapper;
import com.kexue.skills.mapper.SysUserMapper;
import com.kexue.skills.service.AccountFrozenService;
import com.kexue.skills.service.ModelPriceService;
import com.kexue.skills.entity.ModelPrice;
import com.kexue.skills.entity.AccountTransaction;
import com.kexue.skills.mapper.AccountTransactionMapper;
import com.kexue.skills.common.util.IDUtils;
import com.kexue.skills.common.ResultCode;
import com.kexue.skills.config.AccountDeductionProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static cn.dev33.satoken.SaManager.log;

/**
 * 账户冻结单服务实现
 *
 * @author 系统生成
 * @since 2026-04-11
 */
@Service("accountFrozenService")
@Transactional(rollbackFor = Exception.class)
public class AccountFrozenServiceImpl implements AccountFrozenService {

    private static final Logger LOG = LoggerFactory.getLogger(AccountFrozenServiceImpl.class);

    private static final Integer FROZEN_TYPE_TOKEN = 1;

    private static final Integer FROZEN_TYPE_RMB = 2;

    private static final BigDecimal YUAN_TO_POINTS_COEFFICIENT = BigDecimal.valueOf(100);

    @Resource
    private AccountFrozenMapper accountFrozenMapper;

    @Resource
    private AccountMapper accountMapper;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private ModelPriceService modelPriceService;

    @Resource
    private AccountTransactionMapper accountTransactionMapper;

    @Resource
    private AccountDeductionProperties accountDeductionProperties;

    /**
     * 创建冻结单
     *
     * @param accountFrozenDto 冻结单DTO
     * @return 冻结单信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountFrozen createFrozen(AccountFrozenDto accountFrozenDto) {
        // 1. 验证创建冻结单参数
        validateCreateFrozenParams(accountFrozenDto);
        
        // 2. 通过sessionId获取用户信息
        SysUser sysUser = getUserBySessionId(accountFrozenDto.getSessionId());
        
        // 3. 通过用户ID获取账户信息
        Account account = getAccountByUserId(sysUser.getUserId());
        
        // 4. 根据冻结类型计算冻结金额
        // - 如果是token类型，根据预估tokens和模型价格计算
        // - 如果是RMB类型，将元转换为积分（1元=100积分）
        BigDecimal finalFrozenAmount = calculateFrozenAmount(accountFrozenDto);
        
        // 5. 检查账户余额是否足够冻结
        // 计算可用余额（总余额 - 已冻结金额），确保足够本次冻结
        checkBalanceSufficient(account, finalFrozenAmount);
        
        // 6. 更新账户冻结金额
        // 将本次冻结金额加到账户的已冻结金额中
        updateAccountFrozenAmount(account, finalFrozenAmount);
        
        // 7. 执行创建冻结单
        // 构建冻结单对象并保存到数据库
        return doCreateFrozen(accountFrozenDto, sysUser.getUserId(), finalFrozenAmount);
    }

    /**
     * 验证创建冻结单参数
     *
     * @param accountFrozenDto 冻结单DTO
     */
    private void validateCreateFrozenParams(AccountFrozenDto accountFrozenDto) {
        if (accountFrozenDto == null) {
            throw new BizException(ResultCode.PARAMETER_EMPTY.getCode(), ResultCode.PARAMETER_EMPTY.getMessage());
        }
        if (accountFrozenDto.getSessionId() == null) {
            throw new BizException(ResultCode.SESSION_ID_NOT_EXIST.getCode(), ResultCode.SESSION_ID_NOT_EXIST.getMessage());
        }
        if (accountFrozenDto.getFrozenType() == null) {
            throw new BizException(ResultCode.PARAMETER_EMPTY.getCode(), "冻结类型不能为空");
        }
        
        // 根据冻结类型进行不同的参数校验
        if (FROZEN_TYPE_TOKEN.equals(accountFrozenDto.getFrozenType())) {
            // token类型需要校验：estimatedInputTokens、estimatedOutputTokens、modelName
            if (accountFrozenDto.getEstimatedInputTokens() == null) {
                throw new BizException(ResultCode.PARAMETER_EMPTY.getCode(), "预估输入tokens不能为空");
            }
            if (accountFrozenDto.getEstimatedOutputTokens() == null) {
                throw new BizException(ResultCode.PARAMETER_EMPTY.getCode(), "预估输出tokens不能为空");
            }
            if (accountFrozenDto.getModelName() == null) {
                throw new BizException(ResultCode.PARAMETER_EMPTY.getCode(), "模型名称不能为空");
            }
        } else if (FROZEN_TYPE_RMB.equals(accountFrozenDto.getFrozenType())) {
            // RMB类型需要校验：frozenAmount
            if (accountFrozenDto.getFrozenAmount() == null) {
                throw new BizException(ResultCode.PARAMETER_EMPTY.getCode(), "冻结金额不能为空");
            }
        }
        // 其他类型的校验可以在此添加
    }

    /**
     * 通过sessionId获取用户信息
     *
     * @param sessionId 会话ID
     * @return 用户信息
     */
    private SysUser getUserBySessionId(String sessionId) {
        SysUser sysUser = sysUserMapper.getBySessionId(sessionId);
        if (sysUser == null) {
            throw new BizException(ResultCode.SESSION_ID_NOT_EXIST.getCode(), ResultCode.SESSION_ID_NOT_EXIST.getMessage());
        }
        return sysUser;
    }

    /**
     * 通过用户ID获取账户信息
     *
     * @param userId 用户ID
     * @return 账户信息
     */
    private Account getAccountByUserId(Long userId) {
        Account account = accountMapper.queryByUserId(userId);
        if (account == null) {
            throw new BizException(ResultCode.ACCOUNT_NOT_EXIST.getCode(), ResultCode.ACCOUNT_NOT_EXIST.getMessage());
        }
        return account;
    }

    /**
     * 根据冻结类型计算冻结金额
     *
     * @param accountFrozenDto 冻结单DTO
     * @return 计算后的冻结金额（单位：积分）
     */
    private BigDecimal calculateFrozenAmount(AccountFrozenDto accountFrozenDto) {
        BigDecimal frozenAmount = accountFrozenDto.getFrozenAmount();
        if (FROZEN_TYPE_TOKEN.equals(accountFrozenDto.getFrozenType())) {
            return calculateTokenFrozenAmount(accountFrozenDto);
        } else if (FROZEN_TYPE_RMB.equals(accountFrozenDto.getFrozenType())) {
            return calculateRmbFrozenAmount(frozenAmount);
        }
        return frozenAmount;
    }

    /**
     * 计算token类型的冻结金额
     * 根据预估输入输出tokens和模型价格计算冻结金额，并应用扣费系数
     *
     * @param accountFrozenDto 冻结单DTO
     * @return 冻结金额（单位：积分）
     */
    private BigDecimal calculateTokenFrozenAmount(AccountFrozenDto accountFrozenDto) {
        LOG.debug("开始计算token类型冻结金额 - sessionId: {}, modelName: {}, estimatedInputTokens: {}, estimatedOutputTokens: {}",
                accountFrozenDto.getSessionId(), accountFrozenDto.getModelName(), 
                accountFrozenDto.getEstimatedInputTokens(), accountFrozenDto.getEstimatedOutputTokens());
        
        // 1. 验证必要参数
        if (accountFrozenDto.getEstimatedInputTokens() == null ||
            accountFrozenDto.getEstimatedOutputTokens() == null ||
            accountFrozenDto.getModelName() == null) {
            LOG.warn("token冻结金额计算缺少必要参数，返回原始冻结金额 - sessionId: {}, frozenAmount: {}",
                    accountFrozenDto.getSessionId(), accountFrozenDto.getFrozenAmount());
            return accountFrozenDto.getFrozenAmount();
        }
        
        // 2. 标准化模型名称
        String modelName = normalizeModelName(accountFrozenDto.getModelName());
        LOG.debug("标准化模型名称 - 原始名称: {}, 标准化后: {}", accountFrozenDto.getModelName(), modelName);
        
        // 3. 获取模型价格列表
        List<ModelPrice> modelPriceList = getModelPriceList(modelName);
        LOG.debug("获取模型价格列表 - modelName: {}, 价格规则数量: {}", modelName, modelPriceList.size());
        
        if (modelPriceList.isEmpty()) {
            LOG.warn("模型价格列表为空，请检查模型价格表: {}", modelName);
            return accountFrozenDto.getFrozenAmount();
        }
        
        // 4. 查找输入模型价格
        ModelPrice inputModelPrice = findInputModelPrice(modelPriceList, accountFrozenDto.getEstimatedInputTokens());
        LOG.debug("查找输入模型价格 - estimatedInputTokens: {}, 匹配结果: {}",
                accountFrozenDto.getEstimatedInputTokens(), 
                inputModelPrice != null ? "inputPerCent=" + inputModelPrice.getInputPerCent() : "未找到匹配");
        
        // 5. 查找输出模型价格
        ModelPrice outputModelPrice = findOutputModelPrice(modelPriceList, accountFrozenDto.getEstimatedOutputTokens());
        LOG.debug("查找输出模型价格 - estimatedOutputTokens: {}, 匹配结果: {}",
                accountFrozenDto.getEstimatedOutputTokens(),
                outputModelPrice != null ? "outputPerCent=" + outputModelPrice.getOutputPerCent() : "未找到匹配");
        
        if (inputModelPrice == null || outputModelPrice == null) {
            LOG.warn("未找到匹配的模型价格规则 - inputModelPrice: {}, outputModelPrice: {}",
                    inputModelPrice != null ? "已找到" : "未找到",
                    outputModelPrice != null ? "已找到" : "未找到");
            return accountFrozenDto.getFrozenAmount();
        }
        
        // 6. 计算总的token费用
        long totalFee = calculateTotalTokenFee(accountFrozenDto, inputModelPrice, outputModelPrice);
        LOG.debug("计算token总费用 - inputFee: {}, outputFee: {}, totalFee: {}",
                calculateTokenFee(accountFrozenDto.getEstimatedInputTokens(), inputModelPrice.getInputPerCent()),
                calculateTokenFee(accountFrozenDto.getEstimatedOutputTokens(), outputModelPrice.getOutputPerCent()),
                totalFee);
        
        // 7. 应用扣费系数
        BigDecimal baseAmount = BigDecimal.valueOf(totalFee);
        BigDecimal coefficient = accountDeductionProperties.getCoefficient();
        BigDecimal finalAmount = baseAmount.multiply(coefficient);
        
        LOG.info("token冻结金额计算完成 - sessionId: {}, 基础金额: {}分, 扣费系数: {}, 最终冻结金额: {}积分",
                accountFrozenDto.getSessionId(), totalFee, coefficient, finalAmount);
        
        return finalAmount;
    }

    /**
     * 标准化模型名称
     * 将前端传入的模型名称转换为数据库中对应的名称
     *
     * @param modelName 前端传入的模型名称
     * @return 标准化后的模型名称
     */
    private String normalizeModelName(String modelName) {
        if ("Qwen 3.5 Plus".equals(modelName)) {
            return "qwen3.5-plus";
        }
        return modelName;
    }

    /**
     * 获取模型价格列表
     *
     * @param modelName 模型名称
     * @return 模型价格列表
     */
    private List<ModelPrice> getModelPriceList(String modelName) {
        ModelPriceDto modelPriceDto = new ModelPriceDto();
        modelPriceDto.setModelName(modelName);
        return modelPriceService.getList(modelPriceDto);
    }

    /**
     * 根据输入tokens查找匹配的输入模型价格
     * 使用standard模式过滤价格规则
     *
     * @param modelPriceList 模型价格列表
     * @param estimatedInputTokens 预估输入tokens
     * @return 匹配的输入模型价格，若无匹配返回null
     */
    private ModelPrice findInputModelPrice(List<ModelPrice> modelPriceList, Long estimatedInputTokens) {
        return modelPriceList.stream()
                .filter(mp -> "standard".equals(mp.getOutputMode()))
                .filter(mp -> mp.getMinTokens() < estimatedInputTokens)
                .filter(mp -> mp.getMaxTokens() == -1 || mp.getMaxTokens() >= estimatedInputTokens)
                .max((mp1, mp2) -> mp1.getMinTokens().compareTo(mp2.getMinTokens()))
                .orElse(null);
    }

    /**
     * 根据输出tokens查找匹配的输出模型价格
     * 使用thinking模式过滤价格规则
     *
     * @param modelPriceList 模型价格列表
     * @param estimatedOutputTokens 预估输出tokens
     * @return 匹配的输出模型价格，若无匹配返回null
     */
    private ModelPrice findOutputModelPrice(List<ModelPrice> modelPriceList, Long estimatedOutputTokens) {
        return modelPriceList.stream()
                .filter(mp -> "thinking".equals(mp.getOutputMode()))
                .filter(mp -> mp.getMinTokens() < estimatedOutputTokens)
                .filter(mp -> mp.getMaxTokens() == -1 || mp.getMaxTokens() >= estimatedOutputTokens)
                .max((mp1, mp2) -> mp1.getMinTokens().compareTo(mp2.getMinTokens()))
                .orElse(null);
    }

    /**
     * 计算总的token费用
     *
     * @param accountFrozenDto 冻结单DTO
     * @param inputModelPrice 输入模型价格
     * @param outputModelPrice 输出模型价格
     * @return 总费用（单位：分）
     */
    private long calculateTotalTokenFee(AccountFrozenDto accountFrozenDto, ModelPrice inputModelPrice, ModelPrice outputModelPrice) {
        long inputFee = calculateTokenFee(accountFrozenDto.getEstimatedInputTokens(), inputModelPrice.getInputPerCent());
        long outputFee = calculateTokenFee(accountFrozenDto.getEstimatedOutputTokens(), outputModelPrice.getOutputPerCent());
        return inputFee + outputFee;
    }

    /**
     * 计算单个token费用
     * 采用向上取整的方式计算
     *
     * @param tokens token数量
     * @param perCent 每token对应的分数
     * @return 费用（单位：分）
     */
    private long calculateTokenFee(long tokens, long perCent) {
        long fee = tokens / perCent;
        if (tokens % perCent > 0) {
            fee += 1;
        }
        return fee;
    }

    /**
     * 计算RMB类型的冻结金额
     * 将元转换为积分（1元=100积分）
     *
     * @param frozenAmount 冻结金额（单位：元）
     * @return 冻结金额（单位：积分）
     */
    private BigDecimal calculateRmbFrozenAmount(BigDecimal frozenAmount) {
        if (frozenAmount == null) {
            return BigDecimal.ZERO;
        }
        return frozenAmount.multiply(YUAN_TO_POINTS_COEFFICIENT).multiply(accountDeductionProperties.getCoefficient());
    }

    /**
     * 检查账户余额是否足够冻结
     *
     * @param account 账户信息
     * @param frozenAmount 本次冻结金额
     */
    private void checkBalanceSufficient(Account account, BigDecimal frozenAmount) {
        BigDecimal balance = account.getBalance() == null ? BigDecimal.ZERO : account.getBalance();
        BigDecimal frozen = account.getFrozenAmount() == null ? BigDecimal.ZERO : account.getFrozenAmount();
        BigDecimal availableBalance = balance.subtract(frozen);
        LOG.debug("检查余额是否足够 - userId: {}, 总余额: {}, 已冻结: {}, 可用余额: {}, 本次冻结: {}",
                account.getUserId(), balance, frozen, availableBalance, frozenAmount);
        if (availableBalance.compareTo(frozenAmount) < 0) {
            LOG.warn("余额不足 - userId: {}, 可用余额: {}, 本次冻结: {}", account.getUserId(), availableBalance, frozenAmount);
            throw new BizException(ResultCode.INSUFFICIENT_BALANCE.getCode(), ResultCode.INSUFFICIENT_BALANCE.getMessage());
        }
        LOG.debug("余额检查通过 - userId: {}, 可用余额: {}, 本次冻结: {}", account.getUserId(), availableBalance, frozenAmount);
    }

    /**
     * 更新账户冻结金额
     *
     * @param account 账户信息
     * @param frozenAmount 本次冻结金额
     */
    private void updateAccountFrozenAmount(Account account, BigDecimal frozenAmount) {
        BigDecimal currentFrozen = account.getFrozenAmount() == null ? BigDecimal.ZERO : account.getFrozenAmount();
        account.setFrozenAmount(currentFrozen.add(frozenAmount));
        account.setUpdateTime(new Date());
        accountMapper.update(account);
    }

    /**
     * 执行创建冻结单
     *
     * @param accountFrozenDto 冻结单DTO
     * @param userId 用户ID
     * @param finalFrozenAmount 最终冻结金额
     * @return 冻结单信息
     */
    private AccountFrozen doCreateFrozen(AccountFrozenDto accountFrozenDto, Long userId, BigDecimal finalFrozenAmount) {
        AccountFrozen accountFrozen = new AccountFrozen();
        accountFrozen.setFrozenId(IDUtils.getSnowflakeIdStr());
        accountFrozen.setUserId(userId);
        accountFrozen.setSessionId(accountFrozenDto.getSessionId());
        accountFrozen.setCallId(accountFrozenDto.getCallId());
        accountFrozen.setModelName(accountFrozenDto.getModelName());
        if (Objects.nonNull(accountFrozenDto.getQuestion())) {
            accountFrozen.setQuestion(accountFrozenDto.getQuestion());
        }
        accountFrozen.setFrozenAmount(finalFrozenAmount);
        accountFrozen.setFrozenType(accountFrozenDto.getFrozenType());
        accountFrozen.setStatus("RESERVED");
        accountFrozen.setExpireAt(accountFrozenDto.getExpireAt());
        accountFrozen.setCreateTime(new Date());
        accountFrozen.setUpdateTime(new Date());
        accountFrozenMapper.insert(accountFrozen);
        return accountFrozen;
    }

    /**
     * 释放冻结单
     *
     * @param accountReleaseDto 冻结单释放DTO
     * @return 冻结单信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountFrozen releaseFrozen(AccountReleaseDto accountReleaseDto) {
        // 1. 验证释放冻结单参数
        validateReleaseParams(accountReleaseDto);
        
        // 2. 通过冻结单ID获取冻结单信息
        AccountFrozen accountFrozen = getFrozenById(accountReleaseDto.getFrozenId());
        
        // 3. 验证冻结单状态是否为预留状态
        // 只有状态为RESERVED的冻结单才能被释放
        validateFrozenStatus(accountFrozen);
        
        // 4. 通过用户ID获取账户信息
        Account account = getAccountByUserId(accountFrozen.getUserId());
        
        // 5. 根据冻结类型计算最终释放金额
        // - 如果是token类型，根据实际使用的tokens和模型价格计算
        // - 如果是RMB类型，将元转换为积分（1元=100积分）
        BigDecimal finalAmount = calculateReleaseAmount(accountReleaseDto, accountFrozen);
        
        // 6. 执行释放时的账户更新
        // - 扣减账户的冻结金额
        // - 如果有实际扣减金额，更新账户余额
        doUpdateAccountForRelease(account, accountFrozen, finalAmount);
        
        // 7. 创建交易流水记录
        // 当有实际扣减金额时，生成交易流水记录
        doCreateTransaction(accountFrozen, account, finalAmount);
        
        // 8. 执行冻结单终结
        // 更新冻结单状态为已终结，并记录最终扣减金额和使用情况
        return doFinalizeFrozen(accountFrozen, accountReleaseDto, finalAmount);
    }

    /**
     * 验证释放冻结单参数
     *
     * @param accountReleaseDto 冻结单释放DTO
     */
    private void validateReleaseParams(AccountReleaseDto accountReleaseDto) {
        if (accountReleaseDto == null) {
            throw new BizException(ResultCode.PARAMETER_EMPTY.getCode(), ResultCode.PARAMETER_EMPTY.getMessage());
        }
        if (accountReleaseDto.getFrozenId() == null) {
            throw new BizException(ResultCode.FROZEN_ID_EMPTY.getCode(), ResultCode.FROZEN_ID_EMPTY.getMessage());
        }
        
        // 注：释放冻结单时的frozenType需要从冻结单中获取，所以这里不做类型相关的校验
        // 具体的类型相关校验会在calculateReleaseAmount方法中处理
    }

    /**
     * 通过冻结单ID获取冻结单信息
     *
     * @param frozenId 冻结单ID
     * @return 冻结单信息
     */
    private AccountFrozen getFrozenById(String frozenId) {
        AccountFrozen accountFrozen = accountFrozenMapper.selectByPrimaryKey(frozenId);
        if (accountFrozen == null) {
            throw new BizException(ResultCode.FROZEN_NOT_EXIST.getCode(), ResultCode.FROZEN_NOT_EXIST.getMessage());
        }
        return accountFrozen;
    }

    /**
     * 验证冻结单状态是否为预留状态
     *
     * @param accountFrozen 冻结单信息
     */
    private void validateFrozenStatus(AccountFrozen accountFrozen) {
        if (!"RESERVED".equals(accountFrozen.getStatus())) {
            throw new BizException(ResultCode.FROZEN_STATUS_ERROR.getCode(), ResultCode.FROZEN_STATUS_ERROR.getMessage());
        }
    }

    /**
     * 根据冻结类型计算最终释放金额
     *
     * @param accountReleaseDto 冻结单释放DTO
     * @param accountFrozen 冻结单信息
     * @return 最终释放金额（单位：积分）
     */
    private BigDecimal calculateReleaseAmount(AccountReleaseDto accountReleaseDto, AccountFrozen accountFrozen) {
        BigDecimal finalAmount = accountReleaseDto.getFinalAmount() != null ?
                                 accountReleaseDto.getFinalAmount() : BigDecimal.ZERO;
        if (FROZEN_TYPE_TOKEN.equals(accountFrozen.getFrozenType())) {
            return calculateTokenReleaseAmount(accountReleaseDto, accountFrozen, finalAmount);
        } else if (FROZEN_TYPE_RMB.equals(accountFrozen.getFrozenType())) {
            return calculateRmbFrozenAmount(finalAmount);
        }
        return finalAmount;
    }

    /**
     * 计算token类型的释放金额
     * 根据实际使用的tokens和模型价格计算释放金额，并应用扣费系数
     *
     * @param accountReleaseDto 冻结单释放DTO
     * @param accountFrozen 冻结单信息
     * @param finalAmount 当前计算的最终金额
     * @return 计算后的释放金额（单位：积分）
     */
    private BigDecimal calculateTokenReleaseAmount(AccountReleaseDto accountReleaseDto, AccountFrozen accountFrozen,
                                                   BigDecimal finalAmount) {
        if (finalAmount.compareTo(BigDecimal.ZERO) != 0 ||
            accountReleaseDto.getUsageInputTokens() == null ||
            accountReleaseDto.getUsageOutputTokens() == null ||
            accountFrozen.getModelName() == null) {
            return finalAmount;
        }
        String modelName = normalizeModelName(accountFrozen.getModelName());
        List<ModelPrice> modelPriceList = getModelPriceList(modelName);
        if (modelPriceList.isEmpty()) {
            return finalAmount;
        }
        ModelPrice inputModelPrice = findInputModelPrice(modelPriceList, accountReleaseDto.getUsageInputTokens());
        ModelPrice outputModelPrice = findOutputModelPrice(modelPriceList, accountReleaseDto.getUsageOutputTokens());
        if (inputModelPrice == null || outputModelPrice == null) {
            return finalAmount;
        }
        long totalFee = calculateReleaseTokenFee(accountReleaseDto, inputModelPrice, outputModelPrice);
        BigDecimal baseAmount = BigDecimal.valueOf(totalFee);
        return baseAmount.multiply(accountDeductionProperties.getCoefficient());
    }

    /**
     * 计算释放时的token总费用
     *
     * @param accountReleaseDto 冻结单释放DTO
     * @param inputModelPrice 输入模型价格
     * @param outputModelPrice 输出模型价格
     * @return 总费用（单位：分）
     */
    private long calculateReleaseTokenFee(AccountReleaseDto accountReleaseDto,
                                          ModelPrice inputModelPrice, ModelPrice outputModelPrice) {
        long inputFee = calculateTokenFee(accountReleaseDto.getUsageInputTokens(), inputModelPrice.getInputPerCent());
        long outputFee = calculateTokenFee(accountReleaseDto.getUsageOutputTokens(), outputModelPrice.getOutputPerCent());
        return inputFee + outputFee;
    }

    /**
     * 执行释放时的账户更新
     * 包括扣减冻结金额和实际余额
     *
     * @param account 账户信息
     * @param accountFrozen 冻结单信息
     * @param finalAmount 最终扣减金额
     */
    private void doUpdateAccountForRelease(Account account, AccountFrozen accountFrozen, BigDecimal finalAmount) {
        BigDecimal frozenAmount = account.getFrozenAmount() == null ? BigDecimal.ZERO : account.getFrozenAmount();
        BigDecimal balance = account.getBalance() == null ? BigDecimal.ZERO : account.getBalance();
        account.setFrozenAmount(frozenAmount.subtract(accountFrozen.getFrozenAmount()));
        if (finalAmount.compareTo(BigDecimal.ZERO) > 0) {
            balance = calculateNewBalance(balance, finalAmount, accountFrozen.getFrozenAmount());
            account.setBalance(balance);
        }
        account.setUpdateTime(new Date());
        accountMapper.update(account);
    }

    /**
     * 计算释放后的新余额
     * 比较实际扣减金额和预扣减金额，取较大值进行扣减
     *
     * @param balance 当前余额
     * @param finalAmount 实际扣减金额
     * @param frozenAmount 预扣减金额
     * @return 新的余额
     */
    private BigDecimal calculateNewBalance(BigDecimal balance, BigDecimal finalAmount, BigDecimal frozenAmount) {
        BigDecimal amountToDeduct = finalAmount.compareTo(frozenAmount) > 0 ? finalAmount : frozenAmount;
        if (balance.compareTo(amountToDeduct) < 0) {
            return BigDecimal.ZERO;
        }
        return balance.subtract(amountToDeduct);
    }

    /**
     * 创建交易流水记录
     *
     * @param accountFrozen 冻结单信息
     * @param account 账户信息
     * @param finalAmount 最终扣减金额
     */
    private void doCreateTransaction(AccountFrozen accountFrozen, Account account, BigDecimal finalAmount) {
        BigDecimal beforeBalance = account.getBalance() == null ? BigDecimal.ZERO : account.getBalance();
        AccountTransaction transaction = buildTransaction(accountFrozen, account, finalAmount, beforeBalance);
        accountTransactionMapper.insert(transaction);
    }

    /**
     * 构建交易流水对象
     *
     * @param accountFrozen 冻结单信息
     * @param account 账户信息
     * @param finalAmount 最终扣减金额
     * @param beforeBalance 扣减前余额
     * @return 交易流水对象
     */
    private AccountTransaction buildTransaction(AccountFrozen accountFrozen, Account account,
                                                 BigDecimal finalAmount, BigDecimal beforeBalance) {
        AccountTransaction transaction = new AccountTransaction();
        transaction.setUserId(accountFrozen.getUserId());
        transaction.setUserName(account.getUserName());
        transaction.setTransactionType(3);
        transaction.setAmount(finalAmount);
        transaction.setBeforeBalance(beforeBalance);
        BigDecimal afterBalance = beforeBalance.subtract(finalAmount);
        if (afterBalance.compareTo(BigDecimal.ZERO) < 0) {
            afterBalance = BigDecimal.ZERO;
        }
        transaction.setAfterBalance(afterBalance);
        transaction.setStatus(1);
        transaction.setTransactionNo(IDUtils.getSnowflakeIdStr());
        transaction.setPayType(3);
        transaction.setBusinessType("frozen_release");
        transaction.setRemark("冻结单释放扣减: " + accountFrozen.getFrozenId());
        transaction.setIsExpense(1);
        if (Objects.nonNull(accountFrozen.getQuestion())) {
            transaction.setQuestion(accountFrozen.getQuestion());
        }
        if (Objects.nonNull(accountFrozen.getCallId())) {
            transaction.setCallId(accountFrozen.getCallId());
        }
        if (accountFrozen.getFrozenType().equals(FROZEN_TYPE_TOKEN) &&
            accountFrozen.getModelName() != null) {
            if (accountFrozen.getUsageInputTokens() != null) {
                transaction.setInputToken(accountFrozen.getUsageInputTokens().intValue());
            }
            if (accountFrozen.getUsageOutputTokens() != null) {
                transaction.setOutputToken(accountFrozen.getUsageOutputTokens().intValue());
            }
            if (accountFrozen.getUsageTotalTokens() != null) {
                transaction.setTotalTokens(accountFrozen.getUsageTotalTokens().intValue());
            }
            transaction.setModelName(accountFrozen.getModelName());
        }
        transaction.setCreateTime(new Date());
        transaction.setUpdateTime(new Date());
        return transaction;
    }

    /**
     * 执行冻结单终结
     * 更新冻结单状态为已终结
     *
     * @param accountFrozen 冻结单信息
     * @param accountReleaseDto 冻结单释放DTO
     * @param finalAmount 最终扣减金额
     * @return 冻结单信息
     */
    private AccountFrozen doFinalizeFrozen(AccountFrozen accountFrozen, AccountReleaseDto accountReleaseDto,
                                            BigDecimal finalAmount) {
        accountFrozen.setFinalAmount(finalAmount);
        accountFrozen.setUsageInputTokens(accountReleaseDto.getUsageInputTokens());
        accountFrozen.setUsageOutputTokens(accountReleaseDto.getUsageOutputTokens());
        accountFrozen.setUsageTotalTokens(accountReleaseDto.getUsageTotalTokens());
        accountFrozen.setFinalizeReason(accountReleaseDto.getFinalizeReason());
        accountFrozen.setStatus("FINALIZED");
        accountFrozen.setUpdateTime(new Date());
        accountFrozenMapper.updateByPrimaryKey(accountFrozen);
        return accountFrozen;
    }

    /**
     * 根据ID查询冻结单
     *
     * @param frozenId 冻结单ID
     * @return 冻结单信息
     */
    @Override
    public AccountFrozen getByFrozenId(String frozenId) {
        return accountFrozenMapper.selectByPrimaryKey(frozenId);
    }

    /**
     * 根据会话ID查询冻结单
     *
     * @param sessionId 会话ID
     * @return 冻结单信息
     */
    @Override
    public AccountFrozen getBySessionId(String sessionId) {
        return accountFrozenMapper.selectBySessionId(sessionId);
    }

}