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.entity.dto.AccountTransactionDto;
import com.kexue.skills.entity.dto.ConsumptionGroupedDto;
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.service.PackageConfigService;
import com.kexue.skills.entity.ModelPrice;
import com.kexue.skills.entity.PackageConfig;
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.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

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

    @Resource
    private AccountTransactionMapper accountTransactionMapper;

    @Resource
    private ModelPriceService modelPriceService;

    @Resource
    private PackageConfigService packageConfigService;

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

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

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

    /**
     * 通过用户ID查询账户
     *
     * @param userId 用户ID
     * @return 实例对象
     */
    @Override
    public Account queryByUserId(Long userId) {
        return 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);
        }
        // 保存数据
        accountMapper.insert(account);
        return account;
    }

    /**
     * 更新数据
     *
     * @param account 实例对象
     * @return 实例对象
     */
    @Override
    public Account update(Account account) {
        // 设置更新时间
        account.setUpdateTime(new Date());
        // 更新数据
        accountMapper.update(account);
        return 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 = 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);
            insert(account);
        }

        // 2. 计算积分
        BigDecimal points = BigDecimal.ZERO;
        String rechargeRemark = "";
        
        // 检查是否有套餐ID
        if (businessId != null) {
            // 查询套餐配置
            PackageConfig packageConfig = packageConfigService.queryById(businessId);
            if (packageConfig != null) {
                // 套餐的baseAmount和giftAmount已经是积分，直接使用
                points = packageConfig.getBaseAmount().add(packageConfig.getGiftAmount());
                // 根据套餐信息生成remark
                rechargeRemark = "购买套餐：" + packageConfig.getName() + "，获得" + points + "积分";
            } else {
                // 没有找到套餐，按照原来的逻辑计算积分
                points = amount.multiply(BigDecimal.valueOf(100));
                rechargeRemark = "充值" + amount + "元，获得" + points + "积分";
            }
        } else {
            // 没有套餐ID，按照原来的逻辑计算积分
            points = amount.multiply(BigDecimal.valueOf(100));
            rechargeRemark = "充值" + amount + "元，获得" + points + "积分";
        }

        // 3. 保存交易记录
        AccountTransaction transaction = new AccountTransaction();
        transaction.setUserId(userId);
        transaction.setUserName(account.getUserName());
        transaction.setTransactionType(1); // 充值
        transaction.setAmount(points); // 存储充值金额（积分）
        transaction.setBeforeBalance(account.getBalance());
        transaction.setAfterBalance(account.getBalance().add(points)); // 余额为积分
        transaction.setStatus(1); // 成功
        transaction.setTransactionNo(transactionNo);
        transaction.setPayType(3); // 余额支付
        transaction.setBusinessId(businessId);// 套餐ID
        transaction.setBusinessType(businessType);
        
        // 添加额外备注
        if (remark != null && !remark.isEmpty()) {
            rechargeRemark += " - " + remark;
        }
        transaction.setRemark(rechargeRemark);
        transaction.setIsExpense(0); // 收入
        transaction.setIncomeType("recharge"); // 充值
        accountTransactionMapper.insert(transaction);

        // 4. 更新账户余额（使用积分）
        if (isWithdrawable) {
            BigDecimal withdrawableBalance = account.getWithdrawableBalance() == null ? BigDecimal.ZERO : account.getWithdrawableBalance();
            account.setWithdrawableBalance(withdrawableBalance.add(points));
        } else {
            BigDecimal nonWithdrawableBalance = account.getNonWithdrawableBalance() == null ? BigDecimal.ZERO : account.getNonWithdrawableBalance();
            account.setNonWithdrawableBalance(nonWithdrawableBalance.add(points));
        }
        BigDecimal balance = account.getBalance() == null ? BigDecimal.ZERO : account.getBalance();
        account.setBalance(balance.add(points));
        account.setUpdateTime(new Date());
        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 = 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); // 支出
        accountTransactionMapper.insert(transaction);

        // 4. 更新账户余额
        return 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 = queryByUserId(userId);
        Assert.notNull(account, "账户不存在");

        // 2. 查询输入token的价格规则（输入token使用默认的standard模式）
        String inputOutputMode = "standard";
        ModelPrice inputModelPrice = modelPriceService.queryByModelNameAndOutputModeAndTokens(dto.getModelName(), inputOutputMode, Long.valueOf(dto.getInputToken()));
        Assert.notNull(inputModelPrice, "输入token价格信息不存在");

        // 3. 查询输出token的价格规则
        String outputMode = dto.getOutputMode() != null ? dto.getOutputMode() : "standard";
        ModelPrice outputModelPrice = modelPriceService.queryByModelNameAndOutputModeAndTokens(dto.getModelName(), outputMode, Long.valueOf(dto.getOutputToken()));
        Assert.notNull(outputModelPrice, "输出token价格信息不存在");

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

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

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

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

        // 6. 保存交易记录
        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());
        accountTransactionMapper.insert(transaction);

        // 7. 更新账户余额
        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(), "问题不能为空");
    }

    /**
     * 增加账户积分（签到奖励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 = 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);
            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);
        // 在备注中添加积分信息
        String signInRemark = "签到奖励" + amount + "积分";
        if (remark != null && !remark.isEmpty()) {
            signInRemark += " - " + remark;
        }
        transaction.setRemark(signInRemark);
        transaction.setIsExpense(0); // 收入
        transaction.setIncomeType("sign_in"); // 签到奖励
        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());
        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 = 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);
            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);
        // 在备注中添加积分信息
        String giftRemark = "赠送" + amount + "积分";
        if (remark != null && !remark.isEmpty()) {
            giftRemark += " - " + remark;
        }
        transaction.setRemark(giftRemark);
        transaction.setIsExpense(0); // 收入
        transaction.setIncomeType("gift"); // 赠送
        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());
        update(account);
        return 1;
    }

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

    /**
     * 通过主键物理删除
     *
     * @param accountId 主键
     * @return 影响行数
     */
    @Override
    public int deleteById(Long accountId) {
        return accountMapper.deleteById(accountId);
    }
    
    /**
     * 获取用户交易记录
     *
     * @param userId 用户ID
     * @return 交易记录列表
     */
    @Override
    public List<com.kexue.skills.entity.AccountTransaction> getTransactions(Long userId) {
        return accountTransactionMapper.queryByUserId(userId);
    }
    
    /**
     * 分页查询充值记录
     *
     * @param queryDto 查询条件
     * @return 分页结果
     */
    @Override
    public PageInfo<AccountTransaction> getRechargePageList(AccountTransactionDto queryDto) {
        PageHelper.startPage(queryDto.getPageNum(), queryDto.getPageSize());
        List<AccountTransaction> list = accountTransactionMapper.getRechargePageList(queryDto);
        return new PageInfo<>(list);
    }
    
    /**
     * 分页查询消费记录（按callId分组）
     *
     * @param queryDto 查询条件
     * @return 分页结果
     */
    @Override
    public PageInfo<ConsumptionGroupedDto> getConsumptionGroupedPageList(AccountTransactionDto queryDto) {
        int pageNum = queryDto.getPageNum() == null || queryDto.getPageNum() < 1 ? 1 : queryDto.getPageNum();
        int pageSize = queryDto.getPageSize() == null || queryDto.getPageSize() < 1 ? 10 : queryDto.getPageSize();

        log.info("开始查询消费记录（内存分组模式），参数：pageNum={}, pageSize={}, userId={}", pageNum, pageSize, queryDto.getUserId());

        // 1. 查询所有原始数据（不分页，获取全量）
        List<AccountTransaction> rawList = accountTransactionMapper.getConsumptionRawList(queryDto);
        if (rawList == null || rawList.isEmpty()) {
            return new PageInfo<>(new ArrayList<>());
        }

        // 2. 内存分组与聚合
        // 使用 LinkedHashMap 保持按 callId 首次出现的顺序（即按时间倒序）
        Map<String, ConsumptionGroupedDto> groupedMap = new LinkedHashMap<>();

        for (AccountTransaction tx : rawList) {
            // 处理 callId 为 null 或空字符串的情况，使用 transactionId 作为唯一标识
            String callId = tx.getCallId();
            if (callId == null || callId.isEmpty()) {
                callId = "tx_" + tx.getTransactionId();
            }
            ConsumptionGroupedDto group = groupedMap.get(callId);

            if (group == null) {
                // 第一次遇到该 callId，创建新组
                group = new ConsumptionGroupedDto();
                // 复制基础信息
                group.setTransactionId(tx.getTransactionId());
                group.setUserId(tx.getUserId());
                group.setUserName(tx.getUserName());
                group.setTransactionType(tx.getTransactionType());
                group.setBeforeBalance(tx.getBeforeBalance());
                group.setAfterBalance(tx.getAfterBalance());
                group.setStatus(tx.getStatus());
                group.setTransactionNo(tx.getTransactionNo());
                group.setPayType(tx.getPayType());
                group.setBusinessId(tx.getBusinessId());
                group.setBusinessType(tx.getBusinessType());
                group.setCallId(tx.getCallId());
                group.setRemark(tx.getRemark());
                group.setIsExpense(tx.getIsExpense());
                group.setModelName(tx.getModelName());
                group.setQuestion(tx.getQuestion());
                group.setIncomeType(tx.getIncomeType());
                group.setCreateTime(tx.getCreateTime());
                group.setUpdateTime(tx.getUpdateTime());
                group.setCreateBy(tx.getCreateBy());
                group.setUpdateBy(tx.getUpdateBy());
                group.setDeleteFlag(tx.getDeleteFlag());
                // 初始化聚合字段
                group.setAmount(BigDecimal.ZERO);
                group.setInputToken(0);
                group.setOutputToken(0);
                group.setTotalTokens(0);
                groupedMap.put(callId, group);
            }

            // 累加数值字段
            if (tx.getAmount() != null) {
                group.setAmount(group.getAmount().add(tx.getAmount()));
            }
            if (tx.getInputToken() != null) {
                group.setInputToken(group.getInputToken() + tx.getInputToken());
            }
            if (tx.getOutputToken() != null) {
                group.setOutputToken(group.getOutputToken() + tx.getOutputToken());
            }
            if (tx.getTotalTokens() != null) {
                group.setTotalTokens(group.getTotalTokens() + tx.getTotalTokens());
            }
        }

        List<ConsumptionGroupedDto> allGroupedList = new ArrayList<>(groupedMap.values());
        log.info("分组聚合完成，总组数：{}", allGroupedList.size());

        // 3. 内存分页
        int total = allGroupedList.size();
        int fromIndex = (pageNum - 1) * pageSize;
        int toIndex = Math.min(fromIndex + pageSize, total);

        List<ConsumptionGroupedDto> pageList = fromIndex < total ? allGroupedList.subList(fromIndex, toIndex) : new ArrayList<>();

        // 4. 构建 PageInfo
        PageInfo<ConsumptionGroupedDto> pageInfo = new PageInfo<>(pageList);
        pageInfo.setTotal((long) total);
        pageInfo.setPageNum(pageNum);
        pageInfo.setPageSize(pageSize);
        pageInfo.setPages((total + pageSize - 1) / pageSize);

        log.info("分页成功：total={}, pages={}, 当前页数据量={}", total, pageInfo.getPages(), pageList.size());
        return pageInfo;
    }


    /**
     * 分页查询赠送记录
     *
     * @param queryDto 查询条件
     * @return 分页结果
     */
    @Override
    public PageInfo<AccountTransaction> getGiftPageList(AccountTransactionDto queryDto) {
        PageHelper.startPage(queryDto.getPageNum(), queryDto.getPageSize());
        List<AccountTransaction> list = accountTransactionMapper.getGiftPageList(queryDto);
        return new PageInfo<>(list);
    }
}