package com.copy.trade.service.impl;

import com.alibaba.druid.util.StringUtils;
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.bean.RedisLock;
import com.copy.trade.constant.DogeApi;
import com.copy.trade.constant.RedisKey;
import com.copy.trade.dao.FollowMapper;
import com.copy.trade.entity.form.FollowForm;
import com.copy.trade.entity.po.*;
import com.copy.trade.entity.vo.*;
import com.copy.trade.enums.FollowConfigEnum;
import com.copy.trade.enums.FollowStatusEnum;
import com.copy.trade.enums.TraderEnum;
import com.copy.trade.service.*;
import com.copy.trade.util.BeanCopior;
import com.copy.trade.util.DogeContractUtils;
import com.copy.trade.util.HttpUtils;
import com.copy.trade.util.RedisUtils;
import com.copy.trade.util.TraderConfiguration;
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 java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
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 RedisUtils redisUtils;
    
    @Autowired
    private IFollowService followServiceImpl;

    @Autowired
    private ICustomerService customerServiceImpl;

    @Autowired
    private ITraderLevelService traderLevelServiceImpl;

    @Autowired
    private IRiskControlService riskControlServiceImpl;

    @Autowired
    private ICustomerFollowSymbolService customerFollowSymbolServiceImpl;

    @Autowired
    private ITraderSymbolService traderSymbolServiceImpl;

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private ITraderTagService traderTagServiceImpl;

    @Autowired
    private ITraderDataService traderDataServiceImpl;
    
    @Autowired
    private IPositionService positionServiceImpl;

    @Autowired
    private IFollowConfigService followConfigServiceImpl;

    @Override
    @Transactional
    public Boolean following(Long customerId, FollowForm followForm,Long memberId,String token) {
    	
        Long traderId = followForm.getTraderId();
        Integer leverage = followForm.getLeverage();
        //杠杆倍数1~200
        if(followForm.getLeverage() != null){
            leverage = Math.abs(leverage);
            followForm.setLeverage(leverage);
            WebAssert.isTrue(leverage >= 1 && leverage <= 200, "chk.follow.leverage.beyond.limit");
        }
        
        
        //验证交易员是否合法
        Customer trader = customerServiceImpl.getById(traderId);
        WebAssert.isNotNull(trader,"chk.trader.not.exist");
        Boolean isTrader =  trader.getTrader().equals(TraderEnum.TRADER.getStatus());
        WebAssert.isTrue(isTrader, "chk.not.trader");
        //如果是超级交易员,需要调用接口,而且按照比例100%下单跟随
        if(isSpecialTrader(trader)) {
        	followForm.setTradingMode(10);
        	followForm.setTradingAmount(new BigDecimal("100"));
        }
        //添加限制:当固定比例时,最大比例0~100
        BigDecimal tradingAmount = followForm.getTradingAmount();
        WebAssert.isNotNull(tradingAmount,"chk.follow.tradingAmount.not.null");
        Integer tradingMode = followForm.getTradingMode();
        WebAssert.isNotNull(tradingMode,"chk.follow.tradingMode.not.null");
        
        BigDecimal maxPrincipalAmount = trader.getMaxPrincipalAmount();
        if((tradingMode == 20 || tradingMode == 0) && maxPrincipalAmount != null) {
            WebAssert.isTrue(tradingAmount.compareTo(maxPrincipalAmount) <= 0, "chk.follow.amount.not.beyond",String.join(",",maxPrincipalAmount.toString()));
        }
        
        BigDecimal balance = DogeContractUtils.asset(dogeHostInner + DogeApi.CONTRACT_ASSET_NEW_STUDENT,memberId);
        if(tradingMode == 10) {
        	Boolean proportionLimit = (tradingAmount.compareTo(new BigDecimal("100")) <= 0) && (tradingAmount.compareTo(new BigDecimal("0")) > 0);
        	WebAssert.isTrue(proportionLimit, "chk.follow.proportion.beyond.limit");
        } else if(tradingMode == 20 || tradingMode == 0) {
        	WebAssert.isTrue(tradingAmount.compareTo(BigDecimal.ZERO) > 0, "chk.follow.amount.must.beyond.0");
        	//20固定资金 不能超过跟单账户
        	Boolean amountLimit = balance.compareTo(tradingAmount) >= 0;
        	WebAssert.isTrue(amountLimit, "chk.follow.amount.beyond.limit");
        	
        }
        //验证交易对是否合法
        List<String> symbols = followForm.getSymbols();
        WebAssert.isTrue(symbols.size() > 0, "chk.follow.symbol.not.null");
        Map<String,TraderSymbol> customerSymbolMap = new HashMap<>();
        //获取交易员开启的跟单交易对
        List<TraderSymbol> traderSymbolList = traderSymbolServiceImpl.listByTrader(traderId);
        traderSymbolList.forEach(traderSymbol -> {
            String symbol = traderSymbol.getSymbol();
            if(!symbols.contains(symbol)){
                return;
            }
            customerSymbolMap.put(symbol,traderSymbol);
            symbols.remove(symbol);
        });
        WebAssert.isTrue(symbols.size() == 0, "chk.follow.symbol.illegal",String.join(",",symbols));

        //验证是否已经跟随
        QueryWrapper<Follow> followQueryWrapper = new QueryWrapper<>();
        followQueryWrapper.eq("customer_id",customerId)
                .eq("trader_id",traderId);
        Follow followDB = getOne(followQueryWrapper);
        boolean isFollowing = followDB != null && followDB.getStatus().equals(FollowStatusEnum.FOLLOWING.getStatus());
        WebAssert.isTrue(!isFollowing, "chk.follow.followed");
        
        FollowConfig followConfig = followConfigServiceImpl.getConfig(FollowConfigEnum.ORDINARY_TEACHER_REMOVE_ONE_WEEK_LIMIT.getNameEn());
        Boolean limitSwitch = (followConfig != null && !StringUtils.isEmpty(followConfig.getConfigContent()) && "1".equals(followConfig.getConfigContent())) 
        		? true : false;
        FollowConfig unfollowConfig = followConfigServiceImpl.getConfig(FollowConfigEnum.CANCEL_FOLLOW_ONE_WEEK_LIMIT.getNameEn());
        Boolean unfollowLimitSwitch = (unfollowConfig != null && !StringUtils.isEmpty(unfollowConfig.getConfigContent()) && "1".equals(unfollowConfig.getConfigContent())) 
        		? true : false;
        //如果是跟随特级或者普通的开关为开,需要检测移除后或者取消是否超过1周,一周内不能跟随.
        boolean isUnFollowBySpecialTrader = (isSpecialTrader(trader) || limitSwitch) && followDB != null 
        		&& (!unfollowLimitSwitch ? followDB.getStatus().equals(FollowStatusEnum.REMOVE.getStatus()) 
                		: (!followDB.getStatus().equals(FollowStatusEnum.FOLLOWING.getStatus())))
        		&& ((new Date().getTime() - followDB.getUpdatedTime().getTime()) < 7 * 24* 3600000);
        WebAssert.isTrue(!isUnFollowBySpecialTrader, "chk.follow.trader.unfollow.not.oneweek");
        
        //特级交易员只能跟随一个
        Integer followSpecailTrader = ((FollowMapper)baseMapper).isFollowSpecailTrader(customerId);
        boolean isFollowSpecialTrader = isSpecialTrader(trader) && followSpecailTrader !=null && followSpecailTrader >0;
        WebAssert.isTrue(!isFollowSpecialTrader, "chk.follow.special.trader.has.follow");
        
        //验证交易员跟随名额是否满了
        //获取锁
        boolean lock = redisLock.lock(RedisKey.LOCK_FOLLOWING, traderId.toString(), 100);
        if(!lock){
            WebAssert.throwException("5000");
        }
        TraderLevel traderLevel = traderLevelServiceImpl.getById(trader.getTraderLevelId());
        Integer maxFollow = traderLevel.getMaxFollow();
         followQueryWrapper = new QueryWrapper<>();
        followQueryWrapper.eq("trader_id",traderId)
                .eq("status", FollowStatusEnum.FOLLOWING.getStatus());
        int count = count(followQueryWrapper);
        WebAssert.isTrue(maxFollow.compareTo(count + 1) >= 0, "chk.follow.overflow");

        //是否是特级都调用接口
        Long minFollowAmount = trader.getMinFollowAmount() == null ? 0L : trader.getMinFollowAmount();
        if(isSpecialTrader(trader)) {
        	minFollowAmount = trader.getMinFollowAmount() == null ? 2000L : trader.getMinFollowAmount();
        }
        Boolean isSuccess = DogeContractUtils.vailSpecialTrader(dogeHost + DogeApi.FOLLOW_WALLET_SPECIAL,token,minFollowAmount);
        WebAssert.isTrue(isSuccess,"chk.follow.special.trader.fail", minFollowAmount.toString());
        //3.添加跟随
        if(followDB == null){
            followDB = new Follow();
        }
        followDB.setCustomerId(customerId);
        followDB.setTraderId(traderId);
        followDB.setStatus(FollowStatusEnum.FOLLOWING.getStatus());
        followServiceImpl.saveOrUpdate(followDB);
        //4.添加或更新风控
        RiskControl riskControl = riskControlServiceImpl.getByFollowId(followDB.getId());
        if(riskControl == null){
            riskControl = new RiskControl();
        }
        riskControl.setCustomerId(customerId);
        riskControl.setLeverage(followForm.getLeverage());
        riskControl.setFollowId(followDB.getId());
        riskControl.setMaxCopiedAmount(followForm.getMaxCopiedAmount());
        riskControl.setStopLossPercentage(followForm.getStopLossPercentage());
        riskControl.setStopProfitPercentage(followForm.getStopProfitPercentage());
        riskControl.setTradingMode(tradingMode);
        riskControl.setTradingAmount(followForm.getTradingAmount());
        riskControlServiceImpl.saveOrUpdate(riskControl);
        //5.添加或跟新跟单交易对
       customerFollowSymbolServiceImpl.update(customerId,riskControl.getId(),customerSymbolMap);

        //释放锁
        redisLock.unlock(RedisKey.LOCK_FOLLOWING,traderId.toString());
        return true;
    }


    @Override
    public FollowVo info(Long customerId, Long traderId) {
        Follow follow = getByCustomerIdAndTraderId(customerId, traderId);
        WebAssert.isNotNull(follow, "chk.follow.info.null");
        RiskControl riskControl = riskControlServiceImpl.getByFollowId(follow.getId());
        RiskControlVo riskControlVo = BeanCopior.map(riskControl, RiskControlVo.class);
        FollowVo followVo = new FollowVo();
        followVo.setRiskControl(riskControlVo);
        List<CustomerFollowSymbol> customerFollowSymbols = customerFollowSymbolServiceImpl.listByRiskControl(riskControl.getId());
        List<TraderSymbolVo> customerFollow = BeanCopior.mapList(customerFollowSymbols, TraderSymbolVo.class);
        followVo.setCustomerFollowSymbols(customerFollow);
        return followVo;
    }

    @Override
    @Transactional
    public Boolean update(Long customerId, FollowForm followForm) {
        Follow follow = getByCustomerIdAndTraderId(customerId, followForm.getTraderId());
        WebAssert.isNotNull(follow, "chk.follow.info.null");
        
        
        Customer trader = customerServiceImpl.getById(followForm.getTraderId());
        if(isSpecialTrader(trader)) {
        	followForm.setTradingMode(10);
        	followForm.setTradingAmount(new BigDecimal("100"));
        }
        BigDecimal tradingAmount = followForm.getTradingAmount();
        WebAssert.isNotNull(tradingAmount,"chk.follow.tradingAmount.not.null");
        Integer tradingMode = followForm.getTradingMode();
        WebAssert.isNotNull(tradingMode,"chk.follow.tradingMode.not.null");
        
        
        BigDecimal maxPrincipalAmount = trader.getMaxPrincipalAmount();
        if(tradingMode == 20 || tradingMode == 0) {
        	WebAssert.isTrue(tradingAmount.compareTo(BigDecimal.ZERO) > 0, "chk.follow.amount.must.beyond.0");
        	if(maxPrincipalAmount != null) {
        		WebAssert.isTrue(tradingAmount.compareTo(maxPrincipalAmount) <= 0, "chk.follow.amount.not.beyond",String.join(",",maxPrincipalAmount.toString()));
        	}
        }        
        //验证交易对是否合法
        List<String> symbols = followForm.getSymbols();
        //交易对不能为空
        WebAssert.isTrue(symbols.size() > 0, "chk.follow.symbols.null");
        Map<String,TraderSymbol> customerSymbolMap = new HashMap<>();
        //获取交易员开启的跟单交易对
        List<TraderSymbol> traderSymbolList = traderSymbolServiceImpl.listByTrader(followForm.getTraderId());
        traderSymbolList.forEach(traderSymbol -> {
            String symbol = traderSymbol.getSymbol();
            if(!symbols.contains(symbol)){
                return;
            }
            customerSymbolMap.put(symbol,traderSymbol);
            symbols.remove(symbol);
        });
        WebAssert.isTrue(symbols.size() == 0, "chk.follow.symbol.illegal",String.join(",",symbols));
        //更新风控设置
        RiskControl riskControl = riskControlServiceImpl.getByFollowId(follow.getId());
        riskControl.setLeverage(followForm.getLeverage());
        riskControl.setMaxCopiedAmount(followForm.getMaxCopiedAmount());
        riskControl.setStopLossPercentage(followForm.getStopLossPercentage());
        riskControl.setStopProfitPercentage(followForm.getStopProfitPercentage());
        riskControl.setTradingMode(followForm.getTradingMode());
        riskControl.setTradingAmount(followForm.getTradingAmount());
        //riskControlServiceImpl.updateById(riskControl);
        riskControlServiceImpl.updateRiskControlById(riskControl);
        
        customerFollowSymbolServiceImpl.update(customerId,riskControl.getId(),customerSymbolMap);
        return true;
    }
    
    @Override
    @Transactional
    public FollowForm getConfig(Long customerId, Long traderId) {
    	FollowForm followForm = new FollowForm();
        Follow follow = this.getByCustomerIdAndTraderId(customerId, traderId);
        if(follow != null) {
	        RiskControl riskControl = riskControlServiceImpl.getByFollowId(follow.getId());
	        followForm.setTraderId(traderId);
	        followForm.setLeverage(riskControl.getLeverage());
	        followForm.setMaxCopiedAmount(riskControl.getMaxCopiedAmount());
	        followForm.setStopLossPercentage(riskControl.getStopLossPercentage());
	        followForm.setStopProfitPercentage(riskControl.getStopProfitPercentage());
	        followForm.setTradingMode(riskControl.getTradingMode());
	        followForm.setTradingAmount(riskControl.getTradingAmount());
	        List<CustomerFollowSymbol> customerFollowSymbolList = customerFollowSymbolServiceImpl.listByCustomerAndTrader(follow.getCustomerId(), follow.getTraderId());
	        List<String> symbols = new ArrayList<>();
	        customerFollowSymbolList.forEach(customerFollowSymbol->{
	        	symbols.add(customerFollowSymbol.getSymbol());
	        });
	        followForm.setSymbols(symbols);
        }
        return followForm;
    }

    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);
    }

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

        //关闭跟随中交易对
        customerFollowSymbolServiceImpl.offFollowSymbol(customerId,traderId);
        follow.setStatus(followStatusEnum.getStatus());
        followServiceImpl.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;
    }

    @Override
    public Integer countByTrader(Long traderId) {
        QueryWrapper<Follow> followQueryWrapper = new QueryWrapper<>();
        followQueryWrapper.eq("trader_id",traderId)
                .eq("status",FollowStatusEnum.FOLLOWING.getStatus());
        return count(followQueryWrapper);
    }

    @Override
    public Page<TraderVo> followingList(Page page, Long customerId) {
       List<TraderVo>  list = ((FollowMapper)baseMapper).followingList(page,customerId);
       
       
       list.forEach(traderVo -> {
    	   Integer followCount = followServiceImpl.countByTrader(traderVo.getId());
	       
	       //当前跟单人数添加默认的
	       Integer defaultFollowCustomer = traderVo.getDefaultFollowCustomer() == null ? 0 : traderVo.getDefaultFollowCustomer();
	       traderVo.setFollowing(followCount + defaultFollowCustomer);
	       
           traderVo.setIsFollow(1);
           FollowConfig followConfig = followConfigServiceImpl.getConfig(FollowConfigEnum.SPECIAL_TRADER_CODE.getNameEn());
           boolean isSpecialTrader = traderVo.getTraderLevelId() >= Integer.parseInt(followConfig.getConfigContent());
           traderVo.setSpecialTrader(isSpecialTrader);
           //查询标签
           List<Tag> taglist = traderTagServiceImpl.list(traderVo.getId());
           List<String> tags = new ArrayList<>();
           taglist.forEach(tag ->{
               tags.add(tag.getName());
           });
           traderVo.setTags(tags);
           List<YieldVo> yieldVoList = traderDataServiceImpl.yield14(traderVo.getId());
           traderVo.setYield14List(yieldVoList);
           BigDecimal balance = DogeContractUtils.asset(dogeHost + DogeApi.CONTRACT_ASSET_NEW,traderVo.getMemberId());
           traderVo.setMoneyStrength("≥5K");
           if(balance.compareTo(new BigDecimal("5000")) < 0) {
           	traderVo.setMoneyStrength("<5K");
           }
           if(isSpecialTrader) {
        	   traderVo.setTags(TraderConfiguration.getSpecailTagList(traderVo.getMemberId(),traderVo.getTags()));
        	   traderVo.setNickname(TraderConfiguration.getSpecailName(traderVo.getMemberId(),traderVo.getNickname()));
           }
           traderVo.setTeamProfit14String(TraderConfiguration.getSpecialTraderAmoutString(traderVo.getTeamProfit14()));
           traderVo.setProfitAmountString(TraderConfiguration.getSpecialTraderAmoutString(traderVo.getProfitAmount()));
           
           
       });
       page.setRecords(list);
        return page;
    }

    @Override
    public Boolean isFollow(Long customerId, Long traderId) {
        QueryWrapper<Follow> followQueryWrapper = new QueryWrapper<>();
        followQueryWrapper.eq("customer_id",customerId)
                .eq("trader_id",traderId)
                .eq("status", FollowStatusEnum.FOLLOWING.getStatus());
        Follow follow = getOne(followQueryWrapper);
        if(follow == null){
            return false;
        }
        return true;
    }

    @Override
    public Page<FollowerVo> followers(Page page, Long traderId) {
       List<FollowerVo>  followerVolist = ((FollowMapper)baseMapper).followers(page,traderId);
       followerVolist.forEach(followerVo -> {
    	   Position position = new Position();
    	   position.setTraderId(traderId);
    	   position.setCustomerId(followerVo.getId());
    	   BigDecimal dividendFeeAll = positionServiceImpl.selectDividendFee(position);
    	   followerVo.setTotalProfitSharing(dividendFeeAll != null ? dividendFeeAll.toPlainString() : null);
    	   position.setCreatedTime(getLastWeektime(2));
    	   position.setUpdatedTime(getLastWeektime(1));
    	   BigDecimal dividendFee = positionServiceImpl.selectDividendFee(position);
    	   followerVo.setLastProfitSharing(dividendFee != null ? dividendFee.toPlainString() : null);

    	   BigDecimal balance = DogeContractUtils.asset(dogeHostInner + DogeApi.CONTRACT_ASSET_NEW_STUDENT,followerVo.getMemberId());
    	   followerVo.setBalance(balance != null ? balance.toPlainString() : null);
    	   
    	   
    	   
       });
       page.setRecords(followerVolist);
       return page;
    }
    
    public static Date getLastWeektime(Integer lastWeek) {
    	Calendar calendar = Calendar.getInstance();
        calendar.setWeekDate(calendar.getWeekYear(), calendar.get(Calendar.WEEK_OF_YEAR) - lastWeek + 1, 1);
        calendar.set(calendar.get(calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(calendar.DAY_OF_MONTH), 16, 00, 00);
        return calendar.getTime();
    }
    
    public Boolean isSpecialTrader(Customer trader) {
    	FollowConfig followConfig = followConfigServiceImpl.getConfig(FollowConfigEnum.SPECIAL_TRADER_CODE.getNameEn());
        boolean isSpecialTrader = trader.getTraderLevelId() >= Integer.parseInt(followConfig.getConfigContent());
    	if(isSpecialTrader) {
    		return true;
    	} 
   		return false;
    }
    

	@Override
	public Integer followerCount(Long traderId) {
		QueryWrapper<Follow> customerQueryWrapper = new QueryWrapper<>();
        customerQueryWrapper.eq("trader_id",traderId);
        customerQueryWrapper.eq("status",10);
        return count(customerQueryWrapper);
	}
	
	public static void main(String[] args) {
		System.out.println(getLastWeektime(1));
		System.out.println(getLastWeektime(2));

	}
	
	
}
