package com.copy.trade.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.copy.trade.entity.dto.ContractOrderEntrust;
import com.copy.trade.entity.dto.EntrustDeal;
import com.copy.trade.entity.dto.PositionDto;
import com.copy.trade.entity.form.CopiedTradeForm;
import com.copy.trade.entity.form.PositionForm;
import com.copy.trade.entity.po.CopiedTrade;
import com.copy.trade.entity.po.Customer;
import com.copy.trade.entity.po.Position;
import com.copy.trade.entity.vo.CopiedTradeVo;
import com.copy.trade.entity.vo.PositionStatisticsVo;
import com.copy.trade.entity.vo.PositionVo;
import com.copy.trade.bean.RedisLock;
import com.copy.trade.constant.RedisKey;
import com.copy.trade.consumer.KafkaConsumer;
import com.copy.trade.dao.CopiedTradeMapper;
import com.copy.trade.dao.PositionMapper;
import com.copy.trade.enums.DirectionEnum;
import com.copy.trade.enums.EntrustStatusEnum;
import com.copy.trade.enums.PositionStatusEnum;
import com.copy.trade.enums.TraderEnum;
import com.copy.trade.service.IClosePositionService;
import com.copy.trade.service.ICopiedTradeService;
import com.copy.trade.service.ICustomerService;
import com.copy.trade.service.IPositionService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import org.apache.ibatis.annotations.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

/**
 * <p>
 * 跟单持仓表 服务实现类
 * </p>
 *
 * @author wz
 * @since 2022-11-17
 */
@Service
public class PositionServiceImpl extends ServiceImpl<PositionMapper, Position> implements IPositionService {
	
	private final Logger log = LoggerFactory.getLogger(PositionServiceImpl.class);
    
	@Autowired
    private ICopiedTradeService copiedTradeServiceImpl;

    @Autowired
    private ICustomerService customerServiceImpl;

    @Autowired
    private IPositionService positionServiceImpl;
    
    @Autowired
    private RedisLock redisLock;

    @Autowired
    private IClosePositionService closePositionServiceImpl;

    @Override
    @Transactional
    public Boolean entrustDeal(EntrustDeal entrustDeal) {
        //验证委托
        CopiedTrade copiedTrade = copiedTradeServiceImpl.getByContractOrderEntrustId(entrustDeal.getContractOrderEntrustId());
        Position position = new Position();
        position.setContractOrderEntrustId(entrustDeal.getContractOrderEntrustId());
        position.setOpenPrice(entrustDeal.getOpenPrice());
        position.setPositionId(entrustDeal.getPositionId());
        position.setTotalPosition(entrustDeal.getVolume());
        position.setAvailablePosition(entrustDeal.getVolume());
        position.setCurrentPosition(entrustDeal.getVolume());
        position.setPrincipalAmount(entrustDeal.getPrincipalAmount());
        position.setTotalPrincipalAmount(entrustDeal.getPrincipalAmount());
        position.setOpenTime(entrustDeal.getOpenTime());
        position.setStatus(PositionStatusEnum.STARTED.getStatus());
        position.setDirection(DirectionEnum.getByDirectionStr(entrustDeal.getDirection()).getDirection());
        //存在交易员委托队列还未消费
        if(copiedTrade == null){
            //查询用户
            Customer customer = customerServiceImpl.getByMemberId(entrustDeal.getMemberId());
            //只会存在交易员委托单消费延迟情况
            if(customer == null || !customer.getTrader().equals(TraderEnum.TRADER.getStatus())){
                return true;
            }
            position.setCustomerId(customer.getId());
            save(position);
            return true;
        }
        position.setSymbol(copiedTrade.getSymbol());
        position.setCustomerId(copiedTrade.getCustomerId());
        position.setTraderId(copiedTrade.getTraderId());
        positionServiceImpl.save(position);

        //更新委托状态
        copiedTrade.setStatus(EntrustStatusEnum.ENTRUST_SUCCESS.getStatus());
        copiedTradeServiceImpl.updateById(copiedTrade);
        return true;
    }
    
    @Override
    public Boolean entrustOrderSuccess(Long posionId,ContractOrderEntrust entrustDeal,Long customerId,Long traderId,Long traderPositionId) {
    	log.info("开仓:仓位id:{},学生id:{},老师id:{},order数据:{}",posionId,customerId,traderId,JSON.toJSONString(entrustDeal));
    	boolean lock = redisLock.lock(RedisKey.LOCK_FOLLOW_POSITION + posionId.toString(), posionId.toString(), 100);
        if(!lock){
            return false;
        }
    	Position positionOld = getByPositionId(posionId);
    	if(positionOld != null) {
    		// 检查是否是同一个带单员的仓位，若不同则说明交易所合仓了不同带单员的跟单
    		// 此时需要新建独立记录，避免分润归属错误
    		if(traderId != null && !traderId.equals(positionOld.getTraderId())) {
    			log.warn("开仓:仓位id:{}被交易所合仓，原带单员:{},新带单员:{}，新建独立position记录",
    					posionId, positionOld.getTraderId(), traderId);
    			Position position = new Position();
    			position.setCustomerId(customerId);
    			position.setPositionId(posionId);
    			position.setTraderId(traderId);
    			position.setSymbol(entrustDeal.getSymbol());
    			position.setDirection(DirectionEnum.getByDirectionStr(entrustDeal.getDirection()).getDirection());
    			position.setLeverage(entrustDeal.getLeverage());
    			position.setOpenPrice(entrustDeal.getTradedPrice());
    			position.setTotalPosition(entrustDeal.getVolume());
    			position.setTotalPrincipalAmount(entrustDeal.getPrincipalAmount());
    			position.setAvailablePosition(entrustDeal.getVolume());
    			position.setCurrentPosition(entrustDeal.getVolume());
    			position.setPrincipalAmount(entrustDeal.getPrincipalAmount());
    			position.setContractOrderEntrustId(entrustDeal.getContractOrderEntrustId());
    			position.setStatus(PositionStatusEnum.STARTED.getStatus());
    			position.setTransactionFee(entrustDeal.getOpenFee());
    			position.setOpenTime(entrustDeal.getDealTime());
    			position.setTraderPositionId(traderPositionId);
    			log.info("开仓:合仓场景新建position,仓位id:{},数据:{}",posionId,JSON.toJSONString(position));
    			positionServiceImpl.save(position);
    			redisLock.unlock(RedisKey.LOCK_FOLLOW_POSITION + posionId.toString(), posionId.toString());
    			return true;
    		}
    		//暂时只  开仓价格 总持仓张数 总本金  当前可平张数  当前持仓张数  保证金  交易手续费
    		BigDecimal openPriceOld = positionOld.getOpenPrice();
    		BigDecimal totalPositionOld = positionOld.getTotalPosition();
    		BigDecimal availableOld = positionOld.getAvailablePosition();
    		BigDecimal openPriceNew = entrustDeal.getTradedPrice();
    		BigDecimal totalPositionNew = entrustDeal.getVolume();
    		BigDecimal openPriceEnd = ((openPriceOld.multiply(availableOld)).add(openPriceNew.multiply(totalPositionNew)))
    				.divide(availableOld.add(totalPositionNew),8, BigDecimal.ROUND_DOWN);
    		positionOld.setOpenPrice(openPriceEnd);
    		positionOld.setTotalPosition(totalPositionOld.add(totalPositionNew));
    		positionOld.setTotalPrincipalAmount(positionOld.getTotalPrincipalAmount().add(entrustDeal.getPrincipalAmount()));
    		positionOld.setAvailablePosition(positionOld.getAvailablePosition().add(entrustDeal.getVolume()));
    		positionOld.setCurrentPosition(positionOld.getCurrentPosition().add(entrustDeal.getVolume()));
    		positionOld.setPrincipalAmount(positionOld.getPrincipalAmount().add(entrustDeal.getPrincipalAmount()));
    		positionOld.setTransactionFee(positionOld.getTransactionFee().add(entrustDeal.getOpenFee()));
    		positionOld.setContractOrderEntrustId(entrustDeal.getContractOrderEntrustId());
    		log.info("开仓:仓位id:{},position数据:{}",posionId,JSON.toJSONString(positionOld));
    		positionServiceImpl.saveOrUpdate(positionOld);
    		redisLock.unlock(RedisKey.LOCK_FOLLOW_POSITION + posionId.toString(), posionId.toString());
        	return true;
    	}
    		
    	//只有平仓价格,平仓时间,平仓盈利,在开仓时没有.
    	Position position = new Position();
    	position.setCustomerId(customerId);
    	position.setPositionId(entrustDeal.getPositionId());
    	position.setTraderId(traderId);
    	position.setSymbol(entrustDeal.getSymbol());
    	position.setDirection(DirectionEnum.getByDirectionStr(entrustDeal.getDirection()).getDirection());
    	position.setLeverage(entrustDeal.getLeverage());
    	position.setOpenPrice(entrustDeal.getTradedPrice());
    	position.setTotalPosition(entrustDeal.getVolume());
    	position.setTotalPrincipalAmount(entrustDeal.getPrincipalAmount());
    	position.setAvailablePosition(entrustDeal.getVolume());
    	position.setCurrentPosition(entrustDeal.getVolume());
    	position.setPrincipalAmount(entrustDeal.getPrincipalAmount());
    	position.setContractOrderEntrustId(entrustDeal.getContractOrderEntrustId());
    	position.setStatus(PositionStatusEnum.STARTED.getStatus());
    	position.setTransactionFee(entrustDeal.getOpenFee());
    	position.setOpenTime(entrustDeal.getDealTime());
    	position.setTraderPositionId(traderPositionId);
    	log.info("开仓:仓位id:{},position数据:{}",posionId,JSON.toJSONString(position));
    	positionServiceImpl.save(position);
    	redisLock.unlock(RedisKey.LOCK_FOLLOW_POSITION + posionId.toString(), posionId.toString());
    	return true;
    }


    @Override
    public Position getByPositionId(Long positionId) {
        QueryWrapper<Position> positionQueryWrapper = new QueryWrapper<>();
        positionQueryWrapper.eq("position_id",positionId);
        return getOne(positionQueryWrapper);
    }

    @Override
    public Boolean updateAvailablePosition(BigDecimal volume,Long positionId) {
        return ((PositionMapper)baseMapper).updateAvailablePosition(volume, positionId);
    }

    @Override
    public Boolean updateCurrentPosition(BigDecimal volume, Long positionId, Integer status, Long transactionTime) {
        return ((PositionMapper)baseMapper).updateCurrentPosition(volume, positionId, status, transactionTime);
    }

    @Override
    public List<Position> followPosition(String contractOrderEntrustId) {
        return ((PositionMapper)baseMapper).followPosition(contractOrderEntrustId);
    }

    @Override
    public List<Position> followPositionByTraderPositionId(Long traderPositionId) {
        return ((PositionMapper)baseMapper).followPositionByTraderPositionId(traderPositionId);
    }

    @Override
    public Position getByContractOrderEntrustId(String contractOrderEntrustId) {
        QueryWrapper<Position> positionQueryWrapper = new QueryWrapper<>();
        positionQueryWrapper.eq("contract_order_entrust_id",contractOrderEntrustId);
        return getOne(positionQueryWrapper);
    }
    
    @Override
    public Position getStudentPositionByTraderPositionId(Long traderPositionId,Long customerId) {
//    	QueryWrapper<Position> positionQueryWrapper = new QueryWrapper<>();
//    	positionQueryWrapper.eq("trader_position_id",traderPositionId).eq("customer_id",customerId).ne("status",30);
//    	return getOne(positionQueryWrapper);
    	return ((PositionMapper)baseMapper).getStudentPositionByTraderPositionId(traderPositionId, customerId);
    }
    
    @Override
    public BigDecimal sumPrincipalAmount(Long customerId, Long traderId) {
        return ((PositionMapper)baseMapper).sumPrincipalAmount(customerId, traderId);
    }
    
    @Override
    public List<Position> sumPositionList(Long customerId, Long traderId) {
    	return ((PositionMapper)baseMapper).sumPositionList(customerId, traderId);
    }
    
    @Override
    public Position getTraderPosition(Long customerId,String contractOrderEntrustId) {
    	return ((PositionMapper)baseMapper).getTraderPosition(customerId, contractOrderEntrustId);
    }


    @Override
    public Map<String,BigDecimal> earningsCalculationByDay(Long traderId, Long startTime, Long endTime) {
        //查询平仓
        List<Position> historyPositionList = ((PositionMapper) baseMapper).closedPositionList(traderId, startTime, endTime);
        log.info("统计老师数据:老师今日的平仓数据{}",historyPositionList.toString());
        BigDecimal earnings = BigDecimal.ZERO;
        BigDecimal principalAmount = BigDecimal.ZERO;
        BigDecimal profitOrderCount = BigDecimal.ZERO;
        for (Position historyPosition : historyPositionList) {
             /*//查询平仓数据
            List<ClosePosition> closedPositionList = closePositionServiceImpl.closePositionByPositionId(historyPosition.getPositionId());
            BigDecimal total
            closedPositionList.forEach(closePosition -> {
            //统计盈利
                BigDecimal transactionAmount = closePosition.getTransactionAmount();

            });*/
            earnings = earnings.add(historyPosition.getProfitAndLoss() == null? BigDecimal.ZERO :historyPosition.getProfitAndLoss());
            principalAmount = principalAmount.add(historyPosition.getTotalPrincipalAmount());
            if(historyPosition.getProfitAndLoss() != null && historyPosition.getProfitAndLoss().compareTo(BigDecimal.ZERO) > 0){
                profitOrderCount = profitOrderCount.add(BigDecimal.ONE);
            }
        }
        Map<String,BigDecimal> resultMap = new HashMap<>();
        resultMap.put("earnings",earnings);
        resultMap.put("principalAmount",principalAmount);
        resultMap.put("positionSize",new BigDecimal(historyPositionList.size()));
        resultMap.put("profitOrderCount", profitOrderCount);
        return resultMap;
    }
    
    @Override
    public List<Position> updatePositionList(Long traderId, Date startTime, Date endTime) {
    	List<Position> historyPositionList = ((PositionMapper) baseMapper).updatePositionList(traderId, startTime, endTime);
    	return historyPositionList;
    }

    @Override
    public BigDecimal sumFollowAmount(Long traderId) {
        return ((PositionMapper)baseMapper).sumFollowAmount(traderId);
    }
    
    @Override
    public BigDecimal sumFollowAmountToday(Long traderId, Long startTime) {
    	return ((PositionMapper)baseMapper).sumFollowAmountToday(traderId,startTime);
    }

	@Override
	public List<PositionDto> selectPositionStatusNot30All() {
		return ((PositionMapper)baseMapper).selectPositionStatusNot30All();
	}
	
    @Override
    public Integer getPositionCount(Long traderId) {
        QueryWrapper<Position> positionQueryWrapper = new QueryWrapper<>();
        positionQueryWrapper.eq("trader_id",traderId);
        positionQueryWrapper.ne("status",30);
        return count(positionQueryWrapper);
    }
    
    @Override
    public Integer getStudentPositionCount(Long customerId,Long traderId,String symbol) {
    	QueryWrapper<Position> positionQueryWrapper = new QueryWrapper<>();
    	positionQueryWrapper.eq("customer_id",customerId);
    	positionQueryWrapper.eq("trader_id",traderId);
    	positionQueryWrapper.eq("symbol",symbol);
        positionQueryWrapper.ne("status",30);
    	return count(positionQueryWrapper);
    }
    
    @Override
    public Integer getStudentPositionCount(Long customerId, Long traderPositionId) {
    	QueryWrapper<Position> positionQueryWrapper = new QueryWrapper<>();
    	positionQueryWrapper.eq("customer_id",customerId);
    	positionQueryWrapper.eq("trader_position_id",traderPositionId);
        positionQueryWrapper.ne("status",30);
    	return count(positionQueryWrapper);
    }
    
    @Override
    public Page<PositionVo> list(PositionForm positionForm) {
    	Page page = positionForm.newFormPage();
    	List<PositionVo> list = ((PositionMapper)baseMapper).page(page, positionForm);
        page.setRecords(list);
        return page;
    }
    
	@Override
	public BigDecimal selectDividendFee(Position position) {
		return ((PositionMapper)baseMapper).selectDividendFee(position);
	}
	
	@Override
	public BigDecimal selectCommission(Position position) {
		return ((PositionMapper)baseMapper).selectCommission(position);
	}
	
	@Override
	public BigDecimal selectStudentProfit(Long customerId, Long traderId) {
		return ((PositionMapper)baseMapper).selectStudentProfit(customerId,traderId);
	}

	@Override
	public PositionStatisticsVo getPositionStatistics() {
		PositionStatisticsVo positionStatisticsVo = new PositionStatisticsVo();
		
		BigDecimal totalDividendFee = ((PositionMapper)baseMapper).selectDividendFee(new Position());
		positionStatisticsVo.setTotalDividendFee(totalDividendFee);
		
		BigDecimal totalFollowAmount = ((PositionMapper)baseMapper).sumTotalFollowAmount();
		positionStatisticsVo.setTotalFollowAmount(totalFollowAmount);
		
		return positionStatisticsVo;
	}
	
    @Override
    public Integer getPositionCountForTeacherOrStudent(Long traderId,Long customerId) {
    	QueryWrapper<Position> positionQueryWrapper = new QueryWrapper<>();
    	positionQueryWrapper.eq("trader_id",traderId);
    	positionQueryWrapper.eq("customer_id",customerId);
    	positionQueryWrapper.ne("status",30);
    	return count(positionQueryWrapper);
    }
}
