package com.bizzan.bitrade.dao;

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 com.bizzan.bitrade.dao.base.BaseDao;
import com.bizzan.bitrade.entity.ContractMoneyType;
import com.bizzan.bitrade.entity.ContractPositionType;
import com.bizzan.bitrade.entity.UserPurse;

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

public interface UserPurseDao extends BaseDao<UserPurse> {

    /**
     * 增加钱包余额
     *
     * @param walletId
     * @param amount
     * @return
     */
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.balance = purse.balance + :amount where purse.id = :id")
    int increaseBalance(@Param("id") long id, @Param("amount") BigDecimal amount);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.balance = 0 where purse.id = :id and purse.balance<0")
    int restoreMinusBalance(@Param("id") long id);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.balance = 0 where purse.id = :id")
    int zeroBalance(@Param("id") long id);

    /**
     * 减少钱包余额
     *
     * @param walletId
     * @param amount
     * @return
     */
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.balance = purse.balance - :amount where purse.id = :id and purse.balance>=:amount")
    int decreaseBalance(@Param("id") long id, @Param("amount") BigDecimal amount);

    /**
     * 冻结钱包余额
     *
     * @param walletId
     * @param amount
     * @return
     */
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.balance = purse.balance - :amount,purse.frozenBalance=purse.frozenBalance + :amount where purse.id = :id and purse.balance >= :amount")
    int freezeBalance(@Param("id") long id, @Param("amount") BigDecimal amount);

    /**
     * 解冻钱包余额
     *
     * @param walletId
     * @param amount
     * @return
     */
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.balance = purse.balance + :amount,purse.frozenBalance=purse.frozenBalance - :amount where purse.id = :id and purse.frozenBalance >= :amount")
    int thawBalance(@Param("id") long id, @Param("amount") BigDecimal amount);

    /**
     * 减少冻结余额
     *
     * @param walletId
     * @param amount
     * @return
     */
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.frozenBalance=purse.frozenBalance - :amount where purse.id = :id and purse.frozenBalance >= :amount")
    int decreaseFrozen(@Param("id") long id, @Param("amount") BigDecimal amount);

    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.eUsdtAddress = :eUsdtAddress, purse.tUsdtAddress = :tUsdtAddress where purse.id = :id")
    int updateAddress(@Param("id") long id, @Param("eUsdtAddress") String eUsdtAddress, @Param("tUsdtAddress") String tUsdtAddress);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.balance = purse.balance - :amount,purse.frozenMargin=purse.frozenMargin + :amount where purse.id = :id and purse.balance >= :amount")
    int freezeMargin(@Param("id") long id, @Param("amount") BigDecimal amount);

    /**
     * 批量直接开仓专用：balance -= total（principal+fee），frozen_balance += principal，跳过 frozen_margin 中转。
     */
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.balance = purse.balance - :total, purse.frozenBalance = purse.frozenBalance + :principal where purse.id = :id and purse.balance >= :total")
    int freezeBalanceDirect(@Param("id") long id, @Param("total") BigDecimal total, @Param("principal") BigDecimal principal);
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.balance = purse.balance + :amount,purse.frozenMargin=purse.frozenMargin - :amount where purse.id = :id and purse.frozenMargin >= :amount")
    int thawMargin(@Param("id") long id, @Param("amount") BigDecimal amount);
    @Transactional
    @Modifying
    @Query(value = "update user_purse purse set purse.balance = purse.balance+:amount+(if(purse.frozen_balance-:amount<0,purse.frozen_balance-:amount,0)),purse.frozen_balance=purse.frozen_balance-:amount-(if(purse.frozen_balance-:amount<0,purse.frozen_balance-:amount,0)) where purse.id = :id",nativeQuery =true)
    int releaseMargin(@Param("id") long id, @Param("amount") BigDecimal amount);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.frozenBalance=purse.frozenBalance+:margin, purse.frozenMargin=purse.frozenMargin - :margin - :fee where purse.id = :id")
    int clearOpenFee(@Param("id") long id, @Param("margin") BigDecimal margin, @Param("fee") BigDecimal fee);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.balance=purse.balance - :amount where purse.id = :id")
    int clearCloseFee(@Param("id") long id, @Param("amount") BigDecimal amount);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.balance=purse.balance - :amount where purse.id = :id and purse.balance>:amount")
    int clearContractOvernightFee(@Param("id") long id, @Param("amount") BigDecimal amount);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.leverage=:leverage, purse.balance = purse.balance + :marginDifference,purse.frozenBalance=purse.frozenBalance - :marginDifference where purse.id = :id and purse.balance+:marginDifference>=0")
    int modifyLeverage(@Param("id") long id, @Param("leverage") BigDecimal leverage, @Param("marginDifference") BigDecimal marginDifference);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.balance = purse.balance + :marginDifference,purse.frozenBalance=purse.frozenBalance - :marginDifference where purse.id = :id")
    int adjustMargin(@Param("id") long id, @Param("marginDifference") BigDecimal marginDifference);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.positionType=:positionType where purse.id = :id")
    int modifyPositionType(@Param("id") long id, @Param("positionType") ContractPositionType positionType);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.moneyType=:moneyType where purse.id = :id")
    int modifyMoneyType(@Param("id") long id, @Param("moneyType") ContractMoneyType moneyType);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.leverage=:leverage,purse.positionType=:positionType,purse.moneyType=:moneyType where purse.id = :id")
    int modifyConfig(@Param("id") long id, @Param("leverage") BigDecimal leverage, @Param("positionType") ContractPositionType positionType, @Param("moneyType") ContractMoneyType moneyType);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.eUsdtAddress=:address where purse.id = :id")
    int updateEUsdtAddress(@Param("id") long id, @Param("address") String address);
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.tUsdtAddress=:address where purse.id = :id")
    int updateTUsdtAddress(@Param("id") long id, @Param("address") String address);
    
    @Transactional
    @Modifying
    @Query("update UserPurse purse set purse.isSupervised = :isSupervised where purse.id = :id")
    int updateIsSupervised(@Param("id") long id, @Param("isSupervised") int isSupervised);
    
    @Query(value = "select is_supervised from user_purse purse where purse.id = :id",nativeQuery =true)
    Integer getIsSupervised(@Param("id") long id);
    
    @Query(value = "select purse.balance+purse.frozen_balance+purse.frozen_margin as allBalance from user_purse purse where purse.id = :id",nativeQuery =true)
    BigDecimal getBalanceById(@Param("id") long id);
    
    @Query("from UserPurse where size(currentPositionList)>0")
    List<UserPurse> findAllWithPositions();
    
    @Query("from UserPurse where id in (:ids)")
    List<UserPurse> findByIds(@Param("ids") List<Long> ids);
    
    UserPurse findUserPurseByEUsdtAddressOrTUsdtAddress(String eUsdtAddress, String tUsdtAddress);
    
    @Query(value = "select sum(a.balance+a.frozen_balance+a.frozen_margin) as allBalance from user_purse a where a.id<>1",nativeQuery =true)
    BigDecimal sumBalance();
    
    @Query(value = "select sum(a.balance+a.frozen_balance+a.frozen_margin) as allBalance from user_purse a where a.id=:memberId",nativeQuery =true)
    BigDecimal sumBalanceByMemberId(@Param("memberId") Long memberId);
    
    @Query(value = "select sum(a.balance+a.frozen_balance+a.frozen_margin) as allBalance from user_purse a where a.id in (:ids)",nativeQuery =true)
    BigDecimal sumBalanceByMemberIds(@Param("ids") List<Long> ids);
    
    @Query(value = "select count(*) as allCount from user_purse a where a.id in (:ids) and a.balance+a.frozen_balance+a.frozen_margin>0",nativeQuery =true)
    long countWithBalanceByMemberIds(@Param("ids") List<Long> ids);
    
    @Query(value = "select a.id from user_purse a where a.is_supervised=1",nativeQuery =true)
    List<BigInteger> findIdListByIsSupervised();

}
