package com.bizzan.bitrade.service;

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

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

import com.bizzan.bitrade.constant.CommonStatus;
import com.bizzan.bitrade.constant.RewardRecordType;
import com.bizzan.bitrade.constant.TransactionType;
import com.bizzan.bitrade.dao.GameRecordDao;
import com.bizzan.bitrade.entity.GameRecord;
import com.bizzan.bitrade.entity.Member;
import com.bizzan.bitrade.entity.MemberTransaction;
import com.bizzan.bitrade.entity.MemberWallet;
import com.bizzan.bitrade.entity.MemberWeightUpper;
import com.bizzan.bitrade.entity.RewardRecord;
import com.bizzan.bitrade.pagination.Criteria;
import com.bizzan.bitrade.pagination.Restrictions;
import com.bizzan.bitrade.util.BigDecimalUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class GameRecordService {

	@Autowired
	private GameRecordDao dao;
    @Autowired
    private GameWalletService gameWalletService;
    @Autowired
    private MemberService memberService;
    @Autowired
    private MemberWeightUpperService memberWeightUpperService;
    @Autowired
    private MemberWalletService memberWalletService;
    @Autowired
    private MemberTransactionService memberTransactionService;
    @Autowired
    private RewardRecordService rewardRecordService;
	
	public void save(GameRecord entity) {
		dao.save(entity);
	}
	
	public GameRecord findOne(Long id) {
		return dao.findOne(id);
	}
	
	@Transactional(rollbackFor = Exception.class)
	public GameRecord open(Long memberId, String username, BigDecimal amount, String batchName, String remark) {
		BigDecimal fee = amount.multiply(BigDecimal.valueOf(0.1));
		boolean freezeResult = gameWalletService.freeze(memberId, amount.add(fee));
		if(!freezeResult) {
			return null;
		}
		
		GameRecord gameRecord = new GameRecord();
		gameRecord.setMemberId(memberId);
		gameRecord.setUsername(username);
		gameRecord.setCreateTime(new Date());
		gameRecord.setAmount(amount);
		gameRecord.setFee(fee);
		gameRecord.setStatus(0);
		gameRecord.setRewardStatus(0);
		gameRecord.setBatchName(batchName);
		gameRecord.setRemark(remark);
		return dao.save(gameRecord);
	}
	
	public List<GameRecord> findCanRewardOrders() {
        Criteria<GameRecord> specification = new Criteria<GameRecord>();
        specification.add(Restrictions.eq("rewardStatus", 0, false));
        specification.add(Restrictions.eq("status", 1, false));
        return dao.findAll(specification);
    
	}
	
	@Transactional(rollbackFor = Exception.class)
    public BigDecimal sendReturnReward(GameRecord order) {
        if(order==null){
            return BigDecimal.ZERO;
        }
        //BigDecimal fee = order.getAmount().multiply(BigDecimal.valueOf(0.05));
        BigDecimal fee = order.getAmount();
        dao.updateRewardStatus(order.getId());
        Member member = memberService.findOne(order.getMemberId());
        if(member.getDisableReward() == 1)
        	return BigDecimal.ZERO;
        if(fee.compareTo(BigDecimal.ZERO)<=0)
        	return BigDecimal.ZERO;
        executeReward(order, member, order.getMemberId(), fee, 0);
        return fee;
	}
	
	public void executeReward(GameRecord order, Member fromMember, Long agentId, BigDecimal fee, int allocatedRate) {
    	MemberWeightUpper upper = memberWeightUpperService.findMemberWeightUpperByMemberId(agentId);
    	
    	if(upper.getWcRate()!=null && upper.getWcRate()>0){
            Integer currentRate=upper.getWcRate() - allocatedRate;
            if(currentRate<0) {
            	log.error("rate error, currentRate={}, upper={}", currentRate, upper.getMemberId());
            	return;
            }
            if(currentRate>0) {
	            //应返比例
	            BigDecimal rate = BigDecimal.valueOf(currentRate).divide(BigDecimal.valueOf(100),8,BigDecimal.ROUND_DOWN);
	            //返佣
	            MemberWallet memberWallet = memberWalletService.findByCoinUnitAndMemberId("USDT", upper.getMemberId());
	            BigDecimal reward = BigDecimalUtils.mulDown(fee ,rate, 8);
	            Member agentMember = memberService.findOne(agentId);
	            if (reward.compareTo(BigDecimal.ZERO) > 0 && agentMember.getDisableReward()==0 && agentMember.getStatus()==CommonStatus.NORMAL) {
	                memberWalletService.increaseBalance(memberWallet.getId(), reward);
	                
	                RewardRecord rewardRecord = new RewardRecord();
	                rewardRecord.setCoin(memberWallet.getCoin());
	                rewardRecord.setMember(memberService.findOne(agentId));
	                rewardRecord.setFromMember(fromMember);
	                rewardRecord.setType(RewardRecordType.GAMEAWARD);
	                rewardRecord.setAmount(reward);
	                rewardRecordService.save(rewardRecord);
	                
	                MemberTransaction memberTransaction = new MemberTransaction();
	                memberTransaction.setAmount(reward);
	                memberTransaction.setFee(BigDecimal.ZERO);
	                memberTransaction.setMemberId(upper.getMemberId());
	                memberTransaction.setSymbol("USDT");
	                memberTransaction.setType(TransactionType.GAME_AWARD);
	                memberTransaction.setDiscountFee("0");
	                memberTransaction.setRealFee("0");
	                memberTransaction.setAddress("");
	                memberTransaction = memberTransactionService.save(memberTransaction);
	            }	
            }
        }
    	
    	if(upper.getUpper() == null)
    		return;
    	else {
    		int wcRate;
    		if(upper.getWcRate() == null || upper.getWcRate() == 0)
    			wcRate = allocatedRate;
    		else
    			wcRate = upper.getWcRate();
    		executeReward(order, fromMember, Long.parseLong(upper.getUpper()), fee, wcRate);
    	}
    }
	
	public BigDecimal sumAmountByMemberIdsAndTime(String startTime, String endTime, List<Long> ids) {
    	BigDecimal amount =  dao.sumAmountByMemberIdsAndTime(startTime, endTime, ids);
    	if(amount == null)
    		return BigDecimal.ZERO;
    	else
    		return amount;
    }
}
