package com.spot.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.spot.entity.Account;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.math.BigDecimal;
import java.util.List;

/**
 * 账户 Mapper 接口
 *
 * @author jean
 * @date 2026-05-06
 */
@Mapper
public interface AccountMapper extends BaseMapper<Account> {

    /**
     * 撤单退币：从冻结余额扣除，增加到可用余额（原子操作）
     *
     * @param accountId    账户ID
     * @param refundAmount 退还金额
     * @return 更新行数，0表示冻结余额不足
     */
    int refundFromFrozenToAvailable(@Param("accountId") Long accountId,
                                    @Param("refundAmount") BigDecimal refundAmount);

    /**
     * 扣除冻结余额
     *
     * @param accountId    账户ID
     * @param frozenAmount 扣除金额
     * @return 更新行数，0表示冻结余额不足
     */
    int deductFrozenBalance(@Param("accountId") Long accountId,
                            @Param("frozenAmount") BigDecimal frozenAmount);

    /**
     * 增加可用余额
     *
     * @param accountId       账户ID
     * @param availableAmount 增加金额
     * @return 更新行数
     */
    int addAvailableBalance(@Param("accountId") Long accountId,
                            @Param("availableAmount") BigDecimal availableAmount);

    /**
     * 增加冻结余额
     *
     * @param accountId    账户ID
     * @param frozenAmount 增加金额
     * @return 更新行数
     */
    int addFrozenBalance(@Param("accountId") Long accountId,
                         @Param("frozenAmount") BigDecimal frozenAmount);

    /**
     * 冻结金额：从可用余额扣除，增加到冻结余额（原子操作）
     *
     * @param accountId     账户ID
     * @param freezeAmount  冻结金额
     * @return 更新行数，0表示可用余额不足
     */
    int freezeFromAvailableToFrozen(@Param("accountId") Long accountId,
                                    @Param("freezeAmount") BigDecimal freezeAmount);

    /**
     * 扣除可用余额
     *
     * @param accountId       账户ID
     * @param availableAmount 扣除金额
     * @return 更新行数，0表示可用余额不足
     */
    int deductAvailableBalance(@Param("accountId") Long accountId,
                               @Param("availableAmount") BigDecimal availableAmount);

    /**
     * 从可用余额转到提现余额（原子操作）
     *
     * @param accountId      账户ID
     * @param withdrawAmount 提现金额
     * @return 更新行数，0表示可用余额不足
     */
    int freezeFromAvailableToWithdraw(@Param("accountId") Long accountId,
                                      @Param("withdrawAmount") BigDecimal withdrawAmount);

    /**
     * 初始化现货账户（INSERT IGNORE，账户已存在时静默跳过）
     * 用于划转时自动初始化首次使用的现货账户，并发安全。
     *
     * @param uid    用户ID
     * @param symbol 币种符号
     * @return 插入行数；0 表示账户已存在（正常情况）
     */
    int insertOrIgnore(@Param("uid") Long uid, @Param("symbol") String symbol);

    /**
     * 查询有冻结余额但无对应活跃委托的孤悬账户
     * <p>
     * 判断逻辑：
     * <ul>
     *   <li>BUY 方向委托冻结的是交易对的计价货币（quote），如 BTCUSDT 买单冻结 USDT</li>
     *   <li>SELL 方向委托冻结的是交易对的基础货币（base），如 BTCUSDT 卖单冻结 BTC</li>
     * </ul>
     * 活跃委托状态：INIT(0)、NEW(1)、PART_FILLED(3)、PENDING_CANCEL(5)
     *
     * @param batchSize 每批次最大返回行数
     * @return 无委托但有冻结余额的账户列表
     */
    List<Account> findFrozenAccountsWithoutOrders(@Param("batchSize") int batchSize);
}
