package com.xxfc.platform.order.biz;

import cn.hutool.core.util.ObjectUtil;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.google.common.collect.Lists;
import com.xxfc.platform.order.bo.FeeTypeBo;
import com.xxfc.platform.order.contant.enumerate.StatisticsStatusEnum;
import com.xxfc.platform.order.entity.OrderRentVehicleReceivedStatistics;
import com.xxfc.platform.order.mapper.OrderRentVehicleReceivedStatisticsMapper;
import com.xxfc.platform.order.pojo.account.OrderAccountBo;
import com.xxfc.platform.order.pojo.dto.OrderDTO;
import com.xxfc.platform.order.pojo.dto.OrderReceivedStatisticsFindDTO;
import lombok.RequiredArgsConstructor;
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.function.Supplier;
import java.util.stream.Stream;

/**
 * 租车订单统计
 *
 * @author libin
 * @email 18178966185@163.com
 * @date 2019-11-08 18:03:42
 */
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OrderRentVehicleReceivedStatisticsBiz extends BaseBiz<OrderRentVehicleReceivedStatisticsMapper, OrderRentVehicleReceivedStatistics> {
    private final BaseOrderBiz baseOrderBiz;
    private final OrderAccountBiz orderAccountBiz;

    /**
     * 租车统计查询
     *
     * @param orderReceivedStatisticsFindDTO
     * @return
     */
    public List<OrderRentVehicleReceivedStatistics> selectOrderReceivedStatistics(OrderReceivedStatisticsFindDTO orderReceivedStatisticsFindDTO) {
        return mapper.selectOrderRentVehicleReceivedStatistics(orderReceivedStatisticsFindDTO);
    }

    /**
     * 租车统计处理
     *
     * @param startDate  开始时间
     * @param endDate    结束时间
     * @param companyMap 公司
     */
    public List<OrderRentVehicleReceivedStatistics> orderRentVehicleReceivedStatistics(Date startDate, Date endDate, Map<Integer, String> companyMap) {
        List<OrderRentVehicleReceivedStatistics> orderRentVehicleReceivedStatisticsList = new ArrayList<>();
        List<String> stisticsActiveState = new ArrayList<>();
        //根据租车订单类型 时间查询
        List<OrderDTO> orderDTOS = baseOrderBiz.selectOrdersByTypeAndTime(Arrays.asList(StatisticsStatusEnum.ORDER_RENT_VEHICLE_TYPE),null, startDate, endDate);
        //数据处理 状态组合 按支付状态分组 而后按组合状态
        Map<Boolean, Map<String, List<OrderDTO>>> stateGroupMap = StatisticsStatusEnum.processOrdersWithState(stisticsActiveState, orderDTOS);

        //订单账目信息
        List<OrderAccountBo> orderAccountBoList = orderAccountBiz.selectByTypeAndDate(StatisticsStatusEnum.ORDER_RENT_VEHICLE_TYPE, startDate, endDate);
        //账目数据处理 状态组合
        Map<String, List<OrderAccountBo>> ordersMap = StatisticsStatusEnum.processOrderAccountsWithState(stisticsActiveState, orderAccountBoList);

        //遍历已经支付单
        Set<Map.Entry<String, List<OrderAccountBo>>> ordersSet = ordersMap.entrySet();
        for (Map.Entry<String, List<OrderAccountBo>> orderEntry : ordersSet) {
            String orderKey = orderEntry.getKey();
            List<OrderAccountBo> orderAccountBos = orderEntry.getValue();
            OrderRentVehicleReceivedStatistics orderRentVehicleReceivedStatistics = createDefaultOrderMemberReceivedStatistics();
            StatisticsStatusEnum.wrapStatisticsObject(startDate, orderKey, companyMap,orderRentVehicleReceivedStatistics);
            //账目处理
            FeeTypeBo feeTypeBo = StatisticsStatusEnum.getFeeTyBoByOrderAccounts(orderAccountBos);
            BeanUtils.copyProperties(feeTypeBo, orderRentVehicleReceivedStatistics);
            //订单量
            Integer totalQuantity = stateGroupMap == null ?
                    0 : stateGroupMap.get(Boolean.TRUE) == null ?
                    0 : stateGroupMap.get(Boolean.TRUE).get(orderKey) == null ?
                    0 : stateGroupMap.get(Boolean.TRUE).get(orderKey).size();
            orderRentVehicleReceivedStatistics.setTotalQuantity(totalQuantity);
            orderRentVehicleReceivedStatisticsList.add(orderRentVehicleReceivedStatistics);
        }
        //未支付单
        Map<String, List<OrderDTO>> noPayOrderRentvehicleMap = stateGroupMap == null ?
                Collections.EMPTY_MAP : stateGroupMap.get(Boolean.FALSE) == null ?
                Collections.EMPTY_MAP : stateGroupMap.get(Boolean.FALSE);
        List<OrderRentVehicleReceivedStatistics> noPayOrderRentVehicleStatisticsList = createNoPayOrderRentVehicleStatisticsList(startDate, noPayOrderRentvehicleMap, companyMap);
        orderRentVehicleReceivedStatisticsList.addAll(noPayOrderRentVehicleStatisticsList);

        //创建剩余状态组合的租车统计对象
        List<OrderRentVehicleReceivedStatistics> otherStatisticsStateGroupList = createOtherStatisticsStateGroupList(startDate, stisticsActiveState, companyMap);
        orderRentVehicleReceivedStatisticsList.addAll(otherStatisticsStateGroupList);
        //保存
        StatisticsStatusEnum.insertReceivedStatisticsBatch(orderRentVehicleReceivedStatisticsList,mapper);

        return orderRentVehicleReceivedStatisticsList;
    }




    /**
     * @param startDate      时间
     * @param noPayOrdersMap 未支付单map
     * @param companyMap 公司map
     * @return
     */
    private List<OrderRentVehicleReceivedStatistics> createNoPayOrderRentVehicleStatisticsList(Date startDate, Map<String, List<OrderDTO>> noPayOrdersMap, Map<Integer, String> companyMap) {
        List<OrderRentVehicleReceivedStatistics> orderRentVehicleReceivedStatisticsList = new ArrayList<>();
        if (noPayOrdersMap == null || noPayOrdersMap.isEmpty()) {
            return orderRentVehicleReceivedStatisticsList;
        }
        Set<Map.Entry<String, List<OrderDTO>>> noPayOrderSet = noPayOrdersMap.entrySet();
        //遍历未支付单map
        for (Map.Entry<String, List<OrderDTO>> noPayOrderEntry : noPayOrderSet) {
            //某种状态组合的租车单
            List<OrderDTO> noPayOrders = noPayOrderEntry.getValue();
            //创建默认的租车订单统计对象
            OrderRentVehicleReceivedStatistics orderRentVehicleReceivedStatistics = createDefaultOrderMemberReceivedStatistics();
            //设置相关默认值
            StatisticsStatusEnum.wrapStatisticsObject(startDate, noPayOrderEntry.getKey(), companyMap, orderRentVehicleReceivedStatistics);
            //租车订单流
            Supplier<Stream<OrderDTO>> orderDtoStreamSupplier = ()-> noPayOrders.stream();
            //总免赔
            BigDecimal damageSafeAmount = BigDecimal.ZERO;
            //总订单金额(包含免赔，不包含押金)
            BigDecimal totalAmount = BigDecimal.ZERO;
            //总押金
            BigDecimal depositAmount = BigDecimal.ZERO;

            //遍历租车单 累计订单总额 总押金 总免赔
            for (OrderDTO noPayOrder : noPayOrders) {
                //免赔
                boolean hasDamageSafe = Objects.nonNull(noPayOrder.getDamageSafe()) && (noPayOrder.getDamageSafe() == StatisticsStatusEnum.DAMAGE_SAFE);
                if (hasDamageSafe) {
                    damageSafeAmount = damageSafeAmount.add(StatisticsStatusEnum.getDameSafeAmount(noPayOrder.getData()));
                }
                totalAmount = totalAmount.add(noPayOrder.getRealAmount()).subtract(totalAmount);
                depositAmount = depositAmount.add(noPayOrder.getDeposit());
            }

            orderRentVehicleReceivedStatistics.setNoDeductibleAmount(damageSafeAmount);
            orderRentVehicleReceivedStatistics.setDepositAmount(depositAmount);
            BigDecimal totalNoPayAmount = orderDtoStreamSupplier.get().map(OrderDTO::getRealAmount).reduce(BigDecimal.ZERO,BigDecimal::add);
            //租车费减去 押金和不计免赔费
            orderRentVehicleReceivedStatistics.setTotalAmount(totalNoPayAmount.subtract(depositAmount).subtract(damageSafeAmount));
            //总订单总量
            orderRentVehicleReceivedStatistics.setTotalQuantity(noPayOrders.size());

            orderRentVehicleReceivedStatisticsList.add(orderRentVehicleReceivedStatistics);
        }
        return orderRentVehicleReceivedStatisticsList;
    }

    /**
     * 创建剩余状态数据
     *
     * @param startDate             时间
     * @param statisticsStateGroups 状态组合 集合
     * @param companyMap            公司
     * @return
     */
    private List<OrderRentVehicleReceivedStatistics> createOtherStatisticsStateGroupList(Date startDate,
                                                                                         List<String> statisticsStateGroups,
                                                                                         Map<Integer, String> companyMap) {

        List<OrderRentVehicleReceivedStatistics> orderRentVehicleReceivedStatisticsList = new ArrayList<>(statisticsStateGroups.size());
        //获取剩余状态组合
        List<Integer> companyIds = Objects.isNull(companyMap) ? Collections.EMPTY_LIST : Lists.newArrayList(companyMap.keySet());
        List<String> otherStatisticsStateGroup = StatisticsStatusEnum.getOtherStatisticsStateGroup(companyIds, statisticsStateGroups);
        //创建租车统计克隆对象
        OrderRentVehicleReceivedStatistics orderRentVehicleReceivedStatistics = createDefaultOrderMemberReceivedStatistics();
        //统计对象的生成
        otherStatisticsStateGroup.stream().map(stateGroup -> {
            OrderRentVehicleReceivedStatistics orderRentVehicleReceivedStatisticsClone = StatisticsStatusEnum.wrapStatisticsObject(startDate, stateGroup, companyMap, ObjectUtil.cloneByStream(orderRentVehicleReceivedStatistics));
            orderRentVehicleReceivedStatisticsList.add(orderRentVehicleReceivedStatisticsClone);
            return orderRentVehicleReceivedStatisticsClone;
        }).count();

        return orderRentVehicleReceivedStatisticsList;
    }
    /**
     * 创建默认的租车订单统计对象
     *
     * @return
     */
    private OrderRentVehicleReceivedStatistics createDefaultOrderMemberReceivedStatistics() {
        OrderRentVehicleReceivedStatistics orderRentVehicleReceivedStatistics = new OrderRentVehicleReceivedStatistics();
        orderRentVehicleReceivedStatistics.setDepositAmount(BigDecimal.ZERO);
        orderRentVehicleReceivedStatistics.setDepositRefundAmount(BigDecimal.ZERO);
        orderRentVehicleReceivedStatistics.setNoDeductibleAmount(BigDecimal.ZERO);
        orderRentVehicleReceivedStatistics.setNoDeductibleRefundAmount(BigDecimal.ZERO);
        orderRentVehicleReceivedStatistics.setLossSpecifiedAmount(BigDecimal.ZERO);
        orderRentVehicleReceivedStatistics.setBreakRulesRegulationAmount(BigDecimal.ZERO);
        return orderRentVehicleReceivedStatistics;
    }
}