package com.bizzan.bitrade.service;

import com.alibaba.fastjson.JSON;
import com.bizzan.bitrade.constant.PageModel;
import com.bizzan.bitrade.dao.ContractOrderEntrustRepository;
import com.bizzan.bitrade.entity.*;
import com.bizzan.bitrade.entity.form.OrderQueryForm;
import com.bizzan.bitrade.pagination.Criteria;
import com.bizzan.bitrade.pagination.Restrictions;
import com.bizzan.bitrade.service.Base.BaseService;
import com.bizzan.bitrade.vo.OrderFarmingVo;
import com.bizzan.bitrade.vo.OrderStatVo;
import com.querydsl.core.types.Predicate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class ContractOrderEntrustService  extends BaseService {
    @Autowired
    private LocaleMessageSourceService msService;

    @Autowired
    private ContractOrderEntrustRepository contractOrderEntrustRepository;

    public Page<ContractOrderEntrust> findAll(Predicate predicate, Pageable pageable) {
        return contractOrderEntrustRepository.findAll(predicate, pageable);
    }
    public ContractOrderEntrust save(ContractOrderEntrust order) {
        return contractOrderEntrustRepository.saveAndFlush(order);
    }
    /**
     * 查询所有需要处理的委托
     * @return
     */
    public List<ContractOrderEntrust> findAllNeedMatch() {
        return contractOrderEntrustRepository.findAllNeedMatch();
    }

    /**
     * 查询指定币种某一个用户正在委托的订单(包含开仓订单和平仓订单）
     * @param memberId
     * @param pattern
     * @return
     */
    public long queryEntrustingOrdersCountByContractCoinIdAndPattern(Long memberId, Long contractCoinId, ContractOrderPattern pattern) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
        specification.add(Restrictions.eq("contractId", contractCoinId, false));
        specification.add(Restrictions.eq("patterns", pattern, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));

        return contractOrderEntrustRepository.count(specification);
    }

    /**
     * 查询指定币种某一个用户正在委托的订单(包含开仓订单和平仓订单）
     * @param memberId
     * @param contractCoinId
     * @return
     */
    public long queryEntrustingOrdersCountByContractCoinId(Long memberId, Long contractCoinId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
        specification.add(Restrictions.eq("contractId", contractCoinId, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));

        return contractOrderEntrustRepository.count(specification);
    }

    /**
     * 查找指定仓位模式开仓中的委托订单（仅查询开仓中的订单）- 指定币种
     * @param memberId
     * @return
     */
    public List<ContractOrderEntrust> queryEntrustOpeningOrdersBySymbol(Long memberId, Long contractCoinId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
        specification.add(Restrictions.eq("contractId", contractCoinId, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.OPEN, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        return contractOrderEntrustRepository.findAll(specification);
    }
    
    public List<ContractOrderEntrust> queryEntrustCutOrdersBySymbol(Long memberId, Long contractCoinId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
        specification.add(Restrictions.eq("contractId", contractCoinId, false));
        specification.add(Restrictions.eq("isCut", 1, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.CLOSE, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        return contractOrderEntrustRepository.findAll(specification);
    }
    
    public List<ContractOrderEntrust> queryEntrustCutOrdersByPositionId(Long positionId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("positionId", positionId, false));
        specification.add(Restrictions.eq("isCut", 1, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.CLOSE, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        return contractOrderEntrustRepository.findAll(specification);
    }
    
    public List<ContractOrderEntrust> querySuccessCutOrdersByPositionId(Long positionId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("positionId", positionId, false));
        specification.add(Restrictions.eq("isCut", 1, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.CLOSE, false));
        //specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_SUCCESS, false));
        return contractOrderEntrustRepository.findAll(specification);
    }
    
    public List<ContractOrderEntrust> queryOrdersByPositionId(Long positionId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("positionId", positionId, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.OPEN, false));
        //specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_SUCCESS, false));
        return contractOrderEntrustRepository.findAll(specification);
    }

    /**
     * 批量查询多个仓位的开仓委托，返回 positionId -> followSystemId 映射
     */
    public Map<Long, Long> queryFollowSystemIdsByPositionIds(List<Long> positionIds) {
        if (positionIds == null || positionIds.isEmpty()) return Collections.emptyMap();
        List<ContractOrderEntrust> orders = contractOrderEntrustRepository.findOpenOrdersByPositionIds(positionIds);
        Map<Long, Long> result = new HashMap<>();
        for (ContractOrderEntrust o : orders) {
            if (o.getPositionId() != null && o.getFollowSystemId() != null) {
                result.putIfAbsent(o.getPositionId(), o.getFollowSystemId());
            }
        }
        return result;
    }

    /**
     * 查找指定仓位模式平仓中的委托订单（仅查询平仓中的订单）- 指定币种
     * @param memberId
     * @return
     */
    public List<ContractOrderEntrust> queryEntrustClosingOrdersBySymbolAndDirection(Long memberId, String symbol, ContractOrderDirection direction) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
        specification.add(Restrictions.eq("symbol", symbol, false));
        specification.add(Restrictions.eq("direction", direction, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.CLOSE, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        return contractOrderEntrustRepository.findAll(specification);
    }

    /**
     * 查询所有开仓中的订单
     * @param memberId
     * @return
     */
    public List<ContractOrderEntrust> queryAllEntrustOpeningOrders(Long memberId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.OPEN, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        return contractOrderEntrustRepository.findAll(specification);
    }
    
    public List<ContractOrderEntrust> queryEntrustingOrdersByMemeberId(Long memberId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        return contractOrderEntrustRepository.findAll(specification);
    }

    /**
     * 查询用户当前体验金 ENTRUST_ING 委托单（不在撮合引擎内存队列中，需单独从数据库查询用于前端展示）
     *
     * @param memberId       用户ID
     * @param contractCoinId 合约交易对ID，为 null 时查全部
     * @return 体验金委托单列表
     */
    public List<ContractOrderEntrust> queryEntrustingExperienceOrders(Long memberId, Long contractCoinId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        specification.add(Restrictions.isNotNull("experienceRecordId", null, false));
        if (contractCoinId != null) {
            specification.add(Restrictions.eq("contractId", contractCoinId, false));
        }
        return contractOrderEntrustRepository.findAll(specification);
    }
    /**
     * 根据合约ID查询所有平中的订单
     * @param memberId
     * @return
     */
    public List<ContractOrderEntrust> queryAllEntrustClosingOrdersByContractCoin(Long memberId, Long contractId, ContractOrderDirection direction) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
        specification.add(Restrictions.eq("contractId", contractId, false));
        specification.add(Restrictions.eq("direction", direction, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.CLOSE, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        return contractOrderEntrustRepository.findAll(specification);
    }
    public List<ContractOrderEntrust> queryAllEntrustClosingOrdersByPositionId(Long positionId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("positionId", positionId, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.CLOSE, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        return contractOrderEntrustRepository.findAll(specification);
    }
    public List<ContractOrderEntrust> queryAllEntrustLimitClosingOrdersByPositionId(Long positionId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("positionId", positionId, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.CLOSE, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        specification.add(Restrictions.eq("type", ContractOrderType.LIMIT_PRICE, false));
        return contractOrderEntrustRepository.findAll(specification);
    }
    public List<ContractOrderEntrust> queryAllEntrustMarketClosingOrdersByPositionId(Long positionId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("positionId", positionId, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.CLOSE, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        specification.add(Restrictions.eq("type", ContractOrderType.MARKET_PRICE, false));
        return contractOrderEntrustRepository.findAll(specification);
    }
    public List<ContractOrderEntrust> queryAllEntrustCutOrdersByPositionId(Long positionId) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("positionId", positionId, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.CLOSE, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        specification.add(Restrictions.eq("type", ContractOrderType.SPOT_LIMIT, false));
        return contractOrderEntrustRepository.findAll(specification);
    }
    /**
     * 查询指定用户指定币种当前所有开仓委托
     * @param memberId
     * @param symbol
     * @return
     */
    public List<ContractOrderEntrust> queryAllEntrustOpeningOrdersBySymbol(Long memberId, String symbol) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();

        specification.add(Restrictions.eq("memberId", memberId, false));
        specification.add(Restrictions.eq("symbol", symbol, false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.OPEN, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        return contractOrderEntrustRepository.findAll(specification);
    }

    /**
     * 查询指定用户指定币种当前所有开仓委托(分页)
     * @param memberId
     * @param contractCoinId
     * @return
     */
    public Page<ContractOrderEntrust> queryPageEntrustingOrdersBySymbol(Long memberId, Long contractCoinId, int pageNo, int pageSize) {

        Sort orders = new Sort(new Sort.Order(Sort.Direction.DESC, "createTime"));
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();

        PageRequest pageRequest = new PageRequest(pageNo - 1, pageSize, orders);

        specification.add(Restrictions.eq("memberId", memberId, false));
        if(contractCoinId!=null)
        	specification.add(Restrictions.eq("contractId", contractCoinId, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));

        return contractOrderEntrustRepository.findAll(specification, pageRequest);
    }
    
    /**
     * 查询指定用户指定币种指定类型当前所有开仓委托(分页)
     * @param memberId
     * @param contractCoinId
     * @return
     */
    public Page<ContractOrderEntrust> queryPageEntrustingOrdersBySymbolAndType(Long memberId, Long contractCoinId, int type, int pageNo, int pageSize) {

        Sort orders = new Sort(new Sort.Order(Sort.Direction.DESC, "createTime"));
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();

        PageRequest pageRequest = new PageRequest(pageNo - 1, pageSize, orders);

        specification.add(Restrictions.eq("memberId", memberId, false));
        if(contractCoinId!=null)
        	specification.add(Restrictions.eq("contractId", contractCoinId, false));
        if(type==3) {
        	specification.add(Restrictions.or(Restrictions.eq("type", 0, false),Restrictions.eq("type", 1, false)));
        } else {
        	specification.add(Restrictions.eq("type", type, false));
        }
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));

        return contractOrderEntrustRepository.findAll(specification, pageRequest);
    }
    
    public Page<ContractOrderEntrust> queryPageEntrustingOpenOrdersBySymbolAndType(Long memberId, Long contractCoinId, int type, int pageNo, int pageSize) {

        Sort orders = new Sort(new Sort.Order(Sort.Direction.DESC, "createTime"));
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();

        PageRequest pageRequest = new PageRequest(pageNo - 1, pageSize, orders);

        specification.add(Restrictions.eq("memberId", memberId, false));
        if(contractCoinId!=null)
        	specification.add(Restrictions.eq("contractId", contractCoinId, false));
        if(type==3) {
        	specification.add(Restrictions.or(Restrictions.eq("type", 0, false),Restrictions.eq("type", 1, false)));
        } else {
        	specification.add(Restrictions.eq("type", type, false));
        }
        specification.add(Restrictions.eq("entrustType", 0, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_ING, false));

        return contractOrderEntrustRepository.findAll(specification, pageRequest);
    }

    /**
     * 查询指定用户指定币种所有历史委托(分页)
     * @param memberId
     * @return
     */
    public Page<ContractOrderEntrust> queryPageEntrustHistoryOrdersBySymbol(Long memberId, Long contractCoinId, int pageNo, int pageSize) {

        Sort orders = new Sort(new Sort.Order(Sort.Direction.DESC, "createTime"));
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();

        PageRequest pageRequest = new PageRequest(pageNo - 1, pageSize, orders);

        specification.add(Restrictions.eq("memberId", memberId, false));
        if(contractCoinId!=null)
        	specification.add(Restrictions.eq("contractId", contractCoinId, false));
        specification.add(Restrictions.ne("status", ContractOrderEntrustStatus.ENTRUST_ING, false));

        return contractOrderEntrustRepository.findAll(specification, pageRequest);
    }
    
    public Page<ContractOrderEntrust> queryPageEntrustHistoryCloseOrdersBySymbol(Long memberId, Long contractCoinId, ContractOrderEntrustType entrustType, int pageNo, int pageSize) {

        Sort orders = new Sort(new Sort.Order(Sort.Direction.DESC, "createTime"));
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();

        PageRequest pageRequest = new PageRequest(pageNo - 1, pageSize, orders);

        specification.add(Restrictions.eq("memberId", memberId, false));
        if(contractCoinId!=null)
        	specification.add(Restrictions.eq("contractId", contractCoinId, false));
        specification.add(Restrictions.eq("entrustType", entrustType, false));
        specification.add(Restrictions.ne("status", ContractOrderEntrustStatus.ENTRUST_ING, false));

        return contractOrderEntrustRepository.findAll(specification, pageRequest);
    }
    
    //获取历史记录
    public Page<ContractOrderEntrust> queryPageEntrustHistoryOrders(OrderQueryForm orderQueryForm, PageModel pageModel) {
    	if (pageModel.getProperty() == null) {
            List<String> list = new ArrayList<>();
            list.add("createTime");
            List<Sort.Direction> directions = new ArrayList<>();
            directions.add(Sort.Direction.DESC);
            pageModel.setProperty(list);
            pageModel.setDirection(directions);
        }
        //Sort orders = new Sort(new Sort.Order(Sort.Direction.DESC, "createTime"));
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        //int pageNo = pageModel.getPageNo();
        //int pageSize = pageModel.getPageSize();

        //PageRequest pageRequest = new PageRequest(pageNo - 1, pageSize, orders);

        specification.add(Restrictions.eq("memberId", orderQueryForm.getMemberId(), false));
        specification.add(Restrictions.eq("entrustType", ContractOrderEntrustType.CLOSE, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_SUCCESS, false));
        specification.add(Restrictions.isNull("followId"));
        if(orderQueryForm.getOpenType()!=null && !orderQueryForm.getOpenType().equals("")) {
        	String type = orderQueryForm.getOpenType().trim();
        	if(type.charAt(0) == '[') {
        		List<Integer> typeList = JSON.parseArray(type, Integer.class);
        		specification.add(Restrictions.in("openType", typeList, false));
        	} else
        		specification.add(Restrictions.eq("openType", Integer.valueOf(type), false));
        }
        if(orderQueryForm.getCloseType()!=null && !orderQueryForm.getCloseType().equals("")) {
        	String closeType = orderQueryForm.getCloseType().trim();
        	if(closeType.charAt(0) == '[') {
        		List<Integer> closeTypeList = JSON.parseArray(closeType, Integer.class);
        		specification.add(Restrictions.in("closeType", closeTypeList, false));
        	} else
        		specification.add(Restrictions.eq("closeType", Integer.valueOf(closeType), false));
        }

        return contractOrderEntrustRepository.findAll(specification, pageModel.getPageable());
    }
    
    //获取委托记录
    public Page<ContractOrderEntrust> queryPageEntrustOrders(OrderQueryForm orderQueryForm, PageModel pageModel) {

    	if (pageModel.getProperty() == null) {
            List<String> list = new ArrayList<>();
            list.add("createTime");
            List<Sort.Direction> directions = new ArrayList<>();
            directions.add(Sort.Direction.DESC);
            pageModel.setProperty(list);
            pageModel.setDirection(directions);
        }
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();

        //PageRequest pageRequest = new PageRequest(pageNo - 1, pageSize, orders);

        specification.add(Restrictions.eq("memberId", orderQueryForm.getMemberId(), false));
        specification.add(Restrictions.ne("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        specification.add(Restrictions.isNull("followId"));
        specification.add(Restrictions.or(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_CANCEL, false)
                ,Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_FAILURE, false)
        		,Restrictions.eq("entrustType", ContractOrderEntrustType.OPEN, false)));
        if(orderQueryForm.getOpenType()!=null && !orderQueryForm.getOpenType().equals("")) {
        	String type = orderQueryForm.getOpenType().trim();
        	if(type.charAt(0) == '[') {
        		List<Integer> typeList = JSON.parseArray(type, Integer.class);
        		specification.add(Restrictions.in("openType", typeList, false));
        	} else
        		specification.add(Restrictions.eq("openType", Integer.valueOf(type), false));
        }
        if(orderQueryForm.getCloseType()!=null && !orderQueryForm.getCloseType().equals("")) {
        	if(orderQueryForm.getCloseType().equals("4")) {
        		specification.add(Restrictions.or(Restrictions.gt("profitPrice", 0, false)
                        ,Restrictions.gt("lossPrice", 0, false)));
        	}
        }

        return contractOrderEntrustRepository.findAll(specification, pageModel.getPageable());
    }

    // 获取历史开仓+历史平仓合并记录
    public Page<ContractOrderEntrust> queryPageEntrustHistoryAllOrders(OrderQueryForm orderQueryForm, PageModel pageModel) {
        if (pageModel.getProperty() == null) {
            List<String> list = new ArrayList<>();
            list.add("createTime");
            List<Sort.Direction> directions = new ArrayList<>();
            directions.add(Sort.Direction.DESC);
            pageModel.setProperty(list);
            pageModel.setDirection(directions);
        }
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", orderQueryForm.getMemberId(), false));
        specification.add(Restrictions.isNull("followId"));
        specification.add(Restrictions.ne("status", ContractOrderEntrustStatus.ENTRUST_ING, false));
        if (orderQueryForm.getOpenType() != null && !orderQueryForm.getOpenType().equals("")) {
            String type = orderQueryForm.getOpenType().trim();
            if (type.charAt(0) == '[') {
                List<Integer> typeList = JSON.parseArray(type, Integer.class);
                specification.add(Restrictions.in("openType", typeList, false));
            } else {
                specification.add(Restrictions.eq("openType", Integer.valueOf(type), false));
            }
        }
        if (orderQueryForm.getCloseType() != null && !orderQueryForm.getCloseType().equals("")) {
            String closeType = orderQueryForm.getCloseType().trim();
            if (closeType.charAt(0) == '[') {
                List<Integer> closeTypeList = JSON.parseArray(closeType, Integer.class);
                specification.add(Restrictions.in("closeType", closeTypeList, false));
            } else {
                specification.add(Restrictions.eq("closeType", Integer.valueOf(closeType), false));
            }
        }
        return contractOrderEntrustRepository.findAll(specification, pageModel.getPageable());
    }

    public ContractOrderEntrust findOne(Long entrustId) {
        return contractOrderEntrustRepository.findOne(entrustId);
    }

    public void updateStatus(Long id, ContractOrderEntrustStatus status) {
        contractOrderEntrustRepository.updateStatus(id, status);
    }
    
    public void updateStatusAndDealTime(Long id, ContractOrderEntrustStatus status, Long dealTime) {
    	if(status == ContractOrderEntrustStatus.ENTRUST_CANCEL || status == ContractOrderEntrustStatus.ENTRUST_FAILURE)
    		contractOrderEntrustRepository.updateStatusAndDealTimeAndFee(id, status, dealTime);
    	else
    		contractOrderEntrustRepository.updateStatusAndDealTime(id, status, dealTime);
    }

    public List<ContractOrderEntrust> loadUnMatchOrders(Long id) {
        return contractOrderEntrustRepository.loadUnMatchOrders(id);
    }
    
    public List<ContractOrderEntrust> findAllRunningCuts() {
        return contractOrderEntrustRepository.findAllRunningCuts();
    }
    
    public List<ContractOrderEntrust> findPositionCuts(Long positionId) {
        return contractOrderEntrustRepository.findPositionCuts(positionId);
    }

    public List<ContractOrderEntrust> findAllByMemberIdAndContractId(long memberId, Long contractCoinId) {
        return contractOrderEntrustRepository.findAllByMemberIdAndContractId(memberId, contractCoinId);
    }
    
    public List<ContractOrderEntrust> findOpenByMemberIdAndContractId(long memberId, Long contractCoinId) {
        return contractOrderEntrustRepository.findOpenByMemberIdAndContractId(memberId, contractCoinId);
    }
    
    public ContractOrderEntrust getLatestInOppositeDirection(long memberId, Long contractCoinId, ContractOrderDirection direction) {
    	return contractOrderEntrustRepository.getLatestInOppositeDirection(memberId, contractCoinId, direction==ContractOrderDirection.BUY?1:0);
    }

    /**
     * 查询可以返佣的订单
     * @return
     */
    public List<ContractOrderEntrust> findCanRewardOrders() {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("isReward", 0, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_SUCCESS, false));
        return contractOrderEntrustRepository.findAll(specification);
    }
    
    public List<ContractOrderEntrust> findCanRewardOrdersByTime(Long startTime, Long endTime) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.gt("createTime", startTime, false));
        specification.add(Restrictions.lt("createTime", endTime, false));
        specification.add(Restrictions.eq("status", ContractOrderEntrustStatus.ENTRUST_SUCCESS, false));
        return contractOrderEntrustRepository.findAll(specification);
    }
    
    public int countActiveMembersByDate(String dateStr) throws ParseException {
    	java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
    	Date date = sdf.parse(dateStr);
    	return contractOrderEntrustRepository.countActiveMembersByDate(date.getTime(), date.getTime()+24*3600*1000);
    }
    public int countActiveMembersByMemberIdsAndTime(Long startTime, Long endTime, List<Long> ids) {
    	return contractOrderEntrustRepository.countActiveMembersByMemberIdsAndTime(startTime, endTime, ids);
    }
    
    public long countContract() {
    	Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
    	specification.add(Restrictions.eq("followId", null, false));
    	return contractOrderEntrustRepository.count(specification);
    }
    
    public long countByDirection(ContractOrderDirection direction, String dateStr) throws ParseException {
    	Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
    	specification.add(Restrictions.eq("status", 3, false));
    	specification.add(Restrictions.eq("direction", direction, false));
    	//java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
    	//Date date = sdf.parse(dateStr);
    	specification.add(Restrictions.gte("createTime", dateStr, false));
    	specification.add(Restrictions.lt("createTime", dateStr+" 23:59:59", false));
    	return contractOrderEntrustRepository.count(specification);
    }
    
    public long countByMemberId(long memberId, String dateStr) throws ParseException {
    	java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
    	Date date = sdf.parse(dateStr);
    	return countByMemberId(memberId, date.getTime(), date.getTime() + 24*3600000);
    }
    
    public long countByMemberId(long memberId, long startTime, long endTime) {
    	Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
    	specification.add(Restrictions.eq("status", 3, false));
    	specification.add(Restrictions.eq("entrustType", 0, false));
    	specification.add(Restrictions.gte("usdtOpenTime", startTime, false));
    	specification.add(Restrictions.lt("usdtOpenTime", endTime, false));
    	return contractOrderEntrustRepository.count(specification);
    }
    
    public long countByMemberId(long memberId) {
    	Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
    	specification.add(Restrictions.eq("status", 3, false));
    	specification.add(Restrictions.eq("entrustType", 0, false));
    	return contractOrderEntrustRepository.count(specification);
    }
    
    public long countByMemberIdAndType(long memberId, ContractOrderType type) {
    	Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
    	specification.add(Restrictions.eq("status", 0, false));
    	specification.add(Restrictions.eq("type", type, false));
    	return contractOrderEntrustRepository.count(specification);
    }
    
    public long countRunningOpenByMemberId(long memberId) {
    	Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("memberId", memberId, false));
    	specification.add(Restrictions.eq("status", 0, false));
    	specification.add(Restrictions.eq("entrustType", 0, false));
    	return contractOrderEntrustRepository.count(specification);
    }
    
    public BigDecimal sumVolumeByMemberIdAndContractCoinId(long memberId, long contractCoinId) {
    	BigDecimal volume = contractOrderEntrustRepository.sumVolumeByMemberIdAndContractCoinId(memberId, contractCoinId);
    	if(volume==null)
    		return BigDecimal.ZERO;
    	else
    		return volume;
    }
    
    public BigDecimal sumTotalPrincipalAmountByMemberIds(List<Long> memberIds) {
    	BigDecimal volume = contractOrderEntrustRepository.sumPrincipalAmountByMemberIds(memberIds);
    	if(volume==null)
    		return BigDecimal.ZERO;
    	else
    		return volume;
    }
    
    public BigDecimal sumBlastedLossByPositionIds(List<Long> positionIds) {
    	BigDecimal volume = contractOrderEntrustRepository.sumBlastedLossByPositionIds(positionIds);
    	if(volume==null)
    		return BigDecimal.ZERO;
    	else
    		return volume;
    }
    
    public void deleteById(Long id) {
    	contractOrderEntrustRepository.delete(id);
    }
    
    public void updateUsdtOpenPrice(Long positionId, BigDecimal usdtOpenPrice) {
    	contractOrderEntrustRepository.updateUsdtOpenPrice(positionId, usdtOpenPrice, ContractOrderEntrustStatus.ENTRUST_ING, ContractOrderEntrustType.CLOSE);
    }
    
    public OrderStatVo findStatVo(Long memberId, Long startTime, Long endTime) {
    	OrderStatVo vo = new OrderStatVo();
    	Object[] obj = contractOrderEntrustRepository.statSupervised(memberId, startTime, endTime)[0];
    	if(obj[0]!=null)
    		vo.setCount(Integer.parseInt(obj[0].toString()));
    	if(obj[1]!=null)
    		vo.setViolateCount(Integer.parseInt(obj[1].toString()));
    	return vo;
    }
    
    public List<OrderFarmingVo> findFarmingList(String startTime, String endTime) {
    	List<OrderFarmingVo> list = new ArrayList<>();
    	Object[][] objArray = contractOrderEntrustRepository.statFarming(startTime, endTime);
    	for (Object[] obj : objArray) {
    		OrderFarmingVo vo = new OrderFarmingVo();
        	if(obj[0]!=null)
        		vo.setMemberId(Long.parseLong(obj[0].toString()));
        	if(obj[1]!=null)
        		vo.setTotalCount(Integer.parseInt(obj[1].toString()));
        	list.add(vo);
    	}
    	return list;
    }

    /**
     * 幂等查询：根据 followSystemId + status 查找委托单，用于批量开仓去重
     */
    public ContractOrderEntrust findByFollowSystemIdAndStatus(Long followSystemId, ContractOrderEntrustStatus status) {
        Criteria<ContractOrderEntrust> specification = new Criteria<ContractOrderEntrust>();
        specification.add(Restrictions.eq("followSystemId", followSystemId, false));
        specification.add(Restrictions.eq("status", status, false));
        List<ContractOrderEntrust> list = contractOrderEntrustRepository.findAll(specification);
        return list.isEmpty() ? null : list.get(0);
    }
}
