package com.bizzan.bitrade.dao;

import com.bizzan.bitrade.dao.base.BaseDao;
import com.bizzan.bitrade.entity.StakingOrder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 质押订单 DAO
 *
 * @author auto
 * @date 2026-05-17
 */
public interface StakingOrderDao extends BaseDao<StakingOrder> {

    /**
     * 查询用户质押订单，按创建时间倒序
     *
     * @param memberId 用户ID
     * @param pageable 分页参数
     * @return 质押订单分页
     */
    Page<StakingOrder> findByMemberIdOrderByCreateTimeDesc(Long memberId, Pageable pageable);

    /**
     * 查询用户指定状态的质押订单，按创建时间倒序
     *
     * @param memberId 用户ID
     * @param statuses 状态列表
     * @param pageable 分页参数
     * @return 质押订单分页
     */
    Page<StakingOrder> findByMemberIdAndStatusInOrderByCreateTimeDesc(Long memberId, List<Integer> statuses, Pageable pageable);

    /**
     * 查询锁定期已到且状态仍为"质押中"的订单（用于定时任务触发解冻）
     *
     * @param now 当前时间
     * @return 待解冻订单列表
     */
    @Query("from StakingOrder where status = 0 and unlockTime <= :now")
    List<StakingOrder> findOrdersToUnlock(@Param("now") Date now);

    /**
     * 按状态查询订单
     *
     * @param status 状态值
     * @return 订单列表
     */
    List<StakingOrder> findByStatus(Integer status);

    /**
     * 查询用户在某币种上的活跃质押剩余总量（质押中 + 释放中的未释放部分）
     *
     * @param memberId 用户ID
     * @param coinUnit 币种
     * @return 活跃质押剩余量
     */
    @Query("select coalesce(sum(o.amount - o.releasedAmount), 0) from StakingOrder o " +
           "where o.memberId = :memberId and o.coinUnit = :coinUnit and o.status in (0, 1)")
    BigDecimal sumActiveAmountByMemberIdAndCoinUnit(@Param("memberId") Long memberId,
                                                    @Param("coinUnit") String coinUnit);

    /**
     * 统计用户在某币种上历史累计已释放总量
     */
    @Query("select coalesce(sum(o.releasedAmount), 0) from StakingOrder o " +
           "where o.memberId = :memberId and upper(o.coinUnit) = upper(:coinUnit)")
    BigDecimal sumReleasedAmountByMemberIdAndCoinUnit(@Param("memberId") Long memberId,
                                                      @Param("coinUnit") String coinUnit);

    /**
     * 统计平台某币种当前总活跃质押量（供按比例空投计算分母）
     *
     * @param coinUnit 币种
     * @return 平台总活跃质押量
     */
    @Query("select coalesce(sum(o.amount - o.releasedAmount), 0) from StakingOrder o " +
           "where o.coinUnit = :coinUnit and o.status in (0, 1)")
    BigDecimal sumTotalActiveAmountByCoinUnit(@Param("coinUnit") String coinUnit);

    /**
     * 将订单状态更新为解冻释放中
     *
     * @param id 订单ID
     * @return 影响行数
     */
    @Transactional
    @Modifying
    @Query("update StakingOrder o set o.status = 1 where o.id = :id")
    int updateStatusToReleasing(@Param("id") Long id);

    /**
     * 更新订单已释放金额，若全部释放则自动标记为已完成
     *
     * @param id          订单ID
     * @param amount      本次释放金额
     * @param releaseTime 本次释放时间
     * @return 影响行数
     */
    @Transactional
    @Modifying
    @Query("update StakingOrder o set " +
           "o.releasedAmount = o.releasedAmount + :amount, " +
           "o.lastReleaseTime = :releaseTime, " +
           "o.status = case when (o.amount - o.releasedAmount - :amount) <= 0 then 2 else o.status end " +
           "where o.id = :id")
    int updateReleasedAmount(@Param("id") Long id,
                             @Param("amount") BigDecimal amount,
                             @Param("releaseTime") Date releaseTime);

    /**
     * 检查用户是否有活跃质押（用于空投资格校验）
     *
     * @param memberId 用户ID
     * @return 是否有活跃质押
     */
    @Query("select count(o) > 0 from StakingOrder o where o.memberId = :memberId and o.status in (0, 1)")
    boolean existsActiveStakingByMemberId(@Param("memberId") Long memberId);
}
