package com.bizzan.bitrade.dao;

import com.bizzan.bitrade.entity.ContractOrderEntrust;
import com.bizzan.bitrade.entity.ContractOrderEntrustStatus;
import com.bizzan.bitrade.entity.ContractOrderEntrustType;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

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

public interface ContractOrderEntrustRepository extends JpaRepository<ContractOrderEntrust, Long>, JpaSpecificationExecutor<ContractOrderEntrust>, QueryDslPredicateExecutor<ContractOrderEntrust> {
    @Transactional(rollbackFor = Exception.class)
    @Modifying
    @Query("update ContractOrderEntrust contract set contract.status = :status where contract.id = :eid")
    void updateStatus(@Param("eid") Long eid, @Param("status") ContractOrderEntrustStatus status);
    
    @Transactional(rollbackFor = Exception.class)
    @Modifying
    @Query("update ContractOrderEntrust contract set contract.status = :status, contract.dealTime = :dealTime where contract.id = :eid")
    void updateStatusAndDealTime(@Param("eid") Long eid, @Param("status") ContractOrderEntrustStatus status, @Param("dealTime") Long dealTime);
    
    @Transactional(rollbackFor = Exception.class)
    @Modifying
    @Query("update ContractOrderEntrust contract set contract.status = :status, contract.dealTime = :dealTime, contract.openFee=0, contract.closeFee=0, contract.tradedPrice=0 where contract.id = :eid")
    void updateStatusAndDealTimeAndFee(@Param("eid") Long eid, @Param("status") ContractOrderEntrustStatus status, @Param("dealTime") Long dealTime);

    @Transactional(rollbackFor = Exception.class)
    @Modifying
    @Query("update ContractOrderEntrust contract set contract.usdtOpenPrice = :usdtOpenPrice where contract.positionId = :positionId and contract.status = :status and contract.entrustType = :entrustType")
    void updateUsdtOpenPrice(@Param("positionId") Long positionId, @Param("usdtOpenPrice") BigDecimal usdtOpenPrice, @Param("status") ContractOrderEntrustStatus status, @Param("entrustType") ContractOrderEntrustType entrustType);
    
    /**
     * 查询委托中的订单
     * @return
     */
    @Query("select a from  ContractOrderEntrust a where a.status = 0")
    List<ContractOrderEntrust> findAllNeedMatch();

    @Query("select a from  ContractOrderEntrust a where a.status = 0 and a.contractId = :contractId")
    List<ContractOrderEntrust> loadUnMatchOrders(@Param("contractId") Long contractId);
    
    @Query("select a from  ContractOrderEntrust a where a.status = 0 and a.type = 2 and a.entrustType=1")
    List<ContractOrderEntrust> findAllRunningCuts();
    
    @Query("select a from  ContractOrderEntrust a where a.positionId=:positionId and a.status = 0 and a.type = 2 and a.entrustType=1 and a.volume=0")
    List<ContractOrderEntrust> findPositionCuts(@Param("positionId") Long positionId);

    @Query("select a from  ContractOrderEntrust a where a.status = 0 and a.contractId = :contractId and a.memberId = :memberId")
    List<ContractOrderEntrust> findAllByMemberIdAndContractId(long memberId, Long contractCoinId);
    
    @Query("select a from  ContractOrderEntrust a where a.status = 0 and a.entrustType=0 and a.contractId = :contractCoinId and a.memberId = :memberId")
    List<ContractOrderEntrust> findOpenByMemberIdAndContractId(@Param("memberId") long memberId,@Param("contractCoinId") Long contractCoinId);
    
    @Query(value="select a.* from contract_order_entrust a where a.contract_id = :contractCoinId and a.member_id = :memberId and direction=:direction and (a.status = 0 or a.status = 3) and entrust_type=0 order by id desc limit 1", nativeQuery=true)
    ContractOrderEntrust getLatestInOppositeDirection(@Param("memberId") long memberId, @Param("contractCoinId") Long contractCoinId, @Param("direction") int direction);
    
    @Query("select count(distinct memberId) as total from  ContractOrderEntrust a where a.createTime between :startDate and :endDate")
    int countActiveMembersByDate(@Param("startDate") Long startDate, @Param("endDate") Long endDate);
    
    @Query("select count(distinct memberId) as total from  ContractOrderEntrust a where a.createTime between :startDate and :endDate and a.memberId in (:ids)")
    int countActiveMembersByMemberIdsAndTime(@Param("startDate") Long startDate, @Param("endDate") Long endDate,@Param("ids") List<Long> ids);
    
    @Query(value="select sum(a.volume) as total from contract_order_entrust a where a.contract_id = :contractCoinId and a.member_id = :memberId and a.status = 0 and entrust_type=0", nativeQuery=true)
    BigDecimal sumVolumeByMemberIdAndContractCoinId(@Param("memberId") long memberId, @Param("contractCoinId") Long contractCoinId);
    
    @Query("select sum(a.principalAmount) as total from  ContractOrderEntrust a where a.status = 3 and a.memberId in (:ids)")
    BigDecimal sumPrincipalAmountByMemberIds(@Param("ids") List<Long> ids);
    
    @Query("select sum(a.profitAndLoss) as total from  ContractOrderEntrust a where a.closeType = 5 and a.positionId in (:ids)")
    BigDecimal sumBlastedLossByPositionIds(@Param("ids") List<Long> ids);

    @Query("select a from ContractOrderEntrust a where a.positionId in (:positionIds) and a.entrustType = com.bizzan.bitrade.entity.ContractOrderEntrustType.OPEN")
    List<ContractOrderEntrust> findOpenOrdersByPositionIds(@Param("positionIds") List<Long> positionIds);

    @Query(value="SELECT count(member_id) as order_count, sum(violate_time) as violate_count from contract_order_entrust where member_id=:memberId and create_time between :startTime and :endTime",nativeQuery = true)
	Object[][] statSupervised(@Param("memberId")Long memberId,@Param("startTime")Long startTime, @Param("endTime")Long endTime);
    
    @Query(value="SELECT member_id, count(member_id) as total_count from contract_order_entrust where follow_id is null and create_time between :startTime and :endTime group by member_id having total_count>=50",nativeQuery = true)
	Object[][] statFarming(@Param("startTime")String startTime, @Param("endTime")String endTime);
}
