package com.spot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spot.entity.MemberWallet;
import com.spot.mapper.MemberWalletMapper;
import com.spot.service.MemberWalletService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**
 * 会员资金钱包服务实现类
 *
 * @author jean
 * @date 2026-05-08
 */
@Slf4j
@Service
public class MemberWalletServiceImpl extends ServiceImpl<MemberWalletMapper, MemberWallet>
        implements MemberWalletService {

    @Autowired
    private MemberWalletMapper memberWalletMapper;

    /**
     * 根据会员ID和币种查询钱包
     *
     * @param memberId 会员ID
     * @param coinId   币种标识
     * @return 钱包对象，不存在返回 null
     */
    @Override
    public MemberWallet getByMemberIdAndCoinId(Long memberId, String coinId) {
        return getOne(new LambdaQueryWrapper<MemberWallet>()
                .eq(MemberWallet::getMemberId, memberId)
                .eq(MemberWallet::getCoinId, coinId)
                .last(" LIMIT 1"));
    }

    /**
     * 获取或初始化资金钱包
     * INSERT IGNORE：返回1表示新增成功，0表示钱包已存在
     *
     * @param memberId 会员ID
     * @param coinId   币种标识
     * @return 钱包对象
     */
    @Override
    public MemberWallet getOrCreateWallet(Long memberId, String coinId) {
        // INSERT IGNORE：并发安全，只有一条 INSERT 成功
        int inserted = memberWalletMapper.insertOrIgnore(memberId, coinId);
        if (inserted > 0) {
            // 新增成功，构建零余额钱包返回，无需再查库
            MemberWallet wallet = new MemberWallet();
            wallet.setMemberId(memberId);
            wallet.setCoinId(coinId);
            wallet.setBalance(BigDecimal.ZERO);
            wallet.setFrozenBalance(BigDecimal.ZERO);
            wallet.setToReleased(BigDecimal.ZERO);
            wallet.setIsLock(0);
            wallet.setVersion(0);
            return wallet;
        }
        // 钱包已存在，查库获取最新数据
        return getByMemberIdAndCoinId(memberId, coinId);
    }

    /**
     * 扣减可用余额（乐观锁保护，失败后自动重试一次）
     *
     * @param memberId 会员ID
     * @param coinId   币种标识
     * @param amount   扣减金额
     * @return 更新行数；0 表示持续冲突或余额不足或钱包已锁定
     */
    @Override
    public int deductBalance(Long memberId, String coinId, BigDecimal amount) {
        // 1. 查询当前钱包获取版本号
        MemberWallet wallet = getByMemberIdAndCoinId(memberId, coinId);
        if (wallet == null) {
            log.warn("资金钱包不存在，无法扣减 - MemberId: {}, CoinId: {}", memberId, coinId);
            return 0;
        }

        // 2. 带版本号执行扣减（乐观锁）
        int rows = memberWalletMapper.deductBalance(memberId, coinId, amount, wallet.getVersion());

        // 3. 乐观锁冲突时重试一次（刷新版本号后再扣）
        if (rows == 0) {
            log.warn("资金钱包扣减乐观锁冲突，重试 - MemberId: {}, CoinId: {}, Version: {}",
                    memberId, coinId, wallet.getVersion());
            wallet = getByMemberIdAndCoinId(memberId, coinId);
            if (wallet != null) {
                rows = memberWalletMapper.deductBalance(memberId, coinId, amount, wallet.getVersion());
            }
        }
        return rows;
    }

    /**
     * 增加可用余额
     *
     * @param memberId 会员ID
     * @param coinId   币种标识
     * @param amount   增加金额
     * @return 更新行数；0 表示钱包不存在或已锁定
     */
    @Override
    public int addBalance(Long memberId, String coinId, BigDecimal amount) {
        return memberWalletMapper.addBalance(memberId, coinId, amount);
    }
}
