package com.bizzan.bitrade.vo;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;

import com.alibaba.fastjson.JSON;
import com.bizzan.bitrade.entity.ContractCoin;
import com.bizzan.bitrade.entity.ContractMoneyType;
import com.bizzan.bitrade.entity.ContractOrderDirection;
import com.bizzan.bitrade.entity.ContractPositionType;
import com.bizzan.bitrade.entity.MemberContractPosition;
import com.bizzan.bitrade.entity.MemberContractWallet;
import com.bizzan.bitrade.entity.UserPurse;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@ApiModel("交易账户对象")
public class TradingAccount implements Serializable {
	private static final Long serialVersionUID = 101L;
	
	private Map<String, BigDecimal> currentPriceMap;
	private int blastMarginRate;
	@ApiModelProperty("合约币种列表 用于获取各币种当前保证金和杠杆")
	private List<MemberContractWalletVo> walletList = new ArrayList<MemberContractWalletVo>();
	
	public void genWalletList() {
		for(MemberContractWalletVo wallet: walletList) {
			wallet.setUsdtBuyPrincipalAmount(BigDecimal.ZERO);
		}
		
		if(this.getCurrentPositionWithCutList()!=null) {
			for(MemberContractPosition position: this.getCurrentPositionWithCutList()) {
				// 体验金仓位不计入已用保证金
				if(position.getExperienceRecordId() != null) continue;
				MemberContractWalletVo wallet = this.getWalletByContractId(position.getCoin().getId());
				if(wallet == null)
					continue;
				wallet.setUsdtBuyPrincipalAmount(wallet.getUsdtBuyPrincipalAmount().add(position.getCurrentMargin()));
			}
		}
		
		for(MemberContractWalletVo wallet: walletList) {
			BigDecimal availableForOpen = wallet.getContractCoin().getMaxTotalShare().subtract(wallet.getUsdtBuyPrincipalAmount().add(wallet.getUsdtFrozenBalance()));
			if(availableForOpen.compareTo(getAvailableBalance())>0) {
				availableForOpen = getAvailableBalance();
				if(availableForOpen.compareTo(BigDecimal.ZERO)<0)
					availableForOpen = BigDecimal.ZERO;
				wallet.setUsdtBalance(availableForOpen);
			} else {
				wallet.setUsdtBalance(availableForOpen);
				BigDecimal availableForOpenWithFee = availableForOpen.add(availableForOpen.multiply(wallet.getContractCoin().getOpenFee())
						.multiply(wallet.getUsdtBuyLeverage()));
				if(availableForOpenWithFee.compareTo(getAvailableBalance())>0)
					availableForOpen = getAvailableBalance();
				else
					availableForOpen = availableForOpenWithFee;
			}
			//availableForOpen = availableForOpen.subtract(wallet.getUsdtFrozenBalance());
			
			if(currentPriceMap!=null && currentPriceMap.containsKey(wallet.getContractCoin().getSymbol())) {
				BigDecimal volume = availableForOpen
        			.divide(currentPriceMap.get(wallet.getContractCoin().getSymbol()).multiply(wallet.getContractCoin().getOpenFee().add(BigDecimal.ONE.divide(wallet.getUsdtBuyLeverage(), 8, BigDecimal.ROUND_UP))), 2, BigDecimal.ROUND_DOWN);
				wallet.setUsdtBuyPosition(volume);
			}
		}
		//return walletList;
	}
	
	public MemberContractWalletVo getWalletByContractId(Long contractId) {
		for(MemberContractWalletVo wallet: walletList) {
			if(wallet.getContractCoin().getId().longValue() == contractId.longValue())
				return wallet;
		}
		return null;
	}
	
	public BigDecimal sumCurrentMarginByContractId(long contractId) {
		BigDecimal currentContractMargin = BigDecimal.ZERO;
		if(this.getCurrentPositionWithCutList()==null)
			return currentContractMargin;
		for(MemberContractPosition position: this.getCurrentPositionWithCutList()) {
			if(position.getCoin().getId().longValue() == contractId)
				currentContractMargin = currentContractMargin.add(position.getCurrentMargin());
		}
		return currentContractMargin;
	}

	public List<MemberContractWalletVo> getWalletList() {
		return this.walletList;
	}
	public void setWalletList(List<MemberContractWalletVo> walletList) {
		this.walletList = walletList;
	}

	public void setCurrentPriceMap(Map<String, BigDecimal> currentPriceMap) {
		this.currentPriceMap = currentPriceMap;
		if(this.getCurrentPositionWithCutList()==null || currentPriceMap == null)
			return;
		for(MemberContractPosition position: this.getCurrentPositionWithCutList()) {
			//log.info("coin={}", position.getCoin());
			if (currentPriceMap.containsKey(position.getCoin().getSymbol()))
				position.setCurrentPrice(currentPriceMap.get(position.getCoin().getSymbol()));
		}
	}
	
	public Map<String, BigDecimal> getcurrentPriceMap() {
		return this.currentPriceMap;
	}
	
	public void setBlastMarginRate(int blastMarginRate) {
		this.blastMarginRate = blastMarginRate;
	}

	/**
     * 获取可用余额，开仓或者提币
     * @return
     */
	@ApiModelProperty("可用开仓余额 用于客户端计算可开张数")
    public BigDecimal getAvailableBalance() {
    	BigDecimal revenue = this.getCurrentRevenue();
    	BigDecimal currentBalance = this.getCurrentBalance();
    	//currentBalance = currentBalance.compareTo(this.getBalance())<0?currentBalance:this.getBalance();
    	if(revenue.compareTo(BigDecimal.ZERO)<0)
    		currentBalance = currentBalance.add(revenue);
    	if(currentBalance.compareTo(BigDecimal.ZERO)<0)
    		currentBalance = BigDecimal.ZERO;
    	return currentBalance;
    		//return this.getBalance().add(this.getFrozenBalance()).subtract(this.getCurrentMargin()).add(revenue);
    }
	
	@ApiModelProperty("可用开仓余额")
    public BigDecimal getAvailableBalanceForOpen() {
    	BigDecimal revenue = this.getCurrentRevenue();
    	//BigDecimal currentBalance = this.getCurrentBalance();
    	//currentBalance = currentBalance.compareTo(this.getBalance())<0?currentBalance:this.getBalance();
    	if(revenue.compareTo(BigDecimal.ZERO)>0)
    		return this.getBalance();
    	else
    		return this.getBalance().add(revenue);
    		//return this.getBalance().add(this.getFrozenBalance()).subtract(this.getCurrentMargin()).add(revenue);
    }
    
    /**
     * 获取当前用户总收益
     * @param currentPriceMap
     * @return
     */
	@ApiModelProperty("账户当前收益")
    public BigDecimal getCurrentRevenue() {
    	BigDecimal revenue = BigDecimal.ZERO;
    	if(currentPriceMap == null || this.getCurrentPositionWithCutList()==null)
    		return revenue;
    	for(MemberContractPosition position : this.getCurrentPositionWithCutList()) {
    		// 体验金仓位不计入当前收益（与 getCurrentMargin() 保持一致）
    		if(position.getExperienceRecordId() != null) continue;
    		revenue = revenue.add(position.getCurrentProfit());
    	}
    	return revenue;
    }
    
	@ApiModelProperty("账户当前权益")
    public BigDecimal getCurrentCapital() {
    	return this.getBalance().add(this.getFrozenBalance()).add(this.getFrozenMargin()).add(this.getCurrentRevenue());
    }
	
	@ApiModelProperty("账户静态权益")
	public BigDecimal getStaticBalance() {
		return this.getBalance().add(this.getFrozenBalance()).add(this.getFrozenMargin());
	}
	
	@ApiModelProperty("账户当前保证金")
    public BigDecimal getCurrentMargin() {
    	BigDecimal margin = BigDecimal.ZERO;
    	if(currentPriceMap == null || this.getCurrentPositionWithCutList()==null)
    		return margin;
    	for(MemberContractPosition position : this.getCurrentPositionWithCutList()) {
    		// 体验金仓位不计入已用保证金
    		if(position.getExperienceRecordId() != null) continue;
    		margin = margin.add(position.getCurrentMargin());
    	}
    	return margin;
    }
	
	@ApiModelProperty("账户当前余额(调整保证金后)")
    public BigDecimal getCurrentBalance() {
    	return this.getBalance().add(this.getFrozenBalance()).subtract(getCurrentMargin());
    }
	
	public Map<ContractCoin, BigDecimal> findMarginMap() {
		Map<ContractCoin, BigDecimal> marginMap = new HashMap<ContractCoin, BigDecimal>();
		if(currentPriceMap == null || this.getCurrentPositionWithCutList()==null)
			return marginMap;
		for(MemberContractPosition position : this.getCurrentPositionWithCutList()) {
			// 体验金仓位不参与资金费率计算
			if(position.getExperienceRecordId() != null)
				continue;
			if(marginMap.containsKey(position.getCoin())) {
				marginMap.put(position.getCoin(), marginMap.get(position.getCoin()).add(position.getCurrentMargin()));
			} else
				marginMap.put(position.getCoin(), position.getCurrentMargin());
    	}
		return marginMap;
	}
	
	public Map<ContractCoin, BigDecimal> findMarketValueMap() {
		Map<ContractCoin, BigDecimal> marketValueMap = new HashMap<ContractCoin, BigDecimal>();
		if(currentPriceMap == null || this.getCurrentPositionWithCutList()==null)
			return marketValueMap;
		for(MemberContractPosition position : this.getCurrentPositionWithCutList()) {
			if(marketValueMap.containsKey(position.getCoin())) {
				marketValueMap.put(position.getCoin(), marketValueMap.get(position.getCoin()).add(position.getCurrentMarketValue()));
			} else
				marketValueMap.put(position.getCoin(), position.getCurrentMarketValue());
    	}
		return marketValueMap;
	}
	
	@ApiModelProperty("账户仓位总市值 多单和空单")
	public BigDecimal[] getMaketValue() {
		BigDecimal buyMarketValue = BigDecimal.ZERO;
		BigDecimal sellMarketValue = BigDecimal.ZERO;
		if(currentPriceMap == null || this.getCurrentPositionWithCutList()==null)
    		return new BigDecimal[] {buyMarketValue, sellMarketValue};
    	for(MemberContractPosition position : this.getCurrentPositionWithCutList()) {
    		if(position.getDirection() == ContractOrderDirection.BUY)
    			buyMarketValue = buyMarketValue.add(position.getCurrentMarketValue());
    		else
    			sellMarketValue = sellMarketValue.add(position.getCurrentMarketValue());
    	}
		return new BigDecimal[] {buyMarketValue, sellMarketValue};
	}
    
    public BigDecimal getCurrentPositionByContractCoinIdAndDirection(Long contractCoinId, ContractOrderDirection direction) {
    	BigDecimal currentPosition = BigDecimal.ZERO;
    	if(this.getCurrentPositionWithCutList()==null)
    		return currentPosition;
    	for(MemberContractPosition position : this.getCurrentPositionWithCutList()) {
    		if(position.getCoin().getId().longValue()==contractCoinId.longValue() && position.getDirection()==direction)
    			currentPosition = currentPosition.add(position.getCurrentPosition());
    	}
    	return currentPosition;
    }
    
    public BigDecimal getEstimatedBlastRate() {
    	if(this.getCurrentPositionWithCutList()==null || this.getCurrentPositionWithCutList().size()==0)
    		return BigDecimal.ZERO;
    	
    	BigDecimal[] marketValueArray = this.getMaketValue();
    	BigDecimal marketValue = marketValueArray[0].subtract(marketValueArray[1]);
    	if(marketValue.compareTo(BigDecimal.ZERO)==0)
    		return BigDecimal.ZERO; 
    	BigDecimal rate = this.getCurrentCapital().subtract(this.getCurrentMargin().multiply(BigDecimal.valueOf(blastMarginRate/100.0)))
    			.divide(marketValue, 8, BigDecimal.ROUND_HALF_UP);
    	return rate;
    }
    
    @ApiModelProperty("今日收益")
    private BigDecimal todayRevenue;

	public BigDecimal getTodayRevenue() {
		if (todayRevenue == null)
			return BigDecimal.ZERO;
		else
			return todayRevenue;
	}

	public void setTodayRevenue(BigDecimal todayRevenue) {
		this.todayRevenue = todayRevenue;
	}
	
	@ApiModelProperty("今日动态收益")
	private BigDecimal currentTodayRevenue;
	
	/*@ApiModelProperty("今日动态收益")
	public BigDecimal getCurrentTodayRevenue() {
		if(this.todayRevenue != null)
			return this.todayRevenue.add(this.getCurrentRevenue());
		else
			return BigDecimal.ZERO;
	}*/
	
	public BigDecimal getCurrentTodayRevenue() {
		return currentTodayRevenue;
	}

	public void setCurrentTodayRevenue(BigDecimal currentTodayRevenue) {
		this.currentTodayRevenue = currentTodayRevenue;
	}

	@ApiModelProperty("用户名")
	private String username;
	
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public BigDecimal getCashBalance() {
		return cashBalance;
	}

	public void setCashBalance(BigDecimal cashBalance) {
		this.cashBalance = cashBalance;
	}

	@ApiModelProperty("账户实时总余额")
	private BigDecimal cashBalance;
	
	@ApiModelProperty("跟单账户余额")
	private BigDecimal followBalance;

	public BigDecimal getFollowBalance() {
		return followBalance;
	}

	public void setFollowBalance(BigDecimal followBalance) {
		this.followBalance = followBalance;
	}
	
	private Long id;
    public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public BigDecimal getBalance() {
		return balance;
	}

	public void setBalance(BigDecimal balance) {
		this.balance = balance;
	}

	public BigDecimal getFrozenBalance() {
		return frozenBalance;
	}

	public void setFrozenBalance(BigDecimal frozenBalance) {
		this.frozenBalance = frozenBalance;
	}

	public BigDecimal getFrozenMargin() {
		return frozenMargin;
	}

	public void setFrozenMargin(BigDecimal frozenMargin) {
		this.frozenMargin = frozenMargin;
	}

	public ContractPositionType getPositionType() {
		return positionType;
	}

	public void setPositionType(ContractPositionType positionType) {
		this.positionType = positionType;
	}

	public ContractMoneyType getMoneyType() {
		return moneyType;
	}

	public void setMoneyType(ContractMoneyType moneyType) {
		this.moneyType = moneyType;
	}

	public Integer getIsSupervised() {
		return isSupervised;
	}

	public void setIsSupervised(Integer isSupervised) {
		this.isSupervised = isSupervised;
	}

	@ApiModelProperty("账户余额")
    private BigDecimal balance;
    @ApiModelProperty("已用保证金")
    private BigDecimal frozenBalance;
    @ApiModelProperty("冻结保证金")
    private BigDecimal frozenMargin;
    @ApiModelProperty("仓位类型：0合仓，1分仓")
    @Enumerated(EnumType.ORDINAL)
    private ContractPositionType positionType;
    @ApiModelProperty("资金类型：0U本位，1币本位")
    @Enumerated(EnumType.ORDINAL)
    private ContractMoneyType moneyType;
    @ApiModelProperty("账户是否被监控")
    private Integer isSupervised;
    private List<MemberContractPositionWithCut> currentPositionWithCutList;

	public List<MemberContractPositionWithCut> getCurrentPositionWithCutList() {
		return currentPositionWithCutList;
	}

	public void setCurrentPositionWithCutList(List<MemberContractPositionWithCut> currentPositionWithCutList) {
		this.currentPositionWithCutList = currentPositionWithCutList;
	}
	
	@ApiModelProperty("今日收益率")
	public BigDecimal getTodayRevenueRate() {
		if(todayInitialCapital == null || todayInitialCapital.compareTo(BigDecimal.ZERO)==0 || this.getCurrentTodayRevenue()==null)
			return null;
		return this.getCurrentTodayRevenue().divide(this.todayInitialCapital, 4, BigDecimal.ROUND_HALF_UP);
	}
	
	private String currentDate;
	public String getCurrentDate() {
		return currentDate;
	}

	public void setCurrentDate(String currentDate) {
		this.currentDate = currentDate;
	}

	public BigDecimal getTodayInitialCapital() {
		return todayInitialCapital;
	}

	public void setTodayInitialCapital(BigDecimal todayInitialCapital) {
		this.todayInitialCapital = todayInitialCapital;
	}

	private BigDecimal todayInitialCapital;
	
	@ApiModelProperty("资产账户 获取可用资产和冻结资产")
	private SpotWalletVo spotWallet;

	public SpotWalletVo getSpotWallet() {
		return spotWallet;
	}

	public void setSpotWallet(SpotWalletVo spotWallet) {
		this.spotWallet = spotWallet;
	}
	
	@ApiModelProperty("账户信息列表 包括合约和跟单等账户")
	private List<AccountInfo> accountInfoList;

	public List<AccountInfo> getAccountInfoList() {
		return accountInfoList;
	}

	public void setAccountInfoList(List<AccountInfo> accountInfoList) {
		this.accountInfoList = accountInfoList;
	}
	
	public MemberContractPosition findPositionById(Long positionId) {
		if(this.getCurrentPositionWithCutList()!=null) {
			for(MemberContractPosition position: this.getCurrentPositionWithCutList()) {
				if (position.getId().longValue() == positionId.longValue())
					return position;
			}
		}
		return null;
	}
	
	public String toStdString() {
		return JSON.toJSONString(this.getCurrentPositionWithCutList());
	}
}
