package com.copy.trade.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.copy.trade.constant.DogeApi;
import com.copy.trade.consumer.MarketListener;
import com.copy.trade.dao.FollowMapper;
import com.copy.trade.entity.form.AgentStudentPositionForm;
import com.copy.trade.entity.form.StudentPositionForm;
import com.copy.trade.entity.po.*;
import com.copy.trade.entity.vo.FolloweInforAgentVo;
import com.copy.trade.entity.vo.FollowerAgentVo;
import com.copy.trade.entity.vo.FollowerVo;
import com.copy.trade.entity.vo.TraderTotalVo;
import com.copy.trade.enums.FollowStatusEnum;
import com.copy.trade.enums.TraderEnum;
import com.copy.trade.service.*;
import com.copy.trade.util.DogeContractUtils;
import com.copy.trade.util.WebAssert;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

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


/**
 * <p>
 * 跟随表 服务实现类
 * </p>
 *
 * @author wz
 * @since 2022-11-08
 */
@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements IFollowService {

    @Value("${doge.host_inner}")
    private String dogeHostInner;
    
    @Value("${doge.host}")
    private String dogeHost;
    
    @Autowired
    private MarketListener marketListener;
	
    @Autowired
    private ICustomerFollowSymbolService customerFollowSymbolServiceImpl;
    
    @Autowired
    private IPositionService positionServiceImpl;
    
    @Autowired
    private ICustomerService customerServiceImpl;
    
    @Autowired
    private IRiskControlService riskControlServiceImpl;

    @Override
    public List<Follow> getByCustomerId(Long customerId) {
        QueryWrapper<Follow> followQueryWrapper = new QueryWrapper<>();
        followQueryWrapper.eq("customer_id",customerId)
                .eq("status", FollowStatusEnum.FOLLOWING.getStatus());
        return list(followQueryWrapper);
    }

    @Override
    @Transactional
    public Boolean unfollow(Follow follow, FollowStatusEnum followStatusEnum) {
        //关闭跟随中交易对
        customerFollowSymbolServiceImpl.offFollowSymbol(follow.getCustomerId(),follow.getTraderId());
        follow.setStatus(followStatusEnum.getStatus());
        updateById(follow);
        return true;
    }

    @Override
    public Integer countByTrader(Long traderId, String startTime) {
        QueryWrapper<Follow> followQueryWrapper = new QueryWrapper<>();
        followQueryWrapper.eq("trader_id",traderId);
        if(StringUtils.hasText(startTime)){
            followQueryWrapper.ge("created_time",startTime);
        }
        return count(followQueryWrapper);
    }
    
    //统计某个交易员某个时间前的跟随人数
    @Override
    public Integer countByTraderAndByEndTime(Long traderId, Date endTime) {
    	QueryWrapper<Follow> followQueryWrapper = new QueryWrapper<>();
    	followQueryWrapper.eq("trader_id",traderId);
    	followQueryWrapper.le("created_time",endTime);
    	return count(followQueryWrapper);
    }
    
    @Override
    public Integer countByTraderToday(Long traderId, Date startTime) {
    	QueryWrapper<Follow> followQueryWrapper = new QueryWrapper<>();
    	followQueryWrapper.eq("trader_id",traderId);
    	followQueryWrapper.ge("created_time",startTime);
    	return count(followQueryWrapper);
    }
    
    @Override
    public Integer followerCount(Long traderId) {
        QueryWrapper<Follow> followQueryWrapper = new QueryWrapper<>();
        followQueryWrapper.eq("trader_id",traderId)
                .eq("status",FollowStatusEnum.FOLLOWING.getStatus());
        return count(followQueryWrapper);
    }
    
    @Override
    public Integer followerCountByStatus(Long traderId, FollowStatusEnum followStatusEnum) {
    	QueryWrapper<Follow> followQueryWrapper = new QueryWrapper<>();
    	followQueryWrapper.eq("trader_id",traderId)
    	.eq("status",followStatusEnum.getStatus());
    	return count(followQueryWrapper);
    }
    
    @Override
    public List<Long> followering(Long traderId) {
    	List<Long> list = ((FollowMapper) baseMapper).followering(traderId);
    	return list;
    }
    
    @Override
    public Page<FollowerVo> followers(StudentPositionForm studentPositionForm) {
       Page page = studentPositionForm.newFormPage();
       Integer status = studentPositionForm.getStatus();
       if(status == null) {
    	   studentPositionForm.setStatus(FollowStatusEnum.FOLLOWING.getStatus());
       }
       List<FollowerVo> followerVolist = ((FollowMapper)baseMapper).followers(page,studentPositionForm);
       followerVolist.forEach(followerVo -> {
    	   List<Long> studentMemberIds = new ArrayList<Long>();
    	   studentMemberIds.add(followerVo.getMemberId());
    	   TraderTotalVo followInOutTeacher = DogeContractUtils.getFollowInOut(dogeHostInner + DogeApi.FOLLOW_IN_OUT,studentMemberIds);
    	   followerVo.setUsername(followInOutTeacher.getUsername());
//    	   //跟单账户
//    	   BigDecimal followAccount = DogeContractUtils.asset(dogeHostInner + DogeApi.CONTRACT_ASSET_NEW_STUDENT,followerVo.getMemberId());
//    	   followerVo.setFollowAccount(followAccount);
//    	   //合约账户
//    	   BigDecimal contractAccount = DogeContractUtils.asset(dogeHostInner + DogeApi.CONTRACT_ASSET_NEW,followerVo.getMemberId());
//    	   followerVo.setContractAccount(contractAccount);
    	   Map<String,BigDecimal> assetMap = DogeContractUtils.getAllasset(dogeHostInner + DogeApi.ASSET_ALL,studentMemberIds);
    	   //totalAccountBalance assetAccount contractAccount followAccount
    	   followerVo.setTotalAccountBalance(assetMap.get("totalBalance") != null ? assetMap.get("totalBalance").toPlainString() : null);
    	   followerVo.setAssetAccount(assetMap.get("spotBalance") != null ? assetMap.get("spotBalance").toPlainString() : null);
    	   followerVo.setContractAccount(assetMap.get("swapBalance") != null ? assetMap.get("swapBalance").toPlainString() : null);
    	   followerVo.setFollowAccount(assetMap.get("followBalance") != null ? assetMap.get("followBalance").toPlainString() : null);
    	   
    	   //查看浮动盈亏
    	   BigDecimal profitOrLossAll = new BigDecimal("0");
    	   followerVo.setHasPosition(false);
       	   List<Position> positionList = positionServiceImpl.sumPositionList(followerVo.getId(), studentPositionForm.getTraderId());
       	   //如果是查有仓位的,交易对和方向不能为空
       	   String symbol = studentPositionForm.getSymbol();
       	   Integer directionForm = studentPositionForm.getDirection();
       	   if(studentPositionForm.getHasPosition()) {
       		   WebAssert.isTrue(!StringUtils.isEmpty(symbol),"chk.symbol.not.null");
       		   WebAssert.isTrue(directionForm != null && (directionForm == 0 || directionForm == 1),"chk.direction.not.null.or.incorrect.value");
       	   }
       	   
       	   if(positionList != null && positionList.size() > 0 ) {
       		   followerVo.setHasPosition(true);
	       	   for (Position position : positionList) {
	       			Integer direction = position.getDirection() == 0 ? 1 : -1;
	       			BigDecimal currentPrice = marketListener.getCurrentPriceMap().get(position.getSymbol());
	       			// 盈亏 =(当前价-买入价)*数量*方向
	       			BigDecimal profitOrLoss = (currentPrice.subtract(position.getOpenPrice())).multiply(position.getCurrentPosition())
	       					.multiply(new BigDecimal(direction));
	       			//持仓中的本单盈亏
	       			if(!StringUtils.isEmpty(symbol) && symbol.equals(position.getSymbol()) && directionForm != null && directionForm == position.getDirection()) {
	       				followerVo.setProfitOrLoss(profitOrLoss.toPlainString());
	       			}
	       			profitOrLossAll = profitOrLossAll.add(profitOrLoss);
			   }
       	   }
       	   //跟单总盈亏=浮动盈亏+平仓盈亏
       	   BigDecimal followAllprofitOrLoss = positionServiceImpl.selectStudentProfit(followerVo.getId(),studentPositionForm.getTraderId());
       	   followerVo.setFollowAllprofitOrLoss((followAllprofitOrLoss == null ? BigDecimal.ZERO : followAllprofitOrLoss)
       			   .add(profitOrLossAll == null ? BigDecimal.ZERO : profitOrLossAll).toPlainString());
    	   
       });
       page.setRecords(followerVolist);
       return page;
    }
    
    @Override
    public Page<FollowerAgentVo> followersAgent(AgentStudentPositionForm studentPositionForm) {
    	Page page = studentPositionForm.newFormPage();
    	Integer status = studentPositionForm.getStatus();
    	if(status == null) {
    		studentPositionForm.setStatus(FollowStatusEnum.FOLLOWING.getStatus());
    	}
    	List<FollowerAgentVo> followerVolist = ((FollowMapper)baseMapper).followersAgent(page,studentPositionForm);
    	followerVolist.forEach(followerAgentVo -> {
    		List<Long> studentMemberIds = new ArrayList<Long>();
    		studentMemberIds.add(followerAgentVo.getMemberId());
    		TraderTotalVo followInOutStudent = DogeContractUtils.getFollowInOut(dogeHostInner + DogeApi.FOLLOW_IN_OUT,studentMemberIds);
    		followerAgentVo.setUsername(followInOutStudent.getUsername());
    		List<Long> teacherMemberIds = new ArrayList<Long>();
    		teacherMemberIds.add(followerAgentVo.getTeacherMemberId());
    		TraderTotalVo followInOutTeacher = DogeContractUtils.getFollowInOut(dogeHostInner + DogeApi.FOLLOW_IN_OUT,teacherMemberIds);
    		followerAgentVo.setTeacherUsername(followInOutTeacher.getUsername());
    		
    		Map<String,BigDecimal> assetMap = DogeContractUtils.getAllasset(dogeHostInner + DogeApi.ASSET_ALL,studentMemberIds);
    		followerAgentVo.setTotalAccountBalance(assetMap.get("totalBalance"));
    		followerAgentVo.setAssetAccount(assetMap.get("spotBalance"));
    		followerAgentVo.setContractAccount(assetMap.get("swapBalance"));
    		followerAgentVo.setFollowAccount(assetMap.get("followBalance"));
    		
    		//查看浮动盈亏
    		BigDecimal profitOrLossAll = new BigDecimal("0");
    		List<Position> positionList = positionServiceImpl.sumPositionList(followerAgentVo.getId(), followerAgentVo.getTeacherId());
    		
    		if(positionList != null && positionList.size() > 0 ) {
    			for (Position position : positionList) {
    				Integer direction = position.getDirection() == 0 ? 1 : -1;
    				BigDecimal currentPrice = marketListener.getCurrentPriceMap().get(position.getSymbol());
    				// 盈亏 =(当前价-买入价)*数量*方向
    				BigDecimal profitOrLoss = (currentPrice.subtract(position.getOpenPrice())).multiply(position.getCurrentPosition())
    						.multiply(new BigDecimal(direction));
    				profitOrLossAll = profitOrLossAll.add(profitOrLoss);
    			}
    		}
    		//跟单总盈亏=浮动盈亏+平仓盈亏
    		BigDecimal followAllprofitOrLoss = positionServiceImpl.selectStudentProfit(followerAgentVo.getId(), followerAgentVo.getTeacherId());
    		followerAgentVo.setFollowAllprofitOrLoss((followAllprofitOrLoss == null ? BigDecimal.ZERO : followAllprofitOrLoss)
    				.add(profitOrLossAll == null ? BigDecimal.ZERO : profitOrLossAll));
    		
    	});
    	page.setRecords(followerVolist);
    	return page;
    }

	@Override
	public FolloweInforAgentVo selectFollowInforAgent(String subIds) {
    	List<Long> list = JSONObject.parseArray(subIds, Long.class);
		Integer unfollowCount = 0;
		Integer removeCount = 0;
		List<Long> teacherIds = new ArrayList<Long>();
		FolloweInforAgentVo followeInforAgentVo = new FolloweInforAgentVo();
		for (Long subId : list) {
			Customer customer = customerServiceImpl.getByMemberId(subId);
			if(customer != null && customer.getTrader().equals(TraderEnum.TRADER.getStatus())) {
				unfollowCount = unfollowCount + followerCountByStatus(customer.getId(), FollowStatusEnum.UNFOLLOW);
				removeCount = removeCount + followerCountByStatus(customer.getId(), FollowStatusEnum.REMOVE);
				teacherIds.add(customer.getId());
			}
		}
		followeInforAgentVo.setCancelFollowerCustomer(unfollowCount);
		followeInforAgentVo.setRemoveFollowerCustomer(removeCount);
		followeInforAgentVo.setTeacherIds(teacherIds);
		
		return followeInforAgentVo;
	}

	@Override
	public Boolean removeFollow(Long customerId, Long traderId) {

        Follow follow = getByCustomerIdAndTraderId(customerId, traderId);
        if(follow == null){
            return false;
        }
        //如果持有仓位限制不能取消
        Integer positionCount = positionServiceImpl.getPositionCountForTeacherOrStudent(traderId,traderId);
        WebAssert.isTrue(positionCount == 0, "chk.unfollow.has.position");

        //关闭跟随中交易对
        customerFollowSymbolServiceImpl.offFollowSymbol(customerId,traderId);
        follow.setStatus(FollowStatusEnum.REMOVE.getStatus());
        updateById(follow);
        //删除风控设置
        RiskControl riskControl = riskControlServiceImpl.getByFollowId(follow.getId());
        riskControlServiceImpl.removeById(riskControl.getId());
        QueryWrapper<CustomerFollowSymbol> customerFollowSymbolQueryWrapper = new QueryWrapper<>();
        customerFollowSymbolQueryWrapper.eq("risk_control_id",riskControl.getId());
        List<CustomerFollowSymbol> customerFollowSymbolList = customerFollowSymbolServiceImpl.list(customerFollowSymbolQueryWrapper);
        //删除已跟随的交易对
        customerFollowSymbolList.forEach(customerFollowSymbol -> {
        	customerFollowSymbolServiceImpl.removeById(customerFollowSymbol.getId());
        });
        return true;
    
	}
	
    private Follow getByCustomerIdAndTraderId(Long customerId, Long traderId){
        QueryWrapper<Follow> followQueryWrapper = new QueryWrapper<>();
        followQueryWrapper.eq("customer_id",customerId)
                .eq("trader_id",traderId)
                .eq("status",FollowStatusEnum.FOLLOWING.getStatus());
       return getOne(followQueryWrapper);
    }
	

	
}
