
package com.tmerclub.cloud.flow.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.tmerclub.cloud.api.coupon.feign.CouponFeignClient;
import com.tmerclub.cloud.api.order.dto.CustomerRetainedDTO;
import com.tmerclub.cloud.api.order.feign.OrderFeignClient;
import com.tmerclub.cloud.api.order.vo.CustomerRetainVO;
import com.tmerclub.cloud.api.user.bo.UserOrderStatisticBO;
import com.tmerclub.cloud.api.user.bo.UserOrderStatisticListBO;
import com.tmerclub.cloud.api.user.dto.MemberReqDTO;
import com.tmerclub.cloud.api.user.feign.UserFeignClient;
import com.tmerclub.cloud.api.user.vo.*;
import com.tmerclub.cloud.common.cache.constant.CacheNames;
import com.tmerclub.cloud.common.cache.constant.FlowCacheNames;
import com.tmerclub.cloud.common.cache.util.RedisUtil;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.util.*;
import com.tmerclub.cloud.flow.bo.FlowUserBO;
import com.tmerclub.cloud.flow.bo.FlowUserRetainBO;
import com.tmerclub.cloud.flow.constant.FlowDateTypeEnum;
import com.tmerclub.cloud.flow.service.CustomerAnalysisService;
import com.tmerclub.cloud.flow.service.UserAnalyseMongoService;
import com.tmerclub.cloud.flow.util.FlowUtil;
import com.tmerclub.cloud.flow.vo.MemberSurveyRespVO;
import com.tmerclub.cloud.flow.vo.MemberTrendExcelVO;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lgh on 2018/10/26.
 */
@Service
public class CustomerAnalysisServiceImpl implements CustomerAnalysisService {
    @DubboReference
    private UserFeignClient userFeignClient;
    @DubboReference
    private OrderFeignClient orderFeignClient;
    @DubboReference
    private CouponFeignClient couponFeignClient;
    @Autowired
    private UserAnalyseMongoService userAnalyseMongoService;

    @Override
    public MemberDealRespVO getMemberDeal(MemberReqDTO param) {
        FlowUtil.handleTime(param);
        MemberDealRespVO respParam = new MemberDealRespVO();
        Date startTime = param.getStartTime();
        Date beforeYear = DateUtils.getBeforeYear(startTime, -2);
        param.setBeforeYear(beforeYear);
        param.setDateTime(null);
        param.setDayStartTime(startTime);
        // 获取会员成交数据
        UserOrderStatisticListBO data = orderFeignClient.getMemberPayData(param).getData();
        List<UserOrderStatisticBO> oldUserOrderStatistic = data.getOldUserOrderStatisticList();
        List<UserOrderStatisticBO> newUserOrderStatistic = data.getNewUserOrderStatisticList();
        // 支付客户数
        MemberDealVO allMember = new MemberDealVO();
        MemberDealVO oldMember = handleMemberPayInfo(oldUserOrderStatistic);
        MemberDealVO newMember = handleMemberPayInfo(newUserOrderStatistic);

        allMember.setPayMemberNum(oldMember.getPayMemberNum() + newMember.getPayMemberNum());
        // 成交会员占比
        Integer payMemberNum = allMember.getPayMemberNum();
        allMember.setPayMemberNumRate(1.0);
        newMember.setPayMemberNumRate(AnalysisUtil.divAverage(newMember.getPayMemberNum(), payMemberNum, 4));
        oldMember.setPayMemberNumRate(AnalysisUtil.divAverage(oldMember.getPayMemberNum(), payMemberNum, 4));
        // 付款金额,占比
        allMember.setPayAmount(Arith.add(oldMember.getPayAmount(), newMember.getPayAmount()));
        allMember.setPayAmountRate(1.0);
        newMember.setPayAmountRate(AnalysisUtil.divAverage(newMember.getPayAmount(), allMember.getPayAmount(), 4));
        oldMember.setPayAmountRate(Arith.sub(allMember.getPayAmountRate(), newMember.getPayAmountRate()));
        // 客单价
        double priceMember = (double) Math.round(divAverage(Arith.mul(allMember.getPayAmount() , 100), allMember.getPayMemberNum(), 2));
        allMember.setPricePerMember(Arith.div(priceMember,100));
        // 支付订单数
        allMember.setPayOrderNum(newMember.getPayOrderNum() + oldMember.getPayOrderNum());

        respParam.setAllMember(allMember);
        respParam.setNewMember(newMember);
        respParam.setOldMember(oldMember);

        respParam.setTrendParam(handleMamberDealList(data, param));
        return respParam;
    }

    @Override
    public List<CustomerRetainVO> getCustomerRetained(CustomerRetainedDTO customerRetainedDTO) {
        // 访问留存
        // 访问时间，是每一个月的时间 (例如： 2021-05, 2021-06)
        // 新访问客户数：之前没有访问过，第一次登录访问后，下个月再次登录访问的用户。（包含未注册登录的访客）
        // 因为要计算用户第一次的访问时间所以一定有全表扫描的
        // 第一月留存：新访问的客户，在第一次访问后的下一个月，是否有再次访问成功的人数
        // eg：假设2021年1月份，A B C D 四位客户登录访问；2月份 A B 访问；3月份 D访问，4月份B C D有访问。求 1月份客户在后续2，3，4月份的留存率分别是多少？
        // 根据前面的算法公式，则：
        // 2月份的留存数是 2，留存率 = 2 /4 = 50%
        // 3月份的留存数是 1，留存率 = 1/4 = 25%
        // 4月份的留存数是 3，留存率 = 3/4 = 75%
        Date endTime = DateUtil.beginOfMonth(DateUtil.offsetMonth(customerRetainedDTO.getEndTime(), 1));

        List<FlowUserRetainBO> flowUserRetainList = userAnalyseMongoService.listFlowUserRetain(customerRetainedDTO.getStartTime(), endTime, customerRetainedDTO.getRetainType());

        Map<Long, FlowUserRetainBO> map = flowUserRetainList.stream()
                .collect(Collectors.toMap(flowUserRetainBO -> flowUserRetainBO.getCreateTime().getTime(), f -> f));

        List<CustomerRetainVO> customerRetainList = new ArrayList<>();
        Date startTime = customerRetainedDTO.getStartTime();
        while (startTime.getTime() < endTime.getTime()) {
            FlowUserRetainBO flowUserRetainBO = map.get(startTime.getTime());
            if (Objects.isNull(flowUserRetainBO)) {
                flowUserRetainBO = new FlowUserRetainBO();
            }
            CustomerRetainVO customerRetainVO = BeanUtil.map(flowUserRetainBO, CustomerRetainVO.class);
            customerRetainVO.setCurrentMonth(DateUtil.format(startTime, "yyyy-MM"));
            customerRetainVO.setFirstMonthRemainRate(AnalysisUtil.calculatePercentage(customerRetainVO.getFirstMonthRemain(), customerRetainVO.getNewCustomers()));
            customerRetainVO.setSecondMonthRemainRate(AnalysisUtil.calculatePercentage(customerRetainVO.getSecondMonthRemain(), customerRetainVO.getNewCustomers()));
            customerRetainVO.setThirdMonthRemainRate(AnalysisUtil.calculatePercentage(customerRetainVO.getThirdMonthRemain(), customerRetainVO.getNewCustomers()));
            customerRetainVO.setFourthMonthRemainRate(AnalysisUtil.calculatePercentage(customerRetainVO.getFourthMonthRemain(), customerRetainVO.getNewCustomers()));
            customerRetainVO.setFifthMonthRemainRate(AnalysisUtil.calculatePercentage(customerRetainVO.getFifthMonthRemain(), customerRetainVO.getNewCustomers()));
            customerRetainVO.setSixthMonthRemainRate(AnalysisUtil.calculatePercentage(customerRetainVO.getSixthMonthRemain(), customerRetainVO.getNewCustomers()));
            customerRetainList.add(customerRetainVO);
            startTime = DateUtil.beginOfMonth(DateUtil.offsetMonth(startTime, 1));
        }
        return customerRetainList;
    }
    @Override
    public List<MemberTrendRespVO> getMemberTrend(MemberReqDTO param) {
        // 初始化时间
        FlowUtil.handleTime(param);
        // 查询免费、付费会员的数量数据
        List<MemberTrendRespVO> memberTrendRespList;
        // 今日实时
        if (Objects.equals(FlowDateTypeEnum.REAL_TIME.value(), param.getDateType())) {
            // 从redis中获取
            memberTrendRespList = userAnalyseMongoService.statisticsRealMemberTrend(param.getStartTime(), param.getEndTime(), param.getDateType());
        }
        // 日、周、月、近7天、近30天
        else {
            memberTrendRespList = userAnalyseMongoService.listUserNumAndTypeByTime(param.getStartTime(), param.getEndTime());
        }

        Map<String, MemberTrendRespVO> memberTrendRespMap = memberTrendRespList.stream().collect(Collectors.toMap(MemberTrendRespVO::getCurrentDay, m -> m));

        memberTrendRespList.clear();
        Date startTime = param.getStartTime();
        long endTime = param.getEndTime().getTime();

        while (startTime.getTime() < endTime) {
            MemberTrendRespVO memberTrendRespVO = memberTrendRespMap.get(String.valueOf(startTime.getTime()));
            if (Objects.isNull(memberTrendRespVO)) {
                memberTrendRespVO = new MemberTrendRespVO();
            }
            if (Objects.isNull(memberTrendRespVO.getMemberNum())) {
                memberTrendRespVO.setMemberNum(0);
            }
            if (Objects.isNull(memberTrendRespVO.getVipMemberNum())) {
                memberTrendRespVO.setVipMemberNum(0);
            }
            memberTrendRespVO.setCurrentDay(DateUtils.dateToStrYmd(startTime));
//            // 筛选时间类的每一天注册的会员数数据，不是每一天平台的总会员数
//            int total = memberTrendRespVO.getMemberNum() + memberTrendRespVO.getVipMemberNum();
            if (Objects.equals(param.getMemberType(), 1)) {
            } else {
            }
            startTime = DateUtil.offsetDay(startTime, 1);
            memberTrendRespList.add(memberTrendRespVO);
        }
        return memberTrendRespList;
    }

    @Override
    public List<MemberTrendExcelVO> listMemberTrend(MemberReqDTO memberReqDTO) {
        memberReqDTO.setMemberType(1);
        List<MemberTrendRespVO> ordinaryMember = this.getMemberTrend(memberReqDTO);
        memberReqDTO.setMemberType(2);
        List<MemberTrendRespVO> payMember = this.getMemberTrend(memberReqDTO);
        Map<String, Integer> payMemberMap = payMember.stream().collect(Collectors.toMap(MemberTrendRespVO::getCurrentDay, MemberTrendRespVO::getMemberNum));
        List<MemberTrendExcelVO> resList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (MemberTrendRespVO memberTrendRespVO : ordinaryMember) {
            MemberTrendExcelVO memberTrendExcelVO = new MemberTrendExcelVO();
            Date date = DateUtil.parse(memberTrendRespVO.getCurrentDay(), "yyyyMMdd");
            memberTrendExcelVO.setDate(DateUtils.dateToStrYmd(date));
            memberTrendExcelVO.setNormal(Objects.isNull(memberTrendRespVO.getMemberNum()) ? 0 : memberTrendRespVO.getMemberNum());
            memberTrendExcelVO.setPay(payMemberMap.get(memberTrendRespVO.getCurrentDay()));
            resList.add(memberTrendExcelVO);
        }
        return resList;
    }

    @Override
    public MemberSurveyRespVO getMemberSurvey(MemberReqDTO param) {
        FlowUtil.handleTime(param);
        // 时间类型
        FlowUserBO flowUserBO = null;
        // 当前数据
        FlowDateTypeEnum flowDateTypeEnum = FlowDateTypeEnum.instance(param.getDateType());
        int offset = flowDateTypeEnum.getNum();
        if (FlowDateTypeEnum.weekOrMonth(param.getDateType())) {
            offset = 11;
        } else if (offset > 1){
            offset = offset - 1;
        }
        Date beginTime = FlowUtil.previousTime(param.getStartTime(), param.getDateType(), offset);
        MemberOverviewVO memberOverviewVO = null;
        // 实时统计
        if (Objects.equals(FlowDateTypeEnum.REAL_TIME.value(), param.getDateType())) {
            // 累计会员数、新增会员数
            memberOverviewVO = this.realMemberSurvey(param);
            List<FlowUserBO> memberSurveyResp = userAnalyseMongoService.listFlowUserByTimeAndUserType(beginTime, param.getStartTime(), param.getDateType(), param.getMemberType());
            if(CollUtil.isNotEmpty(memberSurveyResp)){
                flowUserBO = memberSurveyResp.get(0);
            }
        }
        // 日、周、月
        else if (FlowDateTypeEnum.dayOrWeekOrMonth(param.getDateType())) {
            List<FlowUserBO> flowUserList = userAnalyseMongoService.listFlowUserByTimeAndUserType(param.getStartTime(), param.getEndTime(), param.getDateType(), param.getMemberType());
            if (CollUtil.isNotEmpty(flowUserList)) {
                memberOverviewVO = this.toMemberSurveyRespVO(flowUserList).get(0);
            }
            List<FlowUserBO> memberSurveyResp = userAnalyseMongoService.listFlowUserByTimeAndUserType(beginTime, param.getStartTime(), param.getDateType(), param.getMemberType());
            if(CollUtil.isNotEmpty(memberSurveyResp)){
                flowUserBO = memberSurveyResp.get(0);
            }
        }
        // 近7天、近30天
        else {
            // 直接查询新旧数据即可
            memberOverviewVO = this.toMemberSurveyRespVO(userAnalyseMongoService.getFlowUserByTimeAndUserType(param.getStartTime(), param.getEndTime(), param.getDateType(), param.getMemberType()));
            // 缓存中查询上一轮统计的数据，缓存时间为24小时，key中有时间不会查到前一天的统计数据
            String format = DateUtil.format(param.getStartTime(), DatePattern.NORM_DATE_PATTERN);
            String key = FlowCacheNames.MEMBER_SURVEY_NEARLY_TIME + CacheNames.UNION + format + param.getDateType();
            List<FlowUserBO> memberSurveyResp = RedisUtil.get(key);
            if (Objects.isNull(memberSurveyResp)) {
                memberSurveyResp = userAnalyseMongoService.statisticsUserOfTime(param.getDateType(), param.getStartTime(), param.getEndTime());
                RedisUtil.set(key, memberSurveyResp, Constant.DAY_SECOND);
            }
            // 从列表总获取对应的数据类型
            if(CollUtil.isNotEmpty(memberSurveyResp)){
                for (FlowUserBO userBO : memberSurveyResp) {
                    if (Objects.equals(userBO.getType(), param.getMemberType())) {
                        flowUserBO = userBO;
                        break;
                    }
                }
            }
        }

        if (Objects.isNull(memberOverviewVO)) {
            memberOverviewVO = new MemberOverviewVO();
        }

        MemberOverviewVO oldMemberOverviewVO;
        if (Objects.isNull(flowUserBO)) {
            oldMemberOverviewVO = new MemberOverviewVO();
        } else {
            oldMemberOverviewVO = this.toMemberSurveyRespVO(flowUserBO);
        }

        memberOverviewVO.setCreateTime(param.getStartTime());

        this.getGeneralizeRate(memberOverviewVO, oldMemberOverviewVO);

        MemberSurveyRespVO memberSurveyRespVO = new MemberSurveyRespVO();

        memberSurveyRespVO.setMemberOverviewModel(memberOverviewVO);

        // 获取列表
        this.setMemberOverviewList(param, memberOverviewVO, memberSurveyRespVO);

        return memberSurveyRespVO;
    }

    @Override
    public MemberContributeRespVO getMemberContributeValue(MemberReqDTO param) {
        FlowUtil.handleTime(param);
        // 当前筛选条件下的所有订单信息
        MemberContributeRespVO memberContributeRespVO = new MemberContributeRespVO();
        param.setDateTime(null);

        // 累计会员数 累计会员占比 成交会员数 支付订单数 支付金额
        Map<Integer, MemberContributeValueVO> memberContributeValueMap = new HashMap<>(4);

        this.statisticsMemberContributeValue(param, memberContributeValueMap);

        // 设置普通会员和付费会员数据的订单相关数据
        MemberContributeValueVO publicMember;
        MemberContributeValueVO paidMember;
        publicMember = memberContributeValueMap.get(1);
        if (Objects.isNull(publicMember)) {
            publicMember = new MemberContributeValueVO();
        }
        paidMember = memberContributeValueMap.get(2);
        if (Objects.isNull(paidMember)) {
            paidMember = new MemberContributeValueVO();
        }
        // 占比信息
        publicMember.setTotalMemberRate(divAverage(publicMember.getTotalMember(),publicMember.getTotalMember()+paidMember.getTotalMember()));
        paidMember.setTotalMemberRate(Arith.sub(1,publicMember.getTotalMemberRate()));
        publicMember.setPayMemberNumRate(divAverage(publicMember.getPayMemberNum(),publicMember.getPayMemberNum()+ paidMember.getPayMemberNum()));
        paidMember.setPayMemberNumRate(Arith.sub(1,publicMember.getPayMemberNumRate()));
        publicMember.setPayAmountRate(divAverage(publicMember.getPayAmount(),Arith.add(publicMember.getPayAmount(),paidMember.getPayAmount())));
        paidMember.setPayAmountRate(Arith.sub(1,publicMember.getPayAmountRate()));
        publicMember.setPricePerMember(divAverage(publicMember.getPayAmount(),publicMember.getPayMemberNum(), 2));
        paidMember.setPricePerMember(divAverage(paidMember.getPayAmount(),paidMember.getPayMemberNum(), 2));
        publicMember.setFrequencyOfConsume(divAverage(publicMember.getPayOrderNum().doubleValue(),publicMember.getPayMemberNum(), 2));
        paidMember.setPricePerMember(divAverage(paidMember.getPayOrderNum().doubleValue(),paidMember.getPayMemberNum(), 2));

        memberContributeRespVO.setPublicMember(publicMember);
        memberContributeRespVO.setPaidMember(paidMember);
        return memberContributeRespVO;
    }

    private List<MemberDealTreadVO> handleMamberDealList(UserOrderStatisticListBO data, MemberReqDTO param) {
        List<MemberDealTreadVO> trend = new ArrayList<>(Constant.INITIAL_CAPACITY);
        Date startTime = param.getStartTime();
        long endTime = param.getEndTime().getTime();
        Map<String, UserOrderStatisticBO> newUserMap;
        Map<String, UserOrderStatisticBO> oldUserMap;
        if (CollUtil.isEmpty(data.getNewUserOrderStatisticList())) {
            newUserMap = new HashMap<>(0);
        } else {
            newUserMap = data.getNewUserOrderStatisticList().stream().collect(Collectors.toMap(UserOrderStatisticBO::getTimeData, u -> u));
        }
        if (CollUtil.isEmpty(data.getOldUserOrderStatisticList())) {
            oldUserMap = new HashMap<>(0);
        } else {
            oldUserMap = data.getOldUserOrderStatisticList().stream().collect(Collectors.toMap(UserOrderStatisticBO::getTimeData, u -> u));
        }


        while (startTime.getTime() < endTime) {
            String timeKey = DateUtils.dateToStrYmd(startTime);
            MemberDealTreadVO res = new MemberDealTreadVO();
            // 获取会员成交数据
            MemberDealVO oldMemberItem = getMemberPayInfo(oldUserMap.get(timeKey));
            MemberDealVO newMemberItem = getMemberPayInfo(newUserMap.get(timeKey));
            res.setCurrentDay(DateUtils.dateToNumber(startTime));
            // 支付会员数
            res.setOldPayMemberNum(oldMemberItem.getPayMemberNum());
            res.setNewPayMemberNum(newMemberItem.getPayMemberNum());
            // 支付订单数
            res.setNewPayOrderNum(newMemberItem.getPayOrderNum());
            res.setOldPayOrderNum(oldMemberItem.getPayOrderNum());
            // 支付金额
            res.setOldPayAmount(oldMemberItem.getPayAmount());
            res.setNewPayAmount(newMemberItem.getPayAmount());
            // 客单价
            res.setOldPricePerMember(AnalysisUtil.divAverage(res.getOldPayAmount(), res.getOldPayMemberNum(), 2));
            res.setNewPricePerMember(AnalysisUtil.divAverage(res.getNewPayAmount(), res.getNewPayMemberNum(), 2));
            trend.add(res);
            startTime = DateUtil.offsetDay(startTime, 1);
        }
        return trend;
    }

    private void statisticsMemberContributeValue(MemberReqDTO param, Map<Integer, MemberContributeValueVO> memberContributeValueMap) {
        // 今日实时 order、 user 中统计
        if (Objects.equals(FlowDateTypeEnum.REAL_TIME.value(), param.getDateType())) {
            List<MemberContributeValueVO> memberContributeValueList = userAnalyseMongoService.statisticsRealMemberContributeValue(
                    param.getStartTime(),
                    param.getEndTime()
            );

            MemberCountVO memberCountVO = userFeignClient.statisticsUserNum(new MemberReqDTO(param.getStartTime(), param.getEndTime()));


            // 累计会员数
            Map<Integer, MemberContributeValueVO> map = memberContributeValueList.stream().collect(Collectors.toMap(MemberContributeValueVO::getUserType, f -> f));
            for (int i = 1; i < Constant.THREE; i++) {
                MemberContributeValueVO memberContributeValueVO = map.get(i);
                if (Objects.isNull(memberContributeValueVO)) {
                    memberContributeValueVO = new MemberContributeValueVO();
                }
                if (i == 1) {
                    // 普通会员数 = 总会员数 - 付费会员数
                    memberContributeValueVO.setTotalMember(memberCountVO.getTotalMember() - memberCountVO.getPaidMember());
                } else {
                    memberContributeValueVO.setTotalMember(memberCountVO.getPaidMember());
                }
                memberContributeValueMap.put(i, memberContributeValueVO);
            }
        }

        // 日、周、月、近7天、近30天 flow_user中查询
        else {
            List<FlowUserBO> flowUserList = userAnalyseMongoService.listFlowUserByTimeAndUserType(
                    param.getStartTime(),
                    param.getEndTime(),
                    param.getDateType(),
                    null);

            for (FlowUserBO flowUserBO : flowUserList) {
                if (Objects.isNull(flowUserBO.getType()) || flowUserBO.getType() < 1 || flowUserBO.getType() > 2) {
                    continue;
                }
                MemberContributeValueVO memberContributeValueVO = new MemberContributeValueVO();
                memberContributeValueVO.setTotalMember(flowUserBO.getUserNum());
                memberContributeValueVO.setPayMemberNum(flowUserBO.getPayUser());
                memberContributeValueVO.setPayOrderNum(flowUserBO.getPayOrder());
                memberContributeValueVO.setPayAmount(handleLong(flowUserBO.getPayAmount()));
                memberContributeValueMap.put(flowUserBO.getType(), memberContributeValueVO);
            }
        }
    }

    private void setMemberOverviewList(MemberReqDTO param, MemberOverviewVO memberOverviewVO, MemberSurveyRespVO memberSurveyRespVO) {
        // 查询每天的统计数据
        List<FlowUserBO> flowUserList = userAnalyseMongoService.listFlowUserByTimeAndUserType(param.getStartTime(), param.getEndTime(), FlowDateTypeEnum.DAY.value(), param.getMemberType());
        List<MemberOverviewVO> memberOverviewList = this.toMemberSurveyRespVO(flowUserList);
        Map<Long, MemberOverviewVO> map = memberOverviewList.stream().collect(Collectors.toMap(memberOverview -> memberOverview.getCreateTime().getTime(), k -> k));
        // 今日实时要加上当天统计的数据
        if (Objects.equals(FlowDateTypeEnum.REAL_TIME.value(), param.getDateType())) {
            map.put(memberOverviewVO.getCreateTime().getTime(), memberOverviewVO);
        }
        memberOverviewList.clear();

        // 根据时间顺序，处理查询的每日统计数据
        Date currentTime = param.getStartTime();
        long endTime = param.getEndTime().getTime();
        while (currentTime.getTime() < endTime) {
            MemberOverviewVO memberOverview = map.get(currentTime.getTime());
            if (Objects.isNull(memberOverview)) {
                memberOverview = new MemberOverviewVO();
                memberOverview.setCreateTime(currentTime);
            }
            memberOverview.setCurrentDay(DateUtils.dateToNumber(currentTime));
            memberOverviewList.add(memberOverview);
            // 增加一天，继续下一轮循环
            currentTime = FlowUtil.increaseByDateType(currentTime, param.getDateType());
        }

        memberSurveyRespVO.setMemberOverviewModelList(memberOverviewList);
    }

    private void getGeneralizeRate(MemberOverviewVO memberOverviewVO, MemberOverviewVO oldMemberOverviewVO){
        memberOverviewVO.setMemberSingleAmount(Arith.div(memberOverviewVO.getMemberPayAmount(),memberOverviewVO.getPayMember(),2));
        oldMemberOverviewVO.setMemberSingleAmount(Arith.div(oldMemberOverviewVO.getMemberPayAmount(),oldMemberOverviewVO.getPayMember(),2));
        memberOverviewVO.setTotalMemberRate(setRate(memberOverviewVO.getTotalMember().doubleValue(),oldMemberOverviewVO.getTotalMember().doubleValue()));
        memberOverviewVO.setNewMemberRate(setRate(memberOverviewVO.getNewMember().doubleValue(),oldMemberOverviewVO.getNewMember().doubleValue()));
        memberOverviewVO.setCouponMemberRate(setRate(memberOverviewVO.getCouponMember().doubleValue(),oldMemberOverviewVO.getCouponMember().doubleValue()));
        memberOverviewVO.setPayMemberRate(setRate(memberOverviewVO.getPayMember().doubleValue(),oldMemberOverviewVO.getPayMember().doubleValue()));
        memberOverviewVO.setMemberPayAmountRate(setRate(memberOverviewVO.getMemberPayAmount(),oldMemberOverviewVO.getMemberPayAmount()));
        memberOverviewVO.setMemberPayOrderRate(setRate(memberOverviewVO.getMemberPayOrder().doubleValue(),oldMemberOverviewVO.getMemberPayOrder().doubleValue()));
        memberOverviewVO.setMemberSingleAmountRate(setRate(memberOverviewVO.getMemberSingleAmount(),oldMemberOverviewVO.getMemberSingleAmount()));

    }

    private MemberOverviewVO toMemberSurveyRespVO(FlowUserBO flowUser) {
        return this.toMemberSurveyRespVO(Collections.singletonList(flowUser)).get(0);
    }

    private List<MemberOverviewVO> toMemberSurveyRespVO(List<FlowUserBO> flowUserList) {
        List<MemberOverviewVO> memberOverviewVOList = new ArrayList<>();
        if (CollUtil.isEmpty(flowUserList)) {
            return memberOverviewVOList;
        }


        for (FlowUserBO flowUserBO : flowUserList) {
            MemberOverviewVO memberOverviewVO = new MemberOverviewVO();
            memberOverviewVO.setCreateTime(flowUserBO.getCreateTime());
            // 累积会员数
            if (Objects.nonNull(flowUserBO.getUserNum())) {
                memberOverviewVO.setTotalMember(flowUserBO.getUserNum());
            }
            // 新增会员数
            if (Objects.nonNull(flowUserBO.getNewUserNum())) {
                memberOverviewVO.setNewMember(flowUserBO.getNewUserNum());
            }
            // 支付会员数
            if (Objects.nonNull(flowUserBO.getPayUser())) {
                memberOverviewVO.setPayMember(flowUserBO.getPayUser());
            }
            // 领券会员数
            if (Objects.nonNull(flowUserBO.getReceiveCouponUser())) {
                memberOverviewVO.setCouponMember(flowUserBO.getReceiveCouponUser());
            }
            // 会员支付金额
            if (Objects.nonNull(flowUserBO.getPayAmount())) {
                memberOverviewVO.setMemberPayAmount(handleLong(flowUserBO.getPayAmount()));
            }
            // 会员支付订单数
            if (Objects.nonNull(flowUserBO.getPayOrder())) {
                memberOverviewVO.setMemberPayOrder(flowUserBO.getPayOrder());
            }
            memberOverviewVOList.add(memberOverviewVO);
        }
        return memberOverviewVOList;
    }

    private MemberOverviewVO realMemberSurvey(MemberReqDTO param) {
        MemberOverviewVO memberOverviewVO = statisticsMemberOrderInfo(param);
        // 领券会员数
        // 获取领取的所有优惠券的用户和优惠券数量集合
        List<Long> receiverUserIds = couponFeignClient.countMemberCouponByParam(param.getShopId(), param.getStartTime(), param.getEndTime()).getData();
        if(CollectionUtil.isEmpty(receiverUserIds)){
            // 领券会员数
            memberOverviewVO.setCouponMember(0);
        }else{
            // 如果不为0则筛选一下当前满足条件的用户
            if (!Objects.equals(param.getMemberType(), 0)) {
                // 筛选交集的用户
                param.setUserIds(receiverUserIds);
                receiverUserIds = userFeignClient.getMeetConditionsUserIds(param).getData();
            }
            // 领券会员数
            memberOverviewVO.setCouponMember(CollectionUtil.isEmpty(receiverUserIds) ? 0 : receiverUserIds.size());
        }
        return memberOverviewVO;
    }

    private MemberOverviewVO statisticsMemberOrderInfo(MemberReqDTO param) {
        // 查询当前的用户数量，不需要传开始时间
        MemberCountVO memberCountVO = userFeignClient.statisticsUserNum(param);

        MemberOverviewVO memberOverviewVO = new MemberOverviewVO();

        // 累积会员数、新增会员数
        this.setMenberNum(param.getMemberType(), memberCountVO, memberOverviewVO);

        // 支付会员数、会员支付金额、会员支付订单数、会员客单价
        UserOrderStatisticBO userOrderStatisticBO = orderFeignClient.getPaidMemberByParam(param).getData();
        if(Objects.isNull(userOrderStatisticBO)){
            // 会员支付金额
            memberOverviewVO.setMemberPayAmount(0.00);
            // 会员支付订单数
            memberOverviewVO.setMemberPayOrder(0);
            // 会员客单价
            memberOverviewVO.setMemberSingleAmount(0.0);
            // 支付会员数
            memberOverviewVO.setPayMember(0);
        }else {
            // 会员支付金额，分转换成元
            memberOverviewVO.setMemberPayAmount(handDouble(PriceUtil.toDecimalPrice(userOrderStatisticBO.getActualAmount()).doubleValue()));
            // 支付会员数
            memberOverviewVO.setPayMember(userOrderStatisticBO.getPayUserCount());
            // 会员支付订单数
            memberOverviewVO.setMemberPayOrder(userOrderStatisticBO.getConsTimes());
            // 会员客单价
            memberOverviewVO.setMemberSingleAmount(divAverage(memberOverviewVO.getMemberPayAmount(), memberOverviewVO.getPayMember(), 2));
        }
        return memberOverviewVO;
    }

    private void setMenberNum(Integer memberType, MemberCountVO memberCountVO, MemberOverviewVO memberOverviewVO) {
        if (Objects.isNull(memberType) || Objects.equals(memberType, 0)) {
            memberOverviewVO.setTotalMember(memberCountVO.getTotalMember());
            memberOverviewVO.setNewMember(memberCountVO.getNewMember());
        } else if (Objects.equals(memberType, 1)) {
            memberOverviewVO.setTotalMember(memberCountVO.getTotalMember() - memberCountVO.getPaidMember());
            memberOverviewVO.setNewMember(memberCountVO.getNewMember());
        } else  {
            memberOverviewVO.setTotalMember(memberCountVO.getPaidMember());
            memberOverviewVO.setNewMember(memberCountVO.getNewPaidMember());
        }
    }

    private MemberDealVO handleMemberPayInfo(List<UserOrderStatisticBO> userOrderStatisticList) {
        if (CollUtil.isEmpty(userOrderStatisticList)) {
            return getMemberPayInfo(null);
        }
        return getMemberPayInfo(userOrderStatisticList.get(0));
    }

    private MemberDealVO getMemberPayInfo(UserOrderStatisticBO userOrderStatistic) {
        MemberDealVO memberDealVO = new MemberDealVO();
        if (Objects.isNull(userOrderStatistic)) {
            memberDealVO.setPayMemberNum(0);
            memberDealVO.setPayAmount(0.00);
            memberDealVO.setPricePerMember(0.00);
            memberDealVO.setPayOrderNum(0);
        } else {
            memberDealVO.setPayMemberNum(userOrderStatistic.getPayUserCount());
            Double payAmount = userOrderStatistic.getConsAmount();
            if (Objects.isNull(payAmount)) {
                payAmount = 0.00;
            }
            memberDealVO.setPayAmount(payAmount/100);
            double priceMember = (double) Math.round(divAverage(payAmount, memberDealVO.getPayMemberNum(), 2));
            memberDealVO.setPricePerMember(priceMember/100);
            memberDealVO.setPayOrderNum(userOrderStatistic.getConsTimes());
        }
        return memberDealVO;
    }

    private Double handleLong(Long value){
        if (Objects.isNull(value)){
            return 0.00;
        }
        return PriceUtil.toDecimalPrice(value).doubleValue();
    }

    private Double divAverage(Integer a, Integer b) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, 4);
    }

    private Double divAverage(Double a, Integer b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }
    private Double divAverage(Double a, Double b) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, 4);
    }


    private Double setRate(Double newNum,Double oldNum){
        if (newNum.equals(0.0) && oldNum.equals(0.0)){
            return 0.0;
        }else if (newNum > 0.0 && oldNum.equals(0.0)){
            return 0.0;
        }else if (newNum.equals(0.0) && oldNum > 0.0){
            return -100.0;
        }
        double sub = Arith.sub(newNum, oldNum);
        return Arith.mul(Arith.div(sub,oldNum,2),100);
    }

    private Double handDouble(Double value){
        if (Objects.isNull(value)){
            return 0.00;
        }
        return value;
    }
}
