package com.bizzan.bitrade.controller;

import com.bizzan.bitrade.annotation.AccessLog;
import com.bizzan.bitrade.constant.*;
import com.bizzan.bitrade.dto.MemberDTO;
import com.bizzan.bitrade.dto.MemberWalletDTO;
import com.bizzan.bitrade.entity.*;
import com.bizzan.bitrade.controller.screen.ContractRewardRecordScreen;
import com.bizzan.bitrade.controller.screen.MemberScreen;
import com.bizzan.bitrade.controller.screen.MemberStatVo;
import com.bizzan.bitrade.entity.transform.AuthMember;
import com.bizzan.bitrade.model.MemberWithAmountVo;
import com.bizzan.bitrade.service.*;
import com.bizzan.bitrade.util.DateUtil;
import com.bizzan.bitrade.util.FileUtil;
import com.bizzan.bitrade.util.MessageResult;
import com.bizzan.bitrade.util.PredicateUtils;
import com.bizzan.bitrade.vo.TradingAccount;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.bizzan.bitrade.constant.CertifiedBusinessStatus.*;
import static com.bizzan.bitrade.constant.MemberLevelEnum.IDENTIFICATION;
import static com.bizzan.bitrade.constant.SysConstant.SESSION_MEMBER;
import static com.bizzan.bitrade.entity.QMember.member;
import static org.springframework.util.Assert.isTrue;
import static org.springframework.util.Assert.notNull;

/**
 * @author 
 * @description 后台管理会员
 * @date 2019/12/25 16:50
 */
@Api(value = "MemberController" , tags = "代理商用户信息接口")
@RestController
@RequestMapping("member")
@Slf4j
public class MemberController extends BaseController {

    @Autowired
    private MemberService memberService;

    @Autowired
    private MemberWalletService memberWalletService;

    @Autowired
    private BusinessAuthApplyService businessAuthApplyService;

    @Autowired
    private DepositRecordService depositRecordService;

    @Autowired
    private LocaleMessageSourceService messageSource;
    
    @Autowired
    private MemberWeightUpperService memberWeightUpperService;
    @Autowired
    private MemberContractWalletService memberContractWalletService;
    @Autowired
    private MemberTransactionService memberTransactionService;
    @Autowired
    private ContractOrderEntrustService contractOrderEntrustService;
    @Autowired
    private UserPurseService userPurseService;
    @Autowired
    private FollowWalletService followWalletService;
    @Autowired
    private GameRecordService gameRecordService;

    
    //@RequestMapping(value = "/detail")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult detail(@RequestParam("id") Long id, @SessionAttribute(SESSION_MEMBER) AuthMember user) {
        Member checkMember = memberService.findOne(user.getId());
        if(!checkMember.getSuperPartner().equals("1")) {
            return error("您不是代理商！");
        }

        Member member = memberService.findOne(id);
        notNull(member, "validate id!");
        List<MemberWallet> list = memberWalletService.findAllByMemberId(member.getId());
        MemberDTO memberDTO = new MemberDTO();
        memberDTO.setMember(member);
        memberDTO.setList(list);
        return success(memberDTO);
    }
    
    @ApiOperation(value="获取代理商统计信息", notes="获取代理商统计信息")
    @RequestMapping(value = "/stat", method= {RequestMethod.GET, RequestMethod.POST})
    @Transactional(rollbackFor = Exception.class)
    public MessageResult stat(@SessionAttribute(SESSION_MEMBER) AuthMember user,String startDate,String endDate) throws ParseException {
    	String balanceEndDate = null;
    	if(startDate == null)
        	startDate = "1970-1-1";
        if(endDate == null) {
        	endDate = DateUtil.getDate();
        	endDate = endDate + " 23:59:59";
        	balanceEndDate = endDate;
        } else {
        	endDate = endDate + " 23:59:59";
        	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date endDateDate = sdf.parse(endDate);
            long balanceEndDateLong = endDateDate.getTime()-endDateDate.getDay()*24*60*60000 - 60*60000;
            balanceEndDate = sdf.format(new Date(balanceEndDateLong));
            log.info("balanceEndDate={}", balanceEndDate);
        }
        
        
    	
        Member member = memberService.findOne(user.getId());
        if(!member.getSuperPartner().equals("1")) {
            return error("您不是代理商！");
        }
        List<MemberWeightUpper> subList = memberWeightUpperService.findAllByAllUppers(user.getId());
        Set<Long> subIdSet = new LinkedHashSet<Long>();
        for(MemberWeightUpper upper: subList)
        	subIdSet.add(upper.getMemberId());
        subIdSet.add(user.getId());
        List<Long> subIds = new ArrayList<Long>(subIdSet);
        log.info("subIds={}", subIds);
        MemberStatVo vo = new MemberStatVo();
        vo.setMemberId(user.getId());
        //if(subIds.size() != 0) {
	        //BigDecimal balance = memberWalletService.getTotalBalanceByIds(subIds);
	        //balance = balance.add(memberContractWalletService.getTotalBalanceByIds(subIds));
        BigDecimal contractProfit = memberTransactionService.getTotalProfit(subIds, startDate, endDate);
        if (contractProfit == null) contractProfit = BigDecimal.ZERO;
        BigDecimal contractLoss = memberTransactionService.getTotalLoss(subIds, startDate, endDate);
        if (contractLoss == null) contractLoss = BigDecimal.ZERO;
        BigDecimal followProfit = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(startDate, endDate, subIds, TransactionType.FOLLOW_PROFIT);
        if (followProfit == null) followProfit = BigDecimal.ZERO;
        BigDecimal followLoss = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(startDate, endDate, subIds, TransactionType.FOLLOW_LOSS);
        if (followLoss == null) followLoss = BigDecimal.ZERO;
        BigDecimal totalProfit = contractProfit.add(followProfit);
        BigDecimal totalLoss = contractLoss.add(followLoss);
        BigDecimal totalRecharge = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(startDate, endDate, subIds, TransactionType.RECHARGE);
        if (totalRecharge == null) totalRecharge = BigDecimal.ZERO;
        BigDecimal totalWithdraw = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(startDate, endDate, subIds, TransactionType.WITHDRAW);
        if (totalWithdraw == null) totalWithdraw = BigDecimal.ZERO;
        BigDecimal totalAward = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(startDate, endDate, user.getId(), TransactionType.CONTRACT_AWARD);
        if (totalAward == null) totalAward = BigDecimal.ZERO;
        BigDecimal totalFollowAward = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(startDate, endDate, user.getId(), TransactionType.FOLLOW_AWARD);
        if (totalFollowAward == null) totalFollowAward = BigDecimal.ZERO;
        BigDecimal totalActivityAward = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(startDate, endDate, subIds, TransactionType.GAME_AWARD);
        if (totalActivityAward == null) totalActivityAward = BigDecimal.ZERO;
        BigDecimal activityAmount = gameRecordService.sumAmountByMemberIdsAndTime(startDate, endDate, subIds);
        if (activityAmount == null) activityAmount = BigDecimal.ZERO;
        String[] todayTimeStr = DateUtil.getTodayRealSartAndEndDateStr();
        BigDecimal todayRecharge = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(todayTimeStr[0], todayTimeStr[1], subIds, TransactionType.RECHARGE);
        if (todayRecharge == null) todayRecharge = BigDecimal.ZERO;
        BigDecimal todayWithdraw = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(todayTimeStr[0], todayTimeStr[1], subIds, TransactionType.WITHDRAW);
        if (todayWithdraw == null) todayWithdraw = BigDecimal.ZERO;
        BigDecimal todayFee = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(todayTimeStr[0], todayTimeStr[1], subIds, TransactionType.CONTRACT_FEE);
        if (todayFee == null) todayFee = BigDecimal.ZERO;
        String[] yesterdayTimeStr = DateUtil.getYesterdayRealSartAndEndDateStr();
        BigDecimal yesterdayRecharge = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(yesterdayTimeStr[0], yesterdayTimeStr[1], subIds, TransactionType.RECHARGE);
        if (yesterdayRecharge == null) yesterdayRecharge = BigDecimal.ZERO;
        BigDecimal yesterdayWithdraw = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(yesterdayTimeStr[0], yesterdayTimeStr[1], subIds, TransactionType.WITHDRAW);
        if (yesterdayWithdraw == null) yesterdayWithdraw = BigDecimal.ZERO;
        BigDecimal totalPrincipalAmount = contractOrderEntrustService.sumTotalPrincipalAmountByMemberIds(subIds);
        if (totalPrincipalAmount == null) totalPrincipalAmount = BigDecimal.ZERO;
        int todayUserCount = memberService.countByDateAndIds(startDate, subIds);
        long followCount = followWalletService.countWithBalanceByMemberIds(subIds);
        
        vo.setTotalProfit(totalProfit);
        vo.setTotalLoss(totalLoss);
        vo.setTotalRecharge(totalRecharge);
        vo.setTotalWithdraw(totalWithdraw);
        vo.setTodayRecharge(todayRecharge);
        vo.setTodayWithdraw(todayWithdraw);
        vo.setTodayFee(todayFee);
        vo.setYesterdayRecharge(yesterdayRecharge);
        vo.setYesterdayWithdraw(yesterdayWithdraw);
        vo.setTotalAward(totalAward.add(totalFollowAward));
        vo.setActivityAward(totalActivityAward);
        vo.setActivityAmount(activityAmount);
        vo.setTotalPrincipalAmount(totalPrincipalAmount);
        vo.setTodayNewUserCount(todayUserCount);
        vo.setFollowCount((int)followCount);
        //}
        Long[] todayTime = DateUtil.getRealStartAndEndDate(0);
        BigDecimal balance = memberTransactionService.sumAmountByMemberIdsAndTime("1970-1-1", endDate, subIds);
        if (balance == null) balance = BigDecimal.ZERO;
        BigDecimal timestampBalance = memberTransactionService.sumAmountByMemberIdsAndTime("1970-1-1", balanceEndDate, subIds);
        if (timestampBalance == null) timestampBalance = BigDecimal.ZERO;
        int todayOrderCount = contractOrderEntrustService.countActiveMembersByMemberIdsAndTime(todayTime[0], todayTime[1], subIds);
        String[] todayRealTimeStr = DateUtil.getTodayRealSartAndEndDateStr();
        BigDecimal todayContractAward = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(todayRealTimeStr[0], todayRealTimeStr[1], user.getId(), TransactionType.CONTRACT_AWARD);
        if (todayContractAward == null) todayContractAward = BigDecimal.ZERO;
        BigDecimal todayFollowAward = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(todayRealTimeStr[0], todayRealTimeStr[1], user.getId(), TransactionType.FOLLOW_AWARD);
        if (todayFollowAward == null) todayFollowAward = BigDecimal.ZERO;
        vo.setTotalCount(subIds.size());
        vo.setTimeStampBalance(timestampBalance);
        vo.setTotalBalance(balance);
        vo.setTodayOrderCount(todayOrderCount);
        vo.setTodayAward(todayContractAward.add(todayFollowAward));
        return success(vo);
    }

    /**
     * 分页获取用户列表
     * @param pageModel
     * @param screen
     * @param user
     * @return
     */
    @ApiOperation(value="获取下级统计信息", notes="获取下级统计信息")
    @RequestMapping(value = "/page-query", method= {RequestMethod.GET, RequestMethod.POST})
    @Transactional(rollbackFor = Exception.class)
    public MessageResult page(
            PageModel pageModel,
            MemberScreen screen,
            @SessionAttribute(SESSION_MEMBER) AuthMember user) {
        // 检查用户是否是代理商
        Member checkMember = memberService.findOne(user.getId());
        if(!checkMember.getSuperPartner().equals("1")) {
            return error("您不是代理商！");
        }
        Predicate predicate = getPredicate(screen, user.getId());
        Page<Member> all = memberService.findAll(predicate, pageModel.getPageable());
        List<MemberWithAmountVo> list = new ArrayList<MemberWithAmountVo>();
        Long[] todayTime = DateUtil.getStartAndEndDate(0);
        all.forEach(member -> {
        	BigDecimal coinBalance = memberWalletService.sumBalanceByMemberId(member.getId());
        	TradingAccount tradingAccount = userPurseService.findOneVO(member.getId());
        	BigDecimal contractBalance = tradingAccount.getCurrentCapital();
        	BigDecimal totalBalance = coinBalance.add(contractBalance);
        	BigDecimal followBalance = followWalletService.findOneVO(member.getId()).getCurrentCapital();
        	int todayOrder = (int)contractOrderEntrustService.countByMemberId(member.getId(), todayTime[0], todayTime[1]);
			
            BigDecimal totalWithdraw = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.WITHDRAW);
            BigDecimal totalRecharge = memberTransactionService.sumAmountByMemberIdAndType(member.getId(), TransactionType.RECHARGE);
        	
        	MemberWithAmountVo vo = new MemberWithAmountVo();
        	BeanUtils.copyProperties(member, vo);
        	vo.setTotalBalance(totalBalance);
        	vo.setCoinBalance(coinBalance);
        	vo.setContractBalance(contractBalance);
        	vo.setFollowBalance(followBalance);
        	vo.setTodayOrder(todayOrder);
        	vo.setTotalWithdraw(totalWithdraw);
        	vo.setTotalRecharge(totalRecharge);
        	
        	List<Long> subIds = memberWeightUpperService.findMemberIdListByAllUppers(member.getId());
            subIds.add(member.getId());
            
        	long followCount = followWalletService.countWithBalanceByMemberIds(subIds);
            vo.setFollowCount((int)followCount);
            
        	list.add(vo);
        });

        Page<MemberWithAmountVo> newAll = new PageImpl<MemberWithAmountVo>(list, pageModel.getPageable(), all.getTotalElements());
        return success(newAll);
    }
    
    @PostMapping("alter-member-superpartner")
    public MessageResult alterSuperPartner(
    		@SessionAttribute(SESSION_MEMBER) AuthMember user,
            @RequestParam("superPartner") String superPartner,
            @RequestParam("memberId") Long memberId) {
    	MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(memberId);
    	if(memberWeightUpper.getAllUppers() == null || !memberWeightUpper.getAllUppers().contains(String.valueOf(user.getId()))) {
    		return error("非法操作");
    	}
        if(superPartner.equals("0")) {
        	memberWeightUpperService.cancelSuperPartner(memberId);
        } else {
        	Member member = memberService.findOne(memberId);
            member.setSuperPartner(superPartner);
            memberService.save(member);
        }
        return success(messageSource.getMessage("SUCCESS"));
    }
    
    @ApiOperation(value="获取下级统计信息", notes="获取下级统计信息")
    @RequestMapping(value = "/agent-page-query", method= {RequestMethod.GET, RequestMethod.POST})
    @Transactional(rollbackFor = Exception.class)
    public MessageResult agentPage(
            PageModel pageModel,
            MemberScreen screen,
            @SessionAttribute(SESSION_MEMBER) AuthMember user) {
        // 检查用户是否是代理商
        Member checkMember = memberService.findOne(user.getId());
        if(!checkMember.getSuperPartner().equals("1")) {
            return error("您不是代理商！");
        }
        screen.setSuperPartner("1");
        Predicate predicate = getPredicate(screen, user.getId());
        Page<Member> all = memberService.findAll(predicate, pageModel.getPageable());
        List<MemberWithAmountVo> list = new ArrayList<MemberWithAmountVo>();
        String[] todayTimeStr = DateUtil.getTodaySartAndEndDateStr();
        all.forEach(member -> {
            List<Long> subIds = memberWeightUpperService.findMemberIdListByAllUppers(member.getId());
            
            log.info("memberId={},subIds={}", member.getId(), subIds);
            //subIds.add(member.getId());
        	MemberWithAmountVo vo = new MemberWithAmountVo();
        	BeanUtils.copyProperties(member, vo);
        	vo.setAgentTotalCount(subIds.size());
        	
        	subIds.add(member.getId());
            if(subIds.size()>0) {
            	BigDecimal todayRecharge = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(todayTimeStr[0], todayTimeStr[1], member.getId(), TransactionType.RECHARGE);
	            BigDecimal todayWithdraw = memberTransactionService.sumAmountByMemberIdAndTypeAndTime(todayTimeStr[0], todayTimeStr[1], member.getId(), TransactionType.WITHDRAW);
	            BigDecimal agentTodayRecharge = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(todayTimeStr[0], todayTimeStr[1], subIds, TransactionType.RECHARGE);
	            BigDecimal agentTodayWithdraw = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime(todayTimeStr[0], todayTimeStr[1], subIds, TransactionType.WITHDRAW);
	            
	            vo.setTodayRecharge(todayRecharge);
	        	vo.setTodayWithdraw(todayWithdraw);
	        	vo.setAgentTodayRecharge(agentTodayRecharge);
	        	vo.setAgentTodayWithdraw(agentTodayWithdraw);
            }
        	MemberWeightUpper memberWeightUpper = memberWeightUpperService.findMemberWeightUpperByMemberId(member.getId());
        	vo.setRate(memberWeightUpper.getRate());
        	vo.setFollowRate(memberWeightUpper.getFollowRate());
        	vo.setWcRate(memberWeightUpper.getWcRate());
        	
        	BigDecimal totalRecharge = memberTransactionService.sumAmountByMemberIdAndTypeAndTime("1970-1-1", todayTimeStr[1], member.getId(), TransactionType.RECHARGE);
            BigDecimal totalWithdraw = memberTransactionService.sumAmountByMemberIdAndTypeAndTime("1970-1-1", todayTimeStr[1], member.getId(), TransactionType.WITHDRAW);
            BigDecimal agentTotalRecharge = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime("1970-1-1", todayTimeStr[1], subIds, TransactionType.RECHARGE);
            BigDecimal agentTotalWithdraw = memberTransactionService.sumAmountByMemberIdsAndTypeAndTime("1970-1-1", todayTimeStr[1], subIds, TransactionType.WITHDRAW);
            vo.setTotalRecharge(totalRecharge);
        	vo.setTotalWithdraw(totalWithdraw);
            vo.setAgentTotalRecharge(agentTotalRecharge);
        	vo.setAgentTotalWithdraw(agentTotalWithdraw);

            long followCount = followWalletService.countWithBalanceByMemberIds(subIds);
            vo.setFollowCount((int)followCount);
        	
        	list.add(vo);
        });

        Page<MemberWithAmountVo> newAll = new PageImpl<MemberWithAmountVo>(list, pageModel.getPageable(), all.getTotalElements());
        return success(newAll);
    }

    private Predicate getPredicate(MemberScreen screen, Long userId) {
        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())) {
            booleanExpressions.add(member.username.like("%" + screen.getAccount() + "%")
                    .or(member.mobilePhone.like(screen.getAccount() + "%"))
                    .or(member.email.like(screen.getAccount() + "%"))
                    .or(member.id.eq(Long.valueOf(screen.getAccount())))
                    .or(member.realName.like("%" + screen.getAccount() + "%")));
        }
        // 筛选过滤出我邀请的人
        if(screen.getInviterId()!=null) {
        	booleanExpressions.add(member.inviterId.eq(userId));
        } else {
	        List<Long> subIds = memberWeightUpperService.findMemberIdListByAllUppers(userId);
	        booleanExpressions.add(member.id.in(subIds));
        }
        if (screen.getCommonStatus() != null) {
            booleanExpressions.add(member.status.eq(screen.getCommonStatus()));
        }
        if(StringUtils.isNotEmpty(screen.getUsername())) {
            booleanExpressions.add(member.username.contains(screen.getUsername()));
        }
        if(screen.getSuperPartner()!=null)
        	booleanExpressions.add(member.superPartner.eq(screen.getSuperPartner()));
        return PredicateUtils.getPredicate(booleanExpressions);
    }

    /*@RequiresPermissions("member:out-excel")
    @GetMapping("out-excel")
    @AccessLog(module = AdminModule.MEMBER, operation = "导出会员Member Excel")
    public MessageResult outExcel(
            @RequestParam(value = "startTime", required = false) Date startTime,
            @RequestParam(value = "endTime", required = false) Date endTime,
            @RequestParam(value = "account", required = false) String account,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        List<BooleanExpression> booleanExpressionList = getBooleanExpressionList(startTime, endTime, account, null);
        List list = memberService.queryWhereOrPage(booleanExpressionList, null, null).getContent();
        return new FileUtil().exportExcel(request, response, list, "member");
    }*/

    // 获得条件
    private List<BooleanExpression> getBooleanExpressionList(
            Date startTime, Date endTime, String account, CertifiedBusinessStatus status) {
        List<BooleanExpression> booleanExpressionList = new ArrayList();
        if (status != null) {
            booleanExpressionList.add(member.certifiedBusinessStatus.eq(status));
        }
        if (startTime != null) {
            booleanExpressionList.add(member.registrationTime.gt(startTime));
        }
        if (endTime != null) {
            booleanExpressionList.add(member.registrationTime.lt(endTime));
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(account)) {
            booleanExpressionList.add(member.username.like("%" + account + "%")
                    .or(member.mobilePhone.like(account + "%"))
                    .or(member.email.like(account + "%")));
        }
        return booleanExpressionList;
    }
}
