package com.xxfc.platform.order.biz;

import com.github.wxiaoqi.security.admin.bo.UserBo;
import com.github.wxiaoqi.security.admin.feign.UserFeign;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.github.wxiaoqi.security.common.enumconstant.LevelEnum;
import com.github.wxiaoqi.security.common.vo.PageDataVO;
import com.xxfc.platform.order.contant.enumerate.MemberStatisticsBehaviorTypeEnum;
import com.xxfc.platform.order.entity.MemberStatistics;
import com.xxfc.platform.order.mapper.MemberStatisticsMapper;
import com.xxfc.platform.order.pojo.bo.MemberStatisticsBo;
import com.xxfc.platform.order.pojo.bo.MemberStatisticsPageBo;
import com.xxfc.platform.order.pojo.dto.MemberStatisticsFindDTO;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author libin
 * @version 1.0
 * @description
 * @data 2020/1/6 12:35
 */
@Transactional(rollbackFor = Exception.class)
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MemberStatisticsBiz extends BaseBiz<MemberStatisticsMapper, MemberStatistics> {
    private final UserFeign userFeign;

    public MemberStatisticsPageBo findMemberStatisticsWithPage(MemberStatisticsFindDTO memberStatisticsFindDTO) {
        Example example = getMemberStatisticsExample(memberStatisticsFindDTO);

        PageDataVO<MemberStatistics> dataVO = PageDataVO.pageInfo(memberStatisticsFindDTO.getPage(), memberStatisticsFindDTO.getLimit(), () -> mapper.selectByExample(example));
        List<MemberStatistics> data = dataVO.getData();
        if (CollectionUtils.isEmpty(data)) {
            return new MemberStatisticsPageBo();
        }
        MemberStatisticsPageBo memberStatisticsPageBo = createMemberStatistics(memberStatisticsFindDTO);
        memberStatisticsPageBo = wrapToMemberStatisticsPageBo(data,memberStatisticsPageBo);
        memberStatisticsPageBo.setPageNum(dataVO.getPageNum());
        memberStatisticsPageBo.setPageSize(dataVO.getPageSize());
        memberStatisticsPageBo.setTotalCount(dataVO.getTotalCount());
        memberStatisticsPageBo.setTotalPage(dataVO.getTotalPage());
        return memberStatisticsPageBo;
    }

    private Example getMemberStatisticsExample(MemberStatisticsFindDTO memberStatisticsFindDTO) {
        Example example = new Example(MemberStatistics.class);
        Example.Criteria criteria = example.createCriteria();
        if (Objects.nonNull(memberStatisticsFindDTO.getBehaviorType())) {
            if (memberStatisticsFindDTO.getBehaviorType() == MemberStatisticsBehaviorTypeEnum.PAY.getCode()) {
                criteria.andIn("behaviorType", Arrays.asList(MemberStatisticsBehaviorTypeEnum.FIRST_TIME_BUY.getCode(), MemberStatisticsBehaviorTypeEnum.RENEW.getCode()));
            } else {
                criteria.andEqualTo("behaviorType", memberStatisticsFindDTO.getBehaviorType());
            }
        }
        if (Objects.nonNull(memberStatisticsFindDTO.getStartTime()) && Objects.nonNull(memberStatisticsFindDTO.getEndTime())) {
            criteria.andBetween("payTime", memberStatisticsFindDTO.getStartTime(), memberStatisticsFindDTO.getEndTime());
        }
        if (Objects.nonNull(memberStatisticsFindDTO.getStartTime()) && Objects.isNull(memberStatisticsFindDTO.getEndTime())) {
            criteria.andGreaterThanOrEqualTo("payTime", memberStatisticsFindDTO.getStartTime());
        }
        if (Objects.nonNull(memberStatisticsFindDTO.getEndTime()) && Objects.isNull(memberStatisticsFindDTO.getStartTime())) {
            criteria.andLessThanOrEqualTo("payTime", memberStatisticsFindDTO.getEndTime());
        }
        return example;
    }

    public MemberStatisticsPageBo wrapToMemberStatisticsPageBo(List<MemberStatistics> memberStatistics,MemberStatisticsPageBo memberStatisticsPageBo) {
        if (CollectionUtils.isEmpty(memberStatistics)) {
            return memberStatisticsPageBo;
        }
        //用户id
        List<Integer> userIds = memberStatistics.stream().map(member ->
                Arrays.asList(member.getUserId(), member.getParentId())
        ).flatMap(List::stream).filter(Objects::nonNull).distinct().collect(Collectors.toList());

        List<UserBo> userBos = userFeign.findUserDetailUserIds(userIds);
        Map<Integer, UserBo> userBoMap = userBos.stream().collect(Collectors.toMap(UserBo::getUserId, Function.identity()));
        List<MemberStatisticsBo> memberStatisticsBos = new ArrayList<>();
        MemberStatisticsBo memberStatisticsBo;
        UserBo userBo = new UserBo();
        boolean isNullOrEmpty = userBoMap == null || userBoMap.isEmpty();
        for (MemberStatistics memberStatistic : memberStatistics) {
            memberStatisticsBo = new MemberStatisticsBo();
            BeanUtils.copyProperties(memberStatistic, memberStatisticsBo);
            UserBo bo = isNullOrEmpty ? userBo : userBoMap.get(memberStatistic.getUserId()) == null ? userBo : userBoMap.get(memberStatistic.getUserId());
            memberStatisticsBo.setName(bo.getName());
            memberStatisticsBo.setPhone(bo.getPhone());
            UserBo leaderUserBo = isNullOrEmpty ? userBo : userBoMap.get(memberStatistic.getParentId()) == null ? userBo : userBoMap.get(memberStatistic.getParentId());
            memberStatisticsBo.setParentName(leaderUserBo.getName());
            memberStatisticsBo.setParentPhone(leaderUserBo.getPhone());
            memberStatisticsBo.setMemberName(LevelEnum.getLevelEnumByLevel(memberStatistic.getMemberLevel()).getDesc());
            memberStatisticsBos.add(memberStatisticsBo);
        }

        memberStatisticsPageBo.setMemberStatistics(memberStatisticsBos);
        return memberStatisticsPageBo;
    }

    public MemberStatisticsPageBo createMemberStatistics(MemberStatisticsFindDTO memberStatisticsFindDTO) {
        MemberStatisticsPageBo memberStatisticsPageBo = new MemberStatisticsPageBo();
        boolean isStatistics = memberStatisticsFindDTO.getPage() != null && (memberStatisticsFindDTO.getPage() == 1 || memberStatisticsFindDTO.getIsExport());
        if (isStatistics) {
            Example memberStatisticsExample = getMemberStatisticsExample(memberStatisticsFindDTO);
            List<MemberStatistics> memberStatistics = mapper.selectByExample(memberStatisticsExample);

            if (CollectionUtils.isEmpty(memberStatistics)) {
                return memberStatisticsPageBo;
            }

            Supplier<Stream<MemberStatistics>> memberStatisticsSupplier = () -> memberStatistics.stream();
            Map<Integer, Long> memberBehaviorMap = memberStatisticsSupplier.get().collect(Collectors.groupingBy(MemberStatistics::getBehaviorType, Collectors.counting()));

            //激活人数
            long activateNum = memberBehaviorMap.get(MemberStatisticsBehaviorTypeEnum.ACTIVATE.getCode()) == null ? 0 : memberBehaviorMap.get(MemberStatisticsBehaviorTypeEnum.ACTIVATE.getCode());
            memberStatisticsPageBo.setActivateMembersNum(activateNum);

            //会员订单数
            long firstBuyNum = memberBehaviorMap.get(MemberStatisticsBehaviorTypeEnum.FIRST_TIME_BUY.getCode()) == null ? 0 : memberBehaviorMap.get(MemberStatisticsBehaviorTypeEnum.FIRST_TIME_BUY.getCode());
            long renewNum = memberBehaviorMap.get(MemberStatisticsBehaviorTypeEnum.RENEW.getCode()) == null ? 0 : memberBehaviorMap.get(MemberStatisticsBehaviorTypeEnum.RENEW.getCode());
            long orderNums = firstBuyNum + renewNum;
            memberStatisticsPageBo.setMemberOrdersNum(orderNums);

            //新增会员人数
            long newMemberNum = memberStatisticsSupplier.get().filter(member -> Objects.equals(member.getIsFirstTimeMember(), 1)).count();
            memberStatisticsPageBo.setNewMembersNum(newMemberNum);

            //会员等级分类
            Map<Integer, List<MemberStatistics>> memberLevelStatisticsMap = memberStatisticsSupplier.get()
                    .filter(member -> member.getBehaviorType() != MemberStatisticsBehaviorTypeEnum.ACTIVATE.getCode())
                    .collect(Collectors.groupingBy(MemberStatistics::getMemberLevel, Collectors.toList()));

            if (memberLevelStatisticsMap == null || memberLevelStatisticsMap.isEmpty()) {
                return memberStatisticsPageBo;
            }
            memberLevelStatisticsMap.forEach((K, V) -> {
                LevelEnum levelEnum = LevelEnum.getLevelEnumByLevel(K);
                wrapMemberStatisticsPageBo(levelEnum, V, memberStatisticsPageBo);
            });

            //会员订单金额
            BigDecimal totalMemberAmount = memberStatisticsPageBo.getCommonMemberOrderAmount()
                    .add(memberStatisticsPageBo.getGoldMemberOrderAmount())
                    .add(memberStatisticsPageBo.getDiamondMemberOrderAmount()).setScale(2, BigDecimal.ROUND_HALF_UP);

            memberStatisticsPageBo.setMemberAmount(totalMemberAmount);
        }
        return memberStatisticsPageBo;
    }

    private void wrapMemberStatisticsPageBo(LevelEnum levelEnum, List<MemberStatistics> memberStatistics, MemberStatisticsPageBo memberStatisticsPageBo) {
        int orderNum = memberStatistics.size();
        BigDecimal orderAmount = memberStatistics.stream().map(MemberStatistics::getRealAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        switch (levelEnum) {
            case GENERAL:
                memberStatisticsPageBo.setCommonMemberOrdersNum(orderNum);
                memberStatisticsPageBo.setCommonMemberOrderAmount(orderAmount);
                break;
            case GOLD:
                memberStatisticsPageBo.setGoldMemberOrdersNum(orderNum);
                memberStatisticsPageBo.setGoldMemberOrderAmount(orderAmount);
                break;
            case DIAMOND:
                memberStatisticsPageBo.setDiamondMemberOrdersNum(orderNum);
                memberStatisticsPageBo.setDiamondMemberOrderAmount(orderAmount);
                break;
            default:
                break;
        }
    }
}
