package com.bizzan.bitrade.controller.swap;

import com.bizzan.bitrade.annotation.AccessLog;
import com.bizzan.bitrade.constant.AdminModule;
import com.bizzan.bitrade.constant.PageModel;
import com.bizzan.bitrade.controller.common.BaseAdminController;
import com.bizzan.bitrade.entity.ContractRewardRecord;
import com.bizzan.bitrade.entity.FollowWallet;
import com.bizzan.bitrade.entity.GameWallet;
import com.bizzan.bitrade.entity.Member;
import com.bizzan.bitrade.entity.MemberWeightUpper;
import com.bizzan.bitrade.entity.QContractRewardRecord;
import com.bizzan.bitrade.entity.transform.AuthMember;
import com.bizzan.bitrade.model.MemberWithAmountVo;
import com.bizzan.bitrade.model.screen.ContractRewardRecordScreen;
import com.bizzan.bitrade.model.screen.MemberScreen;
import com.bizzan.bitrade.service.ContractRewardRecordService;
import com.bizzan.bitrade.service.FollowWalletService;
import com.bizzan.bitrade.service.MemberService;
import com.bizzan.bitrade.service.MemberWeightUpperService;
import com.bizzan.bitrade.service.UserPurseService;
import com.bizzan.bitrade.util.MessageResult;
import com.bizzan.bitrade.util.PredicateUtils;
import com.bizzan.bitrade.vo.RewardRecordVO;
import com.bizzan.bitrade.vo.RewardSetVo;
import com.bizzan.bitrade.vo.TradingAccount;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Sort;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.SessionAttribute;

import static com.bizzan.bitrade.constant.SysConstant.SESSION_MEMBER;
import static com.bizzan.bitrade.entity.QMember.member;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.annotation.Resource;

@RestController
@RequestMapping("/swap/reward")
@Slf4j
public class ContractRewardRecordController extends BaseAdminController {
	@Resource
    private ContractRewardRecordService contractRewardRecordService;

    @Autowired
    private MemberWeightUpperService memberWeightUpperService;
    @Autowired
    private MemberService memberService;
    @Autowired
    private UserPurseService userPurseService;
    @Autowired
    private FollowWalletService followWalletService;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    /**
     * 分页查询
     * @param pageModel
     * @param screen
     * @return
     */
    @RequiresPermissions("swap:reward:page-query")
    @PostMapping("page-query")
    @AccessLog(module = AdminModule.CONTRACTOPTION, operation = "永续合约返佣订单 列表")
    public MessageResult pageQuery(
            PageModel pageModel,
            ContractRewardRecordScreen screen) {
        if (pageModel.getDirection() == null && pageModel.getProperty() == null) {
            ArrayList<Sort.Direction> directions = new ArrayList<>();
            directions.add(Sort.Direction.DESC);
            pageModel.setDirection(directions);
            List<String> property = new ArrayList<>();
            property.add("createTime");
            pageModel.setProperty(property);
        }
        //获取查询条件
        Predicate predicate = getPredicate(screen);
        Page<ContractRewardRecord> all = contractRewardRecordService.findAll(predicate, pageModel.getPageable());
        return success(all);
    }
    
    @RequiresPermissions("swap:reward:modify")
    @PostMapping("modify")
    @AccessLog(module = AdminModule.CONTRACTOPTION, operation = "返佣设置")
    public MessageResult modify(
            @RequestParam("id") Long memberId,
            @RequestParam("rate") Integer rate,
            Integer type
            ) {
        if(memberId == null){
            return error("设置用户的id不能为空！");
        }
        if(rate == null){
            return error("设置用户的比例不能为空！");
        }
        if(rate.intValue() < 0 || rate.intValue() >= 100){
            return error("设置用户的比例不能为小于0%或超过100%！");
        }
        
        Member member = memberService.findOne(memberId);
        if(member.getInviterId()!=null) {
        	MemberWeightUpper upperMemberUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(member.getInviterId());
        	if(rate >= upperMemberUpper.getRate())
        		return error("设置用户的比例不能大于上级的比例！");
        	
        }

    	if(type == 1) {
    		MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(memberId);
    		int diff = memberWeightUpper.getRate()-rate;
	        memberWeightUpper.setRate(rate);
	        memberWeightUpperService.save(memberWeightUpper);
	        
    		List<MemberWeightUpper> lowerMemberUpperList = memberWeightUpperService.findAllByAllUppers(memberId);
    		for(MemberWeightUpper lowerMemberUpper : lowerMemberUpperList) {
    			int newRate = lowerMemberUpper.getRate()-diff;
    			newRate = (newRate>0)?newRate:0;
    			lowerMemberUpper.setRate(newRate);
    	        memberWeightUpperService.save(lowerMemberUpper);
    		}
    	} else {
    		List<MemberWeightUpper> lowerMemberUpperList = memberWeightUpperService.findAllByUpper(memberId);
	    	for(MemberWeightUpper lowerMemberUpper : lowerMemberUpperList) {
	    		if(rate <= lowerMemberUpper.getRate())
	    			return error("设置用户的比例不能小于下级的比例！");
	    	}
	        MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(memberId);
	        memberWeightUpper.setRate(rate);
	        memberWeightUpperService.save(memberWeightUpper);
    		
    	}
        //contractRewardRecordService.clearRewardSetVoById(0L);
        return success();
    }
    
    @RequiresPermissions("swap:reward:modify")
    @PostMapping("modify-follow")
    @AccessLog(module = AdminModule.CONTRACTOPTION, operation = "返佣设置")
    public MessageResult modifyFollow(
            @RequestParam("id") Long memberId,
            @RequestParam("rate") Integer rate,
            Integer type
            ) {
        if(memberId == null){
            return error("设置用户的id不能为空！");
        }
        if(rate == null){
            return error("设置用户的比例不能为空！");
        }
        if(rate.intValue() < 0 || rate.intValue() >= 100){
            return error("设置用户的比例不能为小于0%或超过100%！");
        }
        
        Member member = memberService.findOne(memberId);
        if(member.getInviterId()!=null) {
        	MemberWeightUpper upperMemberUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(member.getInviterId());
        	if(rate >= upperMemberUpper.getFollowRate())
        		return error("设置用户的比例不能大于上级的比例！");
        	
        }

    	if(type == 1) {
    		MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(memberId);
    		int diff = memberWeightUpper.getFollowRate()-rate;
	        memberWeightUpper.setFollowRate(rate);
	        memberWeightUpperService.save(memberWeightUpper);
	        
    		List<MemberWeightUpper> lowerMemberUpperList = memberWeightUpperService.findAllByAllUppers(memberId);
    		for(MemberWeightUpper lowerMemberUpper : lowerMemberUpperList) {
    			int newRate = lowerMemberUpper.getFollowRate()-diff;
    			newRate = (newRate>0)?newRate:0;
    			lowerMemberUpper.setFollowRate(newRate);
    	        memberWeightUpperService.save(lowerMemberUpper);
    		}
    	} else {
    		List<MemberWeightUpper> lowerMemberUpperList = memberWeightUpperService.findAllByUpper(memberId);
	    	for(MemberWeightUpper lowerMemberUpper : lowerMemberUpperList) {
	    		if(rate <= lowerMemberUpper.getFollowRate())
	    			return error("设置用户的比例不能小于下级的比例！");
	    	}
	        MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(memberId);
	        memberWeightUpper.setFollowRate(rate);
	        memberWeightUpperService.save(memberWeightUpper);
    		
    	}
        //contractRewardRecordService.clearRewardSetVoById(0L);
        return success();
    }
    
    @RequiresPermissions("swap:reward:modify")
    @PostMapping("modify-dividend")
    @AccessLog(module = AdminModule.CONTRACTOPTION, operation = "返分润设置")
    public MessageResult modifyDividend(
            @RequestParam("id") Long memberId,
            @RequestParam("rate") Integer rate
            ) {
        if(memberId == null){
            return error("设置用户的id不能为空！");
        }
        if(rate == null){
            return error("设置用户的比例不能为空！");
        }
        if(rate.intValue() < 0 || rate.intValue() >= 100){
            return error("设置用户的比例不能为小于0%或超过100%！");
        }
        
		MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(memberId);
		memberWeightUpper.setDividendRate(rate);
        memberWeightUpperService.save(memberWeightUpper);
    	
        return success();
    }
    
    @RequiresPermissions("swap:reward:modify")
    @PostMapping("modify-wc")
    @AccessLog(module = AdminModule.CONTRACTOPTION, operation = "返佣设置")
    public MessageResult modifyWc(
            @RequestParam("id") Long memberId,
            @RequestParam("rate") Integer rate
            ) {
        if(memberId == null){
            return error("设置用户的id不能为空！");
        }
        if(rate == null){
            return error("设置用户的比例不能为空！");
        }
        if(rate.intValue() < 0 || rate.intValue() >= 100){
            return error("设置用户的比例不能为小于0%或超过100%！");
        }
        
        /*Member member = memberService.findOne(memberId);
        if(member.getInviterId()!=null) {
        	MemberWeightUpper upperMemberUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(member.getInviterId());
        	if(upperMemberUpper.getWcRate()==null || (upperMemberUpper.getWcRate()!=null && rate >= upperMemberUpper.getWcRate()))
        		return error("设置用户的比例不能大于上级的比例！");
        	
        }*/
        int minUpperWcRate = memberWeightUpperService.findMinUpperWcRate(memberId);
        log.info("minUpperWcRate={}", minUpperWcRate);
        if(rate > minUpperWcRate) {
        	return error("设置用户的比例不能大于上级的比例！");
        }
        
		List<MemberWeightUpper> lowerMemberUpperList = memberWeightUpperService.findAllByUpper(memberId);
    	for(MemberWeightUpper lowerMemberUpper : lowerMemberUpperList) {
    		if(lowerMemberUpper.getWcRate()!=null && rate <= lowerMemberUpper.getWcRate())
    			return error("设置用户的比例不能小于下级的比例！");
    	}
        MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(memberId);
        memberWeightUpper.setWcRate(rate);
        memberWeightUpperService.save(memberWeightUpper);
        return success();
    }

    /**
     * 返佣设置查询
     * @return
     */
    @RequiresPermissions("swap:reward:rewardSets")
    @PostMapping("rewardSets")
    @AccessLog(module = AdminModule.CONTRACTOPTION, operation = "返佣设置查询")
    public MessageResult rewardSets() {
        //获取查询条件
        //RewardSetVo vo = contractRewardRecordService.findAllRewardSetVo();
    	RewardSetVo vo = contractRewardRecordService.findOneLevelRewardSetVo(0L);
        return success(vo);
    }

    /**
     * 清除返佣设置缓存
     * @return
     */
    @RequiresPermissions("swap:reward:clear")
    @PostMapping("clear")
    @AccessLog(module = AdminModule.CONTRACTOPTION, operation = "清除返佣设置缓存")
    public MessageResult clear() {
        //获取查询条件
        contractRewardRecordService.clearAllRewardSetVo();
        return success();
    }

    private Predicate getPredicate(ContractRewardRecordScreen screen) {
        ArrayList<BooleanExpression> booleanExpressions = new ArrayList<>();
        QContractRewardRecord qContractRewardRecord = QContractRewardRecord.contractRewardRecord;
        if(screen.getStartTime() != null) {
            booleanExpressions.add(qContractRewardRecord.createTime.goe(screen.getStartTime()));
        }
        if(screen.getEndTime() != null) {
            booleanExpressions.add(qContractRewardRecord.createTime.loe(screen.getEndTime()));
        }
        if(screen.getMemberId() != null) {
            booleanExpressions.add(qContractRewardRecord.member.id.eq(screen.getMemberId()));
        }
        if(screen.getType() != null) {
            booleanExpressions.add(qContractRewardRecord.type.eq(screen.getType()));
        }

        return PredicateUtils.getPredicate(booleanExpressions);
    }
    
    @PostMapping("/set/list")
    @ResponseBody
    public MessageResult pageByAgent(
            PageModel pageModel,
            MemberScreen screen) {
        Predicate predicate = getMemberPredicate(screen);
        Page<Member> all = memberService.findAll(predicate, pageModel.getPageable());
        List<MemberWithAmountVo> list = new ArrayList<MemberWithAmountVo>();
        all.forEach(member -> {
        	MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(member.getId());
        	
        	MemberWithAmountVo vo = new MemberWithAmountVo();
        	BeanUtils.copyProperties(member, vo);
        	vo.setDirectAgentCount(memberService.countDirectSuperAgentByInviterId(member.getId()));
        	if(memberWeightUpper!=null) {
        		vo.setRate(memberWeightUpper.getRate());
        		vo.setFollowRate(memberWeightUpper.getFollowRate());
        	}
        	
        	List<MemberWeightUpper> subList = memberWeightUpperService.findAllByAllUppers(member.getId());
            List<Long> subIds = new ArrayList<Long>();
            for(MemberWeightUpper upper: subList)
            	subIds.add(upper.getMemberId());
            subIds.add(member.getId());
            
            long followCount = followWalletService.countWithBalanceByMemberIds(subIds);
            vo.setFollowCount((int)followCount);
        	
            if(subIds.size()>0) {
	        	BigDecimal contractBalance = userPurseService.sumBalanceByMemberIds(subIds);
	        	BigDecimal followBalance = followWalletService.sumBalanceByMemberIds(subIds);
	        	vo.setContractBalance(contractBalance.doubleValue());
	        	vo.setFollowBalance(followBalance.doubleValue());
            } else {
            	vo.setContractBalance(0);
            	vo.setFollowBalance(0);
            }
        	
        	list.add(vo);
        });
        Page<MemberWithAmountVo> newAll = new PageImpl<MemberWithAmountVo>(list, pageModel.getPageable(), all.getTotalElements());
        return success(newAll);
    }
    
    @PostMapping("/set/listByInviterId")
    @ResponseBody
    public MessageResult listByInviterId(
            Long inviterId) {
        List<Member> all = memberService.findByInviterId(inviterId);
        all.forEach(member -> {
        	MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(member.getId());
        	member.setThirdLevel(memberWeightUpper.getRate());
        });
        return success(all);
    }
    
    private Predicate getMemberPredicate(MemberScreen screen) {
        ArrayList<BooleanExpression> booleanExpressions = new ArrayList<>();
        if (screen.getStatus() != null) {
            booleanExpressions.add(member.certifiedBusinessStatus.eq(screen.getStatus()));
        }
        if (screen.getStartTime() != null) {
            booleanExpressions.add(member.registrationTime.goe(screen.getStartTime()));
        }
        if (screen.getEndTime() != null) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(screen.getEndTime());
            calendar.add(Calendar.DAY_OF_YEAR, 1);
            booleanExpressions.add(member.registrationTime.lt(calendar.getTime()));
        }

        if (!StringUtils.isEmpty(screen.getAccount())) {
        	if(!StringUtils.isNumeric(screen.getAccount())) {
                booleanExpressions.add(member.username.like("%" + screen.getAccount() + "%")
                        .or(member.mobilePhone.like(screen.getAccount() + "%"))
                        .or(member.email.like(screen.getAccount() + "%"))
                        .or(member.realName.like("%" + screen.getAccount() + "%")));
            }else {
                Long accountId = Long.parseLong(screen.getAccount());
                booleanExpressions.add(member.username.like("%" + screen.getAccount() + "%")
                        .or(member.mobilePhone.like(screen.getAccount() + "%"))
                        .or(member.email.like(screen.getAccount() + "%"))
                        .or(member.id.eq(accountId))
                        .or(member.realName.like("%" + screen.getAccount() + "%")));
            }
        }
        if (screen.getCommonStatus() != null) {
            booleanExpressions.add(member.status.eq(screen.getCommonStatus()));
        }

        if(screen.getSuperPartner() != null && !screen.getSuperPartner().equals("")) {
            booleanExpressions.add(member.superPartner.eq(screen.getSuperPartner()));
        }
        if(screen.getInviterId() != null) {
        	List<Long> childIds = memberService.findDirectSuperAgentChildIds(screen.getInviterId());
        	if (childIds.isEmpty()) {
        		booleanExpressions.add(member.id.eq(-1L));
        	} else {
        		booleanExpressions.add(member.id.in(childIds));
        	}
        } else {
        	booleanExpressions.add(member.inviterId.isNull());
        }
        booleanExpressions.add(member.id.ne(1L));
        return PredicateUtils.getPredicate(booleanExpressions);
    }
}
