package com.kexue.skills.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.entity.Account;
import com.kexue.skills.entity.AccountTransaction;
import com.kexue.skills.entity.SysUser;
import com.kexue.skills.entity.dto.AccountDto;
import com.kexue.skills.common.Assert;
import com.kexue.skills.entity.dto.TokenConsumptionDto;
import com.kexue.skills.exception.BizException;
import com.kexue.skills.mapper.AccountMapper;
import com.kexue.skills.mapper.AccountTransactionMapper;
import com.kexue.skills.mapper.SysUserMapper;
import com.kexue.skills.service.AccountService;
import com.kexue.skills.service.ModelPriceService;
import com.kexue.skills.entity.ModelPrice;
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;

/**
 * (Account)表服务实现类
 *
 * @author 王志维
 * @since 2025-02-21 23:01:48
 */
@Service("accountService")
@Transactional(rollbackFor = Exception.class)
public class AccountServiceImpl implements AccountService {
    @Resource
    private AccountMapper accountMapper;
    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private AccountTransactionMapper accountTransactionMapper;

    @Resource
    private ModelPriceService modelPriceService;

    /**
     * 分页查询
     *
     * @param queryDto 筛选条件
     * @return 查询结果
     */
    @Override
    public PageInfo<Account> getPageList(AccountDto queryDto) {
        PageHelper.startPage(queryDto.getPageNum(), queryDto.getPageSize());
        List<Account> list = this.accountMapper.getPageList(queryDto);
        return new PageInfo<>(list);
    }

    /**
     * 查询列表
     *
     * @param queryDto 筛选条件
     * @return 查询结果
     */
    @Override
    public List<Account> getList(AccountDto queryDto) {
        return this.accountMapper.getList(queryDto);
    }

    /**
     * 通过主键查询单条数据
     *
     * @param accountId 主键
     * @return 实例对象
     */
    @Override
    public Account queryById(Long accountId) {
        return this.accountMapper.queryById(accountId);
    }

    /**
     * 通过用户ID查询账户
     *
     * @param userId 用户ID
     * @return 实例对象
     */
    @Override
    public Account queryByUserId(Long userId) {
        return this.accountMapper.queryByUserId(userId);
    }

    /**
     * 新增数据
     *
     * @param account 实例对象
     * @return 实例对象
     */
    @Override
    public Account insert(Account account) {
        // 设置创建时间和更新时间
        Date now = new Date();
        account.setCreateTime(now);
        account.setUpdateTime(now);
        // 设置默认值
        account.setDeleteFlag(0);
        if (account.getBalance() == null) {
            account.setBalance(BigDecimal.ZERO);
        }
        if (account.getWithdrawableBalance() == null) {
            account.setWithdrawableBalance(BigDecimal.ZERO);
        }
        if (account.getNonWithdrawableBalance() == null) {
            account.setNonWithdrawableBalance(BigDecimal.ZERO);
        }
        if (account.getFrozenAmount() == null) {
            account.setFrozenAmount(BigDecimal.ZERO);
        }
        // 保存数据
        this.accountMapper.insert(account);
        return account;
    }

    /**
     * 更新数据
     *
     * @param account 实例对象
     * @return 实例对象
     */
    @Override
    public Account update(Account account) {
        // 设置更新时间
        account.setUpdateTime(new Date());
        // 更新数据
        this.accountMapper.update(account);
        return this.queryById(account.getAccountId());
    }

    /**
     * 增加账户余额
     *
     * @param userId 用户ID
     * @param amount 增加金额
     * @param isWithdrawable 是否可提现
     * @param transactionNo 交易单号
     * @param businessId 业务ID
     * @param businessType 业务类型
     * @param remark 备注
     * @return 影响行数
     */
    @Override
    public int addBalance(Long userId, BigDecimal amount, boolean isWithdrawable, String transactionNo, Long businessId, String businessType, String remark) {
        // 1. 查询账户信息
        Account account = this.queryByUserId(userId);
        if (account == null) {
            // 创建账户
            account = new Account();
            account.setUserId(userId);
            account.setBalance(BigDecimal.ZERO);
            account.setWithdrawableBalance(BigDecimal.ZERO);
            account.setNonWithdrawableBalance(BigDecimal.ZERO);
            account.setFrozenAmount(BigDecimal.ZERO);
            this.insert(account);
        }

        // 2. 保存交易记录
        AccountTransaction transaction = new AccountTransaction();
        transaction.setUserId(userId);
        transaction.setUserName(account.getUserName());
        transaction.setTransactionType(1); // 充值
        transaction.setAmount(amount);
        transaction.setBeforeBalance(account.getBalance());
        transaction.setAfterBalance(account.getBalance().add(amount));
        transaction.setStatus(1); // 成功
        transaction.setTransactionNo(transactionNo);
        transaction.setPayType(3); // 余额支付
        transaction.setBusinessId(businessId);
        transaction.setBusinessType(businessType);
        transaction.setRemark(remark);
        transaction.setIsExpense(0); // 收入
        transaction.setIncomeType("recharge"); // 充值
        this.accountTransactionMapper.insert(transaction);

        // 3. 更新账户余额
        if (isWithdrawable) {
            BigDecimal withdrawableBalance = account.getWithdrawableBalance() == null ? BigDecimal.ZERO : account.getWithdrawableBalance();
            account.setWithdrawableBalance(withdrawableBalance.add(amount));
        } else {
            BigDecimal nonWithdrawableBalance = account.getNonWithdrawableBalance() == null ? BigDecimal.ZERO : account.getNonWithdrawableBalance();
            account.setNonWithdrawableBalance(nonWithdrawableBalance.add(amount));
        }
        BigDecimal balance = account.getBalance() == null ? BigDecimal.ZERO : account.getBalance();
        account.setBalance(balance.add(amount));
        account.setUpdateTime(new Date());
        this.update(account);
        return 1;
    }

    /**
     * 增加账户余额（默认不可提现）
     *
     * @param userId 用户ID
     * @param amount 增加金额
     * @param transactionNo 交易单号
     * @param businessId 业务ID
     * @param businessType 业务类型
     * @param remark 备注
     * @return 影响行数
     */
    @Override
    public int addBalance(Long userId, BigDecimal amount, String transactionNo, Long businessId, String businessType, String remark) {
        return addBalance(userId, amount, false, transactionNo, businessId, businessType, remark);
    }

    /**
     * 减少账户余额
     *
     * @param userId 用户ID
     * @param amount 减少金额
     * @param transactionNo 交易单号
     * @param businessId 业务ID
     * @param businessType 业务类型
     * @param remark 备注
     * @return 影响行数
     */
    @Override
    public int reduceBalance(Long userId, BigDecimal amount, String transactionNo, Long businessId, String businessType, String remark) {
        // 1. 查询账户信息
        Account account = this.queryByUserId(userId);
        Assert.notNull(account, "账户不存在");

        // 2. 检查余额是否足够
        BigDecimal balance = account.getBalance() == null ? BigDecimal.ZERO : account.getBalance();
        Assert.isTrue(balance.compareTo(amount) >= 0, "账户余额不足");

        // 3. 保存交易记录
        AccountTransaction transaction = new AccountTransaction();
        transaction.setUserId(userId);
        transaction.setUserName(account.getUserName());
        transaction.setTransactionType(3); // 购买内容
        transaction.setAmount(amount);
        transaction.setBeforeBalance(account.getBalance());
        transaction.setAfterBalance(account.getBalance().subtract(amount));
        transaction.setStatus(1); // 成功
        transaction.setTransactionNo(transactionNo);
        transaction.setPayType(3); // 余额支付
        transaction.setBusinessId(businessId);
        transaction.setBusinessType(businessType);
        transaction.setRemark(remark);
        transaction.setIsExpense(1); // 支出
        this.accountTransactionMapper.insert(transaction);

        // 4. 更新账户余额
        return this.accountMapper.updateBalance(userId, amount, 2);
    }

    /**
     * 减少账户余额（token消费转换）
     * @return 消耗的金额
     */
    @Override
    public BigDecimal reduceBalanceWithToken(TokenConsumptionDto dto) {
        validate(dto);
        // 1. 查询账户信息
        Long userId = null ;//根据会话ID查询用户ID
        SysUser bySessionId = sysUserMapper.getBySessionId(dto.getSessionId());
        if(bySessionId == null){
            throw new BizException("会话ID不存在");
        }
        userId = bySessionId.getUserId();
        Account account = this.queryByUserId(userId);
        Assert.notNull(account, "账户不存在");

        // 2. 查询模型价格信息
        ModelPrice modelPrice = modelPriceService.queryByModelName(dto.getModelName());
        Assert.notNull(modelPrice, "模型价格信息不存在");

        // 3. 计算金额
        // 输入token费用：输入token数量 / inputPerCent，不足1分按1分计算
        long inputFee = dto.getInputToken() / modelPrice.getInputPerCent();
        if (dto.getInputToken() % modelPrice.getInputPerCent() > 0) {
            inputFee += 1;
        }

        // 输出token费用：输出token数量 / outputPerCent，不足1分按1分计算
        long outputFee = dto.getOutputToken() / modelPrice.getOutputPerCent();
        if (dto.getOutputToken() % modelPrice.getOutputPerCent() > 0) {
            outputFee += 1;
        }

        // 总费用（分）
        long totalFee = inputFee + outputFee;
        // 转换为元
        BigDecimal amount = BigDecimal.valueOf(totalFee).divide(BigDecimal.valueOf(100));

        // 4. 检查余额是否足够
        BigDecimal balance = account.getBalance() == null ? BigDecimal.ZERO : account.getBalance();
        Assert.isTrue(balance.compareTo(amount) >= 0, "账户余额不足");

        // 5. 保存交易记录
        AccountTransaction transaction = new AccountTransaction();
        transaction.setUserId(userId);
        transaction.setUserName(account.getUserName());
        transaction.setTransactionType(3); // 购买内容
        transaction.setAmount(amount);
        transaction.setBeforeBalance(account.getBalance());
        transaction.setAfterBalance(account.getBalance().subtract(amount));
        transaction.setStatus(1); // 成功
        transaction.setTransactionNo(dto.getTransactionNo());
        transaction.setPayType(3); // 余额支付
        transaction.setRemark(dto.getRemark());
        transaction.setIsExpense(1); // 支出
        transaction.setInputToken(dto.getInputToken());
        transaction.setOutputToken(dto.getOutputToken());
        transaction.setTotalTokens(dto.getTotalTokens());
        transaction.setModelName(dto.getModelName());
        transaction.setQuestion(dto.getQuestion());
        this.accountTransactionMapper.insert(transaction);

        // 6. 更新账户余额
        this.accountMapper.updateBalance(userId, amount, 2);
        return amount;
    }

    void validate(TokenConsumptionDto dto) {
        Assert.notNull(dto, "参数不能为空");
        Assert.notNull(dto.getSessionId(), "会话ID不能为空");
        Assert.notNull(dto.getQuestion(), "问题不能为空");
        Assert.notNull(dto.getModelName(), "模型名称不能为空");
        Assert.notNull(dto.getQuestion(), "问题不能为空");
        Assert.notNull(dto.getModelName(), "模型名称不能为空");
        Assert.notNull(dto.getQuestion(), "问题不能为空");
    }

    /**
     * 增加账户余额（签到奖励token转换）
     *
     * @param userId 用户ID
     * @param amount 增加金额
     * @param transactionNo 交易单号
     * @param businessId 业务ID
     * @param businessType 业务类型
     * @param remark 备注
     * @return 影响行数
     */
    @Override
    public int addSignInBalance(Long userId, BigDecimal amount, String transactionNo, Long businessId, String businessType, String remark) {
        // 1. 查询账户信息
        Account account = this.queryByUserId(userId);
        if (account == null) {
            // 创建账户
            account = new Account();
            account.setUserId(userId);
            account.setBalance(BigDecimal.ZERO);
            account.setWithdrawableBalance(BigDecimal.ZERO);
            account.setNonWithdrawableBalance(BigDecimal.ZERO);
            account.setFrozenAmount(BigDecimal.ZERO);
            this.insert(account);
        }

        // 2. 保存交易记录
        AccountTransaction transaction = new AccountTransaction();
        transaction.setUserId(userId);
        transaction.setUserName(account.getUserName());
        transaction.setTransactionType(5); // 签到奖励
        transaction.setAmount(amount);
        transaction.setBeforeBalance(account.getBalance());
        transaction.setAfterBalance(account.getBalance().add(amount));
        transaction.setStatus(1); // 成功
        transaction.setTransactionNo(transactionNo);
        transaction.setPayType(3); // 余额支付
        transaction.setBusinessId(businessId);
        transaction.setBusinessType(businessType);
        transaction.setRemark(remark);
        transaction.setIsExpense(0); // 收入
        transaction.setIncomeType("sign_in"); // 签到奖励
        this.accountTransactionMapper.insert(transaction);

        // 3. 更新账户余额（签到奖励不可提现）
        BigDecimal nonWithdrawableBalance = account.getNonWithdrawableBalance() == null ? BigDecimal.ZERO : account.getNonWithdrawableBalance();
        account.setNonWithdrawableBalance(nonWithdrawableBalance.add(amount));
        BigDecimal balance = account.getBalance() == null ? BigDecimal.ZERO : account.getBalance();
        account.setBalance(balance.add(amount));
        account.setUpdateTime(new Date());
        this.update(account);
        return 1;
    }

    /**
     * 给用户赠送金额（不可提现）
     *
     * @param userId 用户ID
     * @param amount 赠送金额
     * @param transactionNo 交易单号
     * @param businessId 业务ID
     * @param businessType 业务类型
     * @param remark 备注
     * @return 影响行数
     */
    @Override
    public int addGiftBalance(Long userId, BigDecimal amount, String transactionNo, Long businessId, String businessType, String remark) {
        // 1. 查询账户信息
        Account account = this.queryByUserId(userId);
        if (account == null) {
            // 创建账户
            account = new Account();
            account.setUserId(userId);
            account.setBalance(BigDecimal.ZERO);
            account.setWithdrawableBalance(BigDecimal.ZERO);
            account.setNonWithdrawableBalance(BigDecimal.ZERO);
            account.setFrozenAmount(BigDecimal.ZERO);
            this.insert(account);
        }

        // 2. 保存交易记录
        AccountTransaction transaction = new AccountTransaction();
        transaction.setUserId(userId);
        transaction.setUserName(account.getUserName());
        transaction.setTransactionType(6); // 赠送
        transaction.setAmount(amount);
        transaction.setBeforeBalance(account.getBalance());
        transaction.setAfterBalance(account.getBalance().add(amount));
        transaction.setStatus(1); // 成功
        transaction.setTransactionNo(transactionNo);
        transaction.setPayType(3); // 余额支付
        transaction.setBusinessId(businessId);
        transaction.setBusinessType(businessType);
        transaction.setRemark(remark);
        transaction.setIsExpense(0); // 收入
        transaction.setIncomeType("gift"); // 赠送
        this.accountTransactionMapper.insert(transaction);

        // 3. 更新账户余额（赠送金额不可提现）
        if (account.getNonWithdrawableBalance() == null){
            account.setNonWithdrawableBalance(BigDecimal.ZERO);
        }
        account.setNonWithdrawableBalance(account.getNonWithdrawableBalance().add(amount));
        if (account.getBalance() == null){
            account.setBalance(BigDecimal.ZERO);
        }
        account.setBalance(account.getBalance().add(amount));
        account.setUpdateTime(new Date());
        this.update(account);
        return 1;
    }

    /**
     * 通过主键逻辑删除
     *
     * @param accountId 主键
     * @param updateBy 更新人
     * @return 影响行数
     */
    @Override
    public int logicDeleteById(Long accountId, String updateBy) {
        return this.accountMapper.logicDeleteById(accountId, updateBy);
    }

    /**
     * 通过主键物理删除
     *
     * @param accountId 主键
     * @return 影响行数
     */
    @Override
    public int deleteById(Long accountId) {
        return this.accountMapper.deleteById(accountId);
    }
    
    /**
     * 获取用户交易记录
     *
     * @param userId 用户ID
     * @return 交易记录列表
     */
    @Override
    public List<com.kexue.skills.entity.AccountTransaction> getTransactions(Long userId) {
        return this.accountTransactionMapper.queryByUserId(userId);
    }
}