package com.xxfc.platform.order.biz;

import cn.hutool.core.util.ObjectUtil;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.github.wxiaoqi.security.common.enumconstant.LevelEnum;
import com.google.common.collect.Lists;
import com.xxfc.platform.order.contant.enumerate.DeductionTypeEnum;
import com.xxfc.platform.order.contant.enumerate.StatisticsStatusEnum;
import com.xxfc.platform.order.entity.OrderMemberReceivedStatistics;
import com.xxfc.platform.order.mapper.OrderMemberReceivedStatisticsMapper;
import com.xxfc.platform.order.pojo.account.OrderAccountBo;
import com.xxfc.platform.order.pojo.account.OrderAccountDeduction;
import com.xxfc.platform.order.pojo.account.OrderAccountDetail;
import com.xxfc.platform.order.pojo.dto.OrderDTO;
import com.xxfc.platform.order.pojo.dto.OrderReceivedStatisticsFindDTO;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.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 java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 会员订单统计
 *
 * @author libin
 * @email 18178966185@163.com
 * @date 2019-11-08 18:03:42
 */
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OrderMemberReceivedStatisticsBiz extends BaseBiz<OrderMemberReceivedStatisticsMapper, OrderMemberReceivedStatistics>{
    private final BaseOrderBiz baseOrderBiz;
    private final OrderAccountBiz orderAccountBiz;
    private final int PAY_ORDER = 101;

    /**
     * 会员统计查询
     *
     * @param orderReceivedStatisticsFindDTO
     * @return
     */
    public List<OrderMemberReceivedStatistics> selectOrderReceivedStatistics(OrderReceivedStatisticsFindDTO orderReceivedStatisticsFindDTO) {
        return mapper.selectOrderMemberReceivedStatistics(orderReceivedStatisticsFindDTO);
    }

    /**
     * 会员统计处理
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @param companyMap 公司
     */
    public List<OrderMemberReceivedStatistics> orderMemberReceivedStatistics(Date startDate, Date endDate,Map<Integer,String> companyMap) {
        List<OrderMemberReceivedStatistics> orderMemberReceivedStatisticsList = new ArrayList<>(18);
        List<String> stisticsActiveState = new ArrayList<>();

        //根据时间范围查询出会员单
        List<OrderDTO> orders = baseOrderBiz.selectOrdersByTypeAndTime(Arrays.asList(StatisticsStatusEnum.ORDER_MEMBER_TYPE), null,startDate, endDate);

        //数据处理 状态组合 按支付状态分组 而后按组合状态
        Map<Boolean, Map<String, Map<LevelEnum, List<OrderDTO>>>> stateGroupMap = orders.stream().peek(x -> {
            x.setStateGroup(String.format("%d-%d-%d-%d", Objects.isNull(x.getCompanyId())?StatisticsStatusEnum.DEFAULT_COMPANY:x.getCompanyId(),
                    x.getOrderOrigin(), Objects.isNull(x.getPayWay()) ? StatisticsStatusEnum.NO_PAY_WAY : x.getPayWay(),
                    x.getHasPay()));
            stisticsActiveState.add(x.getStateGroup());
        })
                .collect(Collectors.partitioningBy(x -> Objects.nonNull(x.getPayWay()), Collectors.groupingBy(OrderDTO::getStateGroup, Collectors.groupingBy(OrderDTO::getLevelEnum, Collectors.toList()))));

        //订单账目信息
        List<OrderAccountBo> orderAccountBoList = orderAccountBiz.selectByTypeAndDate(StatisticsStatusEnum.ORDER_MEMBER_TYPE, startDate, endDate);
        //账目数据处理 状态组合
        Map<String, Map<LevelEnum, List<OrderAccountBo>>> orderAccountMap = orderAccountBoList.stream().peek(x -> {
            x.setStateGroup(String.format("%d-%d-%d-%d", Objects.isNull(x.getCompanyId())?StatisticsStatusEnum.DEFAULT_COMPANY:x.getCompanyId(), x.getOrderOrigin(),
                    Objects.isNull(x.getPayWay()) ? StatisticsStatusEnum.NO_PAY_WAY : x.getPayWay(),
                    x.getHasPay()));
            stisticsActiveState.add(x.getStateGroup());
        }).collect(Collectors.groupingBy(OrderAccountBo::getStateGroup, Collectors.groupingBy(OrderAccountBo::getLevelEnum, Collectors.toList())));

        //已经支付单
        Set<Map.Entry<String, Map<LevelEnum, List<OrderAccountBo>>>> ordersSet = orderAccountMap.entrySet();
        for (Map.Entry<String, Map<LevelEnum, List<OrderAccountBo>>> orderEntry : ordersSet) {
            //状态key
            String orderKey = orderEntry.getKey();
            Map<LevelEnum, List<OrderAccountBo>> orderMemberLevelMap = orderEntry.getValue();
            Set<Map.Entry<LevelEnum, List<OrderAccountBo>>> ordermemberLevelentries = orderMemberLevelMap.entrySet();
            MemberLevelStatistics memberLevelStatistics = new MemberLevelStatistics();
            //遍历
            for (Map.Entry<LevelEnum, List<OrderAccountBo>> orderMemberLevelEntry : ordermemberLevelentries) {
                Integer totalQuantity = stateGroupMap==null?0:stateGroupMap.get(Boolean.TRUE).get(orderKey) == null ? 0 : stateGroupMap.get(Boolean.TRUE).get(orderKey).size();
                wrapMemberLevelStatistics(orderMemberLevelEntry.getKey(), orderMemberLevelEntry.getValue(), totalQuantity, memberLevelStatistics);
            }
            OrderMemberReceivedStatistics orderMemberReceivedStatistics = StatisticsStatusEnum.wrapStatisticsObject(startDate, orderKey,companyMap,new OrderMemberReceivedStatistics());
            BeanUtils.copyProperties(memberLevelStatistics, orderMemberReceivedStatistics);
            orderMemberReceivedStatisticsList.add(orderMemberReceivedStatistics);
        }

        //未支付单
        Map<String, Map<LevelEnum, List<OrderDTO>>> noPayOrdersMap = stateGroupMap==null?Collections.EMPTY_MAP:stateGroupMap.get(Boolean.FALSE)==null?Collections.EMPTY_MAP:stateGroupMap.get(Boolean.FALSE);
        List<OrderMemberReceivedStatistics> noPayOrderMemberReceivedStatisticsList = createOrderMemberReceivedStatisticsList(startDate,noPayOrdersMap,companyMap);
        orderMemberReceivedStatisticsList.addAll(noPayOrderMemberReceivedStatisticsList);
        //创建剩余状态数据
        List<OrderMemberReceivedStatistics> otherStatisticsStateGroupList = createOtherStatisticsStateGroupList(startDate, stisticsActiveState,companyMap);
        orderMemberReceivedStatisticsList.addAll(otherStatisticsStateGroupList);
        //保存
        insertMemberReceivedStatisticsBatch(orderMemberReceivedStatisticsList);

        return orderMemberReceivedStatisticsList;
    }

    /**
     * memberLevelStatistics 对象包装
     *
     * @param levelEnum 会员等级
     * @param orderAccountBos 账目对象
     * @param totalQuantity 对应等级的单量
     * @param memberLevelStatistics
     * @return
     */
    private MemberLevelStatistics wrapMemberLevelStatistics(LevelEnum levelEnum, List<OrderAccountBo> orderAccountBos, Integer totalQuantity, MemberLevelStatistics memberLevelStatistics) {
          Map<String,BigDecimal> orderFeeMap =  getOrderAmountAndLateFeeAmount(orderAccountBos);
          memberLevelStatistics.setLateFeeAmount(orderFeeMap.get(StatisticsStatusEnum.LATEFEE_AMOUNT));
          memberLevelStatistics.setOrderRefundAmount(orderFeeMap.get(StatisticsStatusEnum.ORDER_REFUND_AMOUNT));
        return wrapMemberLevelStatistics(levelEnum,orderFeeMap.get(StatisticsStatusEnum.ORDER_AMOUNT),totalQuantity,memberLevelStatistics);
    }

    /**
     * 获取收入
     *
     * @param orderAccountBos
     * @return
     */
    private Map<String,BigDecimal> getOrderAmountAndLateFeeAmount(List<OrderAccountBo> orderAccountBos) {
        Map<String,BigDecimal>  orderAndLateMap = new HashMap<>();
        //订单金额
        BigDecimal totalOrderAmount = BigDecimal.ZERO;
        //续约金额
        BigDecimal totalLateFeeAmount = BigDecimal.ZERO;
        //订单退款金额
        BigDecimal totalOrderRefundAmount = BigDecimal.ZERO;
        if (CollectionUtils.isEmpty(orderAccountBos)) {
            return orderAndLateMap;
        }
        for (OrderAccountBo orderAccountBo : orderAccountBos) {
            OrderAccountDetail accountDetailEntity = orderAccountBo.getAccountDetailEntity();
            if (orderAccountBo.getAccountType() == PAY_ORDER) {
                totalOrderAmount = totalOrderAmount.add(accountDetailEntity.getOrderAmount()).add(accountDetailEntity.getDepositAmount());
            } else {
                totalOrderRefundAmount = totalOrderRefundAmount.add(accountDetailEntity.getOrderAmount());
                List<OrderAccountDeduction> deductions = accountDetailEntity.getDeductions();
                for (OrderAccountDeduction deduction : deductions) {
                    Integer type = deduction.getType();
                    if (DeductionTypeEnum.lateFeeCode.contains(type)){
                        totalLateFeeAmount = totalLateFeeAmount.add(deduction.getAmount());
                    }
                }
            }
        }
        orderAndLateMap.put(StatisticsStatusEnum.ORDER_AMOUNT,totalOrderAmount);
        orderAndLateMap.put(StatisticsStatusEnum.LATEFEE_AMOUNT,totalLateFeeAmount);
        orderAndLateMap.put(StatisticsStatusEnum.ORDER_REFUND_AMOUNT,totalOrderRefundAmount);
        return orderAndLateMap;
    }

    /**
     * @param startDate      时间
     * @param noPayOrdersMap 未支付单map
     * @return
     */
    private List<OrderMemberReceivedStatistics> createOrderMemberReceivedStatisticsList(Date startDate, Map<String, Map<LevelEnum, List<OrderDTO>>> noPayOrdersMap,Map<Integer,String> companyMap) {
        List<OrderMemberReceivedStatistics> orderMemberReceivedStatisticsList = new ArrayList<>();
        if (noPayOrdersMap == null || noPayOrdersMap.isEmpty()) {
            return orderMemberReceivedStatisticsList;
        }
        Set<Map.Entry<String, Map<LevelEnum, List<OrderDTO>>>> noPayOrderSet = noPayOrdersMap.entrySet();
        for (Map.Entry<String, Map<LevelEnum, List<OrderDTO>>> noPayOrderEntry : noPayOrderSet) {
            MemberLevelStatistics memberLevelStatistics = new MemberLevelStatistics();
            //获取状态
            String noPayOrderStateGroup = noPayOrderEntry.getKey();
            Map<LevelEnum, List<OrderDTO>> noPayOrderEntryValue = noPayOrderEntry.getValue();
            OrderMemberReceivedStatistics orderMemberReceivedStatistics = StatisticsStatusEnum.wrapStatisticsObject(startDate, noPayOrderStateGroup,companyMap,new OrderMemberReceivedStatistics());
            Set<Map.Entry<LevelEnum, List<OrderDTO>>> noPayOrderEntries = noPayOrderEntryValue.entrySet();
            for (Map.Entry<LevelEnum, List<OrderDTO>> orderEntry : noPayOrderEntries) {
                wrapOrderMemberReceivedStatistics(orderEntry.getValue(), orderEntry.getKey(), memberLevelStatistics);
            }
            BeanUtils.copyProperties(memberLevelStatistics, orderMemberReceivedStatistics);
            orderMemberReceivedStatisticsList.add(orderMemberReceivedStatistics);
        }
        return orderMemberReceivedStatisticsList;
    }

    /**
     * @param orders                某种状态下的会员单
     * @param levelEnum             会员等级
     * @param memberLevelStatistics 会员统计对象
     * @return
     */
    private MemberLevelStatistics wrapOrderMemberReceivedStatistics(List<OrderDTO> orders, LevelEnum levelEnum, MemberLevelStatistics memberLevelStatistics) {
        orders = CollectionUtils.isEmpty(orders) ? Collections.EMPTY_LIST : orders;
        BigDecimal totalAmount = orders.stream().map(OrderDTO::getRealAmount).reduce(BigDecimal.ZERO, (x, y) -> x.add(y));
        return  wrapMemberLevelStatistics(levelEnum,totalAmount,orders.size(),memberLevelStatistics);
    }

    /**
     * memberLevelStatistics 对象包装
     * @param levelEnum
     * @param amount
     * @param quantity
     * @param memberLevelStatistics
     * @return
     */
    private MemberLevelStatistics wrapMemberLevelStatistics(LevelEnum levelEnum,BigDecimal amount,Integer quantity,MemberLevelStatistics memberLevelStatistics){
        switch (levelEnum) {
            case GENERAL:
                memberLevelStatistics.setToalCommonAmmount(amount);
                memberLevelStatistics.setTotalCommonQuantity(quantity);
                break;
            case GOLD:
                memberLevelStatistics.setTotalGoldAmount(amount);
                memberLevelStatistics.setTotalGoldQuantity(quantity);
                break;
            case DIAMOND:
                memberLevelStatistics.setTotalDiamondAmmount(amount);
                memberLevelStatistics.setTotalDiamondQuantity(quantity);
                break;
            default:
                break;
        }
        return memberLevelStatistics;
    }

    /**
     * 创建剩余状态数据
     *
     * @param startDate             时间
     * @param statisticsStateGroups 状态组合 集合
     * @param companyMap             公司
     * @return
     */
    private List<OrderMemberReceivedStatistics> createOtherStatisticsStateGroupList(Date startDate, List<String> statisticsStateGroups,Map<Integer,String> companyMap) {
        List<OrderMemberReceivedStatistics> orderMemberReceivedStatisticsList = new ArrayList<>();
        //获取剩余状态组合
        List<Integer> companyIds = Objects.isNull(companyMap)?Collections.EMPTY_LIST: Lists.newArrayList(companyMap.keySet());
        List<String> otherStatisticsStateGroup = StatisticsStatusEnum.getOtherStatisticsStateGroup(companyIds,statisticsStateGroups);
        //创建会员克隆统计对象
        OrderMemberReceivedStatistics orderMemberReceivedStatistics = createDefaultOrderMemberReceivedStatistics();
        //统计对象的生成
        otherStatisticsStateGroup.stream().peek(stateGroup -> {
            OrderMemberReceivedStatistics orderMemberReceivedStatisticsClone = StatisticsStatusEnum.wrapStatisticsObject(startDate, stateGroup,companyMap,
                    ObjectUtil.clone(orderMemberReceivedStatistics));
            orderMemberReceivedStatisticsList.add(orderMemberReceivedStatisticsClone);
        }).count();
        return orderMemberReceivedStatisticsList;
    }

    /**
     * 创建默认的会员订单统计对象
     *
     * @return
     */
    private OrderMemberReceivedStatistics createDefaultOrderMemberReceivedStatistics() {
        OrderMemberReceivedStatistics orderMemberReceivedStatistics = new OrderMemberReceivedStatistics();
        orderMemberReceivedStatistics.setTotalAmount(BigDecimal.ZERO);
        orderMemberReceivedStatistics.setTotalQuantity(0);
        orderMemberReceivedStatistics.setTotalCommonQuantity(0);
        orderMemberReceivedStatistics.setToalCommonAmmount(BigDecimal.ZERO);
        orderMemberReceivedStatistics.setTotalGoldQuantity(0);
        orderMemberReceivedStatistics.setTotalGoldAmount(BigDecimal.ZERO);
        orderMemberReceivedStatistics.setTotalDiamondQuantity(0);
        orderMemberReceivedStatistics.setTotalDiamondAmmount(BigDecimal.ZERO);
        return orderMemberReceivedStatistics;
    }

    /**
     * 批量插入
     *
     * @param orderMemberReceivedStatistics
     */
    public void insertMemberReceivedStatisticsBatch(List<OrderMemberReceivedStatistics> orderMemberReceivedStatistics) {
        mapper.insertList(orderMemberReceivedStatistics);
    }

    @Data
    @NoArgsConstructor
    private class MemberLevelStatistics {
        private BigDecimal toalCommonAmmount = BigDecimal.ZERO;

        private Integer totalCommonQuantity = new Integer(0);

        private BigDecimal totalGoldAmount = BigDecimal.ZERO;

        private Integer totalGoldQuantity = new Integer(0);

        private BigDecimal totalDiamondAmmount = BigDecimal.ZERO;

        private Integer totalDiamondQuantity = new Integer(0);

        private BigDecimal totalAmount;

        private Integer totalQuantity;

        /**
         * 违约金
         */
        private BigDecimal lateFeeAmount = BigDecimal.ZERO;
        /**
         * 订单退款金额
         */
        private BigDecimal orderRefundAmount = BigDecimal.ZERO;

        /**
         * 非会员费
         */
        private BigDecimal totalNonMemberAmount;

        /**
         * 非会员费
         */
        private BigDecimal totalMemberAmount;

        public BigDecimal getTotalAmount() {
            return toalCommonAmmount.add(totalGoldAmount).add(totalDiamondAmmount);
        }

        public Integer getTotalQuantity() {
            return totalCommonQuantity + totalGoldQuantity + totalDiamondQuantity;
        }
    }
}