package com.bizzan.bitrade.service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.bizzan.bitrade.dao.FollowWalletDao;
import com.bizzan.bitrade.entity.ContractCoin;
import com.bizzan.bitrade.entity.FollowAccount;
import com.bizzan.bitrade.entity.FollowWallet;
import com.bizzan.bitrade.entity.MemberWallet;
import com.bizzan.bitrade.util.RedisManager;
import com.querydsl.core.types.Predicate;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class SpecialFollowWalletService implements WalletService {
	@Autowired
	private FollowWalletDao dao;
	@Autowired
	private MemberTransactionService transactionService;
	@Autowired
	private MemberService memberService;
	@Autowired
	private ContractCoinService contractCoinService;
	@Autowired
	private SysConfigService sysConfigService;
    @Autowired
    private MemberContractWalletService memberContractWalletService;
	@Autowired
	private RedisManager redisManager;
    @Autowired
    private MemberWalletService memberWalletService;

	@Transactional(rollbackFor = Exception.class)
	public void transferIn(Long id, BigDecimal amount) {
		dao.increaseSpecialBalance(id, amount);
	}
	@Transactional(rollbackFor = Exception.class)
	public void transferOut(Long id, BigDecimal amount) {
		dao.decreaseSpecialBalance(id, amount);
	}
	
	@Transactional(rollbackFor = Exception.class)
	public void clearOpenFee(Long id, ContractCoin coin, BigDecimal margin, BigDecimal openFee) {
		dao.clearSpecialOpenFee(id, margin, openFee);
		//contractCoinService.increaseTotalCloseFee(coin.getId(), openFee);
		
		transactionService.recordFollowFee(id, coin.getBaseSymbol(), openFee, 0);
		
		//memberContractWalletService.thawUsdtBalance(id, coin, margin.add(openFee));
	}
	
	@Transactional(rollbackFor = Exception.class)
	public void clearContractCloseFee(Long id, ContractCoin coin, BigDecimal amount) {
		dao.clearSpecialCloseFee(id, amount);
		//contractCoinService.increaseTotalCloseFee(coin.getId(), amount);
		
		transactionService.recordFollowFee(id, coin.getBaseSymbol(), amount, 1);
	}
	
	@Transactional(rollbackFor = Exception.class)
	public void clearProfitOrLoss(Long id, ContractCoin coin, BigDecimal amount) {
		dao.increaseSpecialBalance(id, amount);
		//if(amount.compareTo(BigDecimal.ZERO)>0)
		//	contractCoinService.increaseTotalProfit(coin.getId(), amount);
		//else
		//	contractCoinService.increaseTotalLoss(coin.getId(), BigDecimal.ZERO.subtract(amount));
		
		transactionService.recordFollowProfitOrLoss(id, coin.getBaseSymbol(), amount);
	}
	
	@Transactional(rollbackFor = Exception.class)
	public void clearFollowDividend(Long id, Long traderId, ContractCoin coin, BigDecimal amount) {
		//MemberWallet memberWallet = memberWalletService.findByCoinUnitAndMemberId("USDT", traderId);
		//memberWalletService.increaseBalance(memberWallet.getId(), amount);
		
		dao.increaseSpecialBalance(id, BigDecimal.ZERO.subtract(amount));
		transactionService.recordFollowDividend(id, coin.getBaseSymbol(), BigDecimal.ZERO.subtract(amount));
		//transactionService.recordFollowDividend(traderId, coin.getBaseSymbol(), amount);
	}
	
	@Transactional(rollbackFor = Exception.class)
	public void clearContractOvernightFee(Long id, ContractCoin coin, BigDecimal amount) {
		int count = dao.clearContractOvernightFee(id, amount);
		//contractCoinService.increaseTotalCloseFee(coin.getId(), amount);
		if(count!=0)
			transactionService.recordFollowOvernightFee(id, coin.getBaseSymbol(), amount);
	}
	
	@Transactional(rollbackFor = Exception.class)
	public boolean freezeMarginAndFee(Long id, ContractCoin contractCoin, BigDecimal amount) {
		int successCount = dao.freezeSpecialMargin(id, amount);
		if(successCount == 0)
			return false;

		//memberContractWalletService.freezeUsdtBalance(id, contractCoin, amount);
		return true;
	}

	@Transactional(rollbackFor = Exception.class)
	public boolean freezeMarginDirectly(Long id, ContractCoin coin, BigDecimal principal, BigDecimal fee) {
		return freezeMarginDirectly(id, coin, principal, fee, null);
	}

	@Transactional(rollbackFor = Exception.class)
	public boolean freezeMarginDirectly(Long id, ContractCoin coin, BigDecimal principal, BigDecimal fee, Long openTime) {
		BigDecimal required = principal.add(fee);
		int result = dao.freezeBalanceDirect(id, required, principal);
		if (result == 0) {
			FollowWallet wallet = dao.findOne(id);
			log.warn("【批量开仓】保证金不足, memberId={}, 应冻结={}, 实际余额={}",
					id, required, wallet != null ? wallet.getBalance() : "查询失败");
			return false;
		}
		if (openTime != null) {
			transactionService.recordFollowFee(id, coin.getBaseSymbol(), fee, 0, new Date(openTime));
		} else {
			transactionService.recordFollowFee(id, coin.getBaseSymbol(), fee, 0);
		}
		return true;
	}
	
	//解冻保证金
	@Transactional(rollbackFor = Exception.class)
	public void thawMargin(Long id, ContractCoin contractCoin, BigDecimal amount) {
		dao.thawSpecialMargin(id, amount);
		
		//memberContractWalletService.thawUsdtBalance(id, contractCoin, amount);
	}
	
	//释放已使用保证金
	@Transactional(rollbackFor = Exception.class)
	public void releaseMargin(Long id, BigDecimal amount) {
		dao.releaseSpecialMargin(id, amount);
	}
	
	public FollowWallet findOne(Long id) {
		FollowWallet entity = dao.findOne(id);
		if(entity == null) {
			entity = new FollowWallet();
			entity.setId(id);
			entity.setBalance(BigDecimal.ZERO);
			entity.setFrozenBalance(BigDecimal.ZERO);
			entity.setFrozenMargin(BigDecimal.ZERO);
			entity.setLeverage(BigDecimal.TEN);
			dao.save(entity);
		}
		return entity;
	}
	
	public ConcurrentHashMap<Long, FollowAccount> findAllWithPositions() {
		ConcurrentHashMap<Long, FollowAccount> accountMap = new ConcurrentHashMap<>();
		List<FollowWallet> list = dao.findAllWithPositions();
		for(FollowWallet userPurse: list) {
			FollowAccount vo = new FollowAccount();
			BeanUtils.copyProperties(userPurse, vo);
			//vo.setBlastMarginRate(sysConfigService.get().getContractMarginRate());
			//vo.setWalletList(memberContractWalletService.findEnabledByMemberId(userPurse.getId()));
			accountMap.put(vo.getId(), vo);
		}
		return accountMap;
	}
	
	public FollowAccount findOneVO(Long id) {
		FollowWallet entity = findOne(id);
		FollowAccount vo = new FollowAccount();
		BeanUtils.copyProperties(entity, vo);
		vo.setBlastMarginRate(sysConfigService.get().getContractMarginRate());
		vo.setWalletList(memberContractWalletService.findEnabledByMemberId(id));
		//vo.setTodayRevenue(this.getTodayRevenue(id));
		return vo;
	}
	
	public FollowAccount findOneVOFromRedis(Long id) {
		FollowAccount account = findOneVO(id);
		redisManager.saveFollowAccount(id, JSON.toJSONString(account));
		return account;
	}

	public List<FollowWallet> findByIds(List<Long> ids) {
		return dao.findByIds(ids);
	}
	
	public void deleteVOFromRedis(Long id) {
		redisManager.removeFollowAccount(id);
	}
	
	public BigDecimal getBalanceById(Long id) {
		return dao.getBalanceById(id);
	}
	
	public void updatePercent(Long id, BigDecimal profitPercent, BigDecimal lossPercent) {
		dao.updatePercent(id, profitPercent, lossPercent);
	}
	
	public Page<FollowWallet> findAll(Predicate predicate, Pageable pageable) {
		return dao.findAll(predicate, pageable);
	}
	@Override
	public void clearContractOvernightFee(Long id, ContractCoin coin, BigDecimal amount, BigDecimal rebateFee) {
		// TODO Auto-generated method stub
		
	}
}
