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.WithdrawalRecord;
import com.kexue.skills.entity.dto.WithdrawalRecordDto;
import com.kexue.skills.common.Assert;
import com.kexue.skills.exception.BizException;
import com.kexue.skills.mapper.WithdrawalRecordMapper;
import com.kexue.skills.service.AccountService;
import com.kexue.skills.service.WithdrawalRecordService;
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.Map;
import java.util.HashMap;
import java.util.UUID;

/**
 * 提现记录Service实现类
 *
 * @author 王志维
 * @since 2026-03-25
 */
@Service("withdrawalRecordService")
@Transactional(rollbackFor = Exception.class)
public class WithdrawalRecordServiceImpl implements WithdrawalRecordService {
    @Resource
    private WithdrawalRecordMapper withdrawalRecordMapper;

    @Resource
    private AccountService accountService;

    /**
     * 提现手续费比例
     */
    private static final BigDecimal FEE_RATE = new BigDecimal("0.02");

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

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

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

    /**
     * 通过用户ID查询提现记录
     *
     * @param userId 用户ID
     * @return 实例对象
     */
    @Override
    public List<WithdrawalRecord> queryByUserId(Long userId) {
        return this.withdrawalRecordMapper.queryByUserId(userId);
    }

    /**
     * 通过提现单号查询提现记录
     *
     * @param withdrawalNo 提现单号
     * @return 实例对象
     */
    @Override
    public WithdrawalRecord queryByWithdrawalNo(String withdrawalNo) {
        return this.withdrawalRecordMapper.queryByWithdrawalNo(withdrawalNo);
    }

    /**
     * 新增数据
     *
     * @param withdrawalRecord 实例对象
     * @return 实例对象
     */
    @Override
    public WithdrawalRecord insert(WithdrawalRecord withdrawalRecord) {
        // 设置创建时间和更新时间
        Date now = new Date();
        withdrawalRecord.setCreateTime(now);
        withdrawalRecord.setUpdateTime(now);
        // 设置默认值
        withdrawalRecord.setDeleteFlag(0);
        // 保存数据
        this.withdrawalRecordMapper.insert(withdrawalRecord);
        return withdrawalRecord;
    }

    /**
     * 更新数据
     *
     * @param withdrawalRecord 实例对象
     * @return 实例对象
     */
    @Override
    public WithdrawalRecord update(WithdrawalRecord withdrawalRecord) {
        // 设置更新时间
        withdrawalRecord.setUpdateTime(new Date());
        // 更新数据
        this.withdrawalRecordMapper.update(withdrawalRecord);
        return this.queryById(withdrawalRecord.getRecordId());
    }

    /**
     * 更新提现状态
     *
     * @param recordId 记录ID
     * @param status 状态
     * @return 影响行数
     */
    @Override
    public int updateStatus(Long recordId, Integer status) {
        Map<String, Object> params = new HashMap<>();
        params.put("recordId", recordId);
        params.put("status", status);
        return this.withdrawalRecordMapper.updateStatus(params);
    }

    /**
     * 通过主键逻辑删除
     *
     * @param recordId 主键
     * @param updateBy 更新人
     * @return 影响行数
     */
    @Override
    public int logicDeleteById(Long recordId, String updateBy) {
        Map<String, Object> params = new HashMap<>();
        params.put("recordId", recordId);
        return this.withdrawalRecordMapper.logicDeleteById(params);
    }

    /**
     * 通过主键物理删除
     *
     * @param recordId 主键
     * @return 影响行数
     */
    @Override
    public int deleteById(Long recordId) {
        return this.withdrawalRecordMapper.deleteById(recordId);
    }

    /**
     * 提交提现申请
     *
     * @param userId 用户ID
     * @param amount 提现金额
     * @param bankName 银行名称
     * @param bankAccount 银行账号
     * @param bankCardholder 持卡人姓名
     * @param remark 备注
     * @return 提现记录
     */
    @Override
    public WithdrawalRecord submitWithdrawal(Long userId, BigDecimal amount, String bankName, String bankAccount, String bankCardholder, String remark) {
        // 1. 查询账户信息
        Account account = accountService.queryByUserId(userId);
        Assert.notNull(account, "账户不存在");

        // 2. 检查可提现余额是否足够
        Assert.isTrue(account.getWithdrawableBalance().compareTo(amount) >= 0, "可提现余额不足");

        // 3. 计算手续费和实际到账金额
        BigDecimal feeAmount = amount.multiply(FEE_RATE);
        BigDecimal actualAmount = amount.subtract(feeAmount);

        // 4. 生成提现单号
        String withdrawalNo = generateWithdrawalNo();

        // 5. 创建提现记录
        WithdrawalRecord record = new WithdrawalRecord();
        record.setUserId(userId);
        record.setUserName(account.getUserName());
        record.setWithdrawalAmount(amount);
        record.setFeeAmount(feeAmount);
        record.setActualAmount(actualAmount);
        record.setStatus(1); // 1.待处理
        record.setWithdrawalNo(withdrawalNo);
        record.setBankName(bankName);
        record.setBankAccount(bankAccount);
        record.setBankCardholder(bankCardholder);
        record.setRemark(remark);
        record.setCreateTime(new Date());
        record.setUpdateTime(new Date());
        record.setDeleteFlag(0);
        this.withdrawalRecordMapper.insert(record);

        // 6. 冻结可提现余额
        account.setWithdrawableBalance(account.getWithdrawableBalance().subtract(amount));
        account.setFrozenAmount(account.getFrozenAmount().add(amount));
        account.setUpdateTime(new Date());
        accountService.update(account);

        return record;
    }

    /**
     * 处理提现
     *
     * @param recordId 记录ID
     * @param status 状态
     * @param remark 备注
     * @return 影响行数
     */
    @Override
    public int processWithdrawal(Long recordId, Integer status, String remark) {
        // 1. 查询提现记录
        WithdrawalRecord record = this.queryById(recordId);
        Assert.notNull(record, "提现记录不存在");

        // 2. 检查状态是否为待处理
        Assert.isTrue(record.getStatus() == 1, "提现记录状态不正确");

        // 3. 更新提现状态
        Map<String, Object> params = new HashMap<>();
        params.put("recordId", recordId);
        params.put("status", status);
        int result = this.withdrawalRecordMapper.updateStatus(params);

        // 4. 如果提现成功，减少可提现余额，增加冻结金额
        if (status == 3) { // 3.成功
            Account account = accountService.queryByUserId(record.getUserId());
            if (account != null) {
                // 减少冻结金额
                account.setFrozenAmount(account.getFrozenAmount().subtract(record.getWithdrawalAmount()));
                // 减少总余额
                account.setBalance(account.getBalance().subtract(record.getWithdrawalAmount()));
                account.setUpdateTime(new Date());
                accountService.update(account);
            }
        } else if (status == 4) { // 4.失败
            // 解冻金额
            Account account = accountService.queryByUserId(record.getUserId());
            if (account != null) {
                account.setFrozenAmount(account.getFrozenAmount().subtract(record.getWithdrawalAmount()));
                account.setWithdrawableBalance(account.getWithdrawableBalance().add(record.getWithdrawalAmount()));
                account.setUpdateTime(new Date());
                accountService.update(account);
            }
        }

        return result;
    }

    /**
     * 生成提现单号
     *
     * @return 提现单号
     */
    private String generateWithdrawalNo() {
        // 提现单号生成规则：W + 时间戳 + 6位随机数
        String timestamp = String.valueOf(System.currentTimeMillis());
        String random = UUID.randomUUID().toString().substring(0, 6).replaceAll("-", "");
        return "W" + timestamp + random;
    }
}