package com.xxfc.platform.order.contant.enumerate;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.xxfc.platform.order.bo.FeeTypeBo;
import com.xxfc.platform.order.entity.OrderReceivedStatisticsBase;
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 org.apache.commons.collections4.CollectionUtils;
import org.assertj.core.util.Lists;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.additional.insert.InsertListMapper;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.WeekFields;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author libin
 * @version 1.0
 * @description
 * @data 2019/11/14 14:28
 */
public enum StatisticsStatusEnum {
    ;
    public static final int DEFAULT_COMPANY = 1;
    public static final int ORDER_MEMBER_TYPE = 3;
    public static final int ORDER_RENT_VEHICLE_TYPE = 1;
    public static final int ORDER_TOUR_TYPE = 2;
    public static final int NO_PAY_WAY = 0;
    public static final Integer DEFAULT_SQL_SIZE = 1000;
    public static final String COMPANY_DEFAULT = "欣新房车控股集团";
    public static final String NO_DEDUCTIBLE_AMOUNT = "damageSafeAmount";
    public static final String PARMAM_JSON = "paramJson";
    public static final int DAMAGE_SAFE = 1;
    public static List<String> orderStates;
    public static List<String> orderOrigins;
    public static List<String> orderPayWays;

    static {
        // 0 未支付 1 已支付
        orderStates = Lists.newArrayList("0", "1");
        // 1 app   2 小程序  3 其他
        orderOrigins = Lists.newArrayList("1", "2", "3");
        // 1 微信  2 支付宝  0不需要支付(使用了优惠券之类的)或未支付
        orderPayWays = Lists.newArrayList("1", "2", "0");
    }

    public static List<String> statisticsSateGroupWithCompanys(List<Integer> companyIdList) {
        List<String> orderStatisticsStateGroups = new ArrayList<>();
        List<String> stateGroup = statisticsStateGroup();
        for (String stgp : stateGroup) {
            for (Integer companyId : companyIdList) {
                // 公司id-订单来源-支付方式-订单状态
                orderStatisticsStateGroups.add(String.format("%d-%s", companyId, stgp));
            }
        }
        return orderStatisticsStateGroups;
    }

    public static List<String> statisticsStateGroup() {
        List<String> orderStatisticsStateGroups = new ArrayList<>();
        for (String orderOrigin : orderOrigins) {
            for (String orderPayWay : orderPayWays) {
                for (String orderState : orderStates) {
                    //订单来源-支付方式-订单状态
                    orderStatisticsStateGroups.add(String.format("%s-%s-%s", orderOrigin, orderPayWay, orderState));
                }
            }
        }
        return orderStatisticsStateGroups;
    }

    public static List<String> getOtherStatisticsStateGroup(List<Integer> companyIdList, List<String> statisticsStates) {
        List<String> stateGroupList = CollectionUtils.isEmpty(companyIdList) ? statisticsStateGroup() : statisticsSateGroupWithCompanys(companyIdList);
        stateGroupList.removeAll(statisticsStates);
        return stateGroupList;
    }

    /**
     * 订单状态组合处理
     *
     * @param stisticsActiveState
     * @param orderDTOS
     * @return
     */
    public static Map<Boolean, Map<String, List<OrderDTO>>> processOrdersWithState(List<String> stisticsActiveState, List<OrderDTO> orderDTOS) {
        Map<Boolean, Map<String, List<OrderDTO>>> stateGroupMap = orderDTOS.stream().peek(x -> {
            x.setStateGroup(String.format("%d-%d-%d-%d", Objects.isNull(x.getCompanyId())?DEFAULT_COMPANY:x.getCompanyId(),
                    x.getOrderOrigin(),
                    x.getPayWay() == null ? NO_PAY_WAY : x.getPayWay()
                    , x.getHasPay()));
            stisticsActiveState.add(x.getStateGroup());
        }).collect(Collectors.partitioningBy(x -> Objects.nonNull(x.getPayWay()), Collectors.groupingBy(OrderDTO::getStateGroup, Collectors.toList())));
        return stateGroupMap == null ? Collections.EMPTY_MAP : stateGroupMap;
    }

    /**
     * 订单账目状态组合处理
     * @param stisticsActiveState
     * @param orderAccountBoList
     * @return
     */
    public static Map<String, List<OrderAccountBo>> processOrderAccountsWithState(List<String> stisticsActiveState, List<OrderAccountBo> orderAccountBoList) {
        return orderAccountBoList.stream().peek(x -> {
            x.setStateGroup(String.format("%d-%d-%d-%d", Objects.isNull(x.getCompanyId())?DEFAULT_COMPANY:x.getCompanyId(),
                    x.getOrderOrigin(),
                    x.getPayWay() == null ? StatisticsStatusEnum.NO_PAY_WAY : x.getPayWay(),
                    x.getHasPay()));
            stisticsActiveState.add(x.getStateGroup());
        }).collect(Collectors.groupingBy(OrderAccountBo::getStateGroup, Collectors.toList()));
    }

    /**
     * 获取账目消费
     *
     * @param orderAccountBos
     * @return
     */
    public static FeeTypeBo getFeeTyBoByOrderAccounts(List<OrderAccountBo> orderAccountBos) {
        FeeTypeBo feeTypeBo = new FeeTypeBo();
        for (OrderAccountBo orderAccountBo : orderAccountBos) {
            //账目详情
            OrderAccountDetail accountDetailEntity = orderAccountBo.getAccountDetailEntity();
            //是否买免赔
            boolean hasDamageSafe = Objects.nonNull(orderAccountBo.getDamageSafe()) && (orderAccountBo.getDamageSafe() == StatisticsStatusEnum.DAMAGE_SAFE);
            if (orderAccountBo.getAccountType().equals(AccountTypeEnum.IN_ORDER_PAY.getCode())) {
                //订单押金
                feeTypeBo.setDepositAmount(feeTypeBo.getDepositAmount().add(accountDetailEntity.getDepositAmount()));
                if (hasDamageSafe) {
                    BigDecimal dameSafeAmount = getDameSafeAmount(orderAccountBo.getData());
                    feeTypeBo.setNoDeductibleAmount(feeTypeBo.getNoDeductibleAmount().add(dameSafeAmount));
                }
                //订单金额(不包含免赔和押金)
                feeTypeBo.setTotalAmount(feeTypeBo.getTotalAmount().add(accountDetailEntity.getOrderAmount()).subtract(feeTypeBo.getNoDeductibleAmount()));
            } else {
                //退款订单押金
                feeTypeBo.setDepositRefundAmount(feeTypeBo.getDepositRefundAmount().add(accountDetailEntity.getDepositAmount()));
                //退款详细账目
                List<OrderAccountDeduction> deductions = accountDetailEntity.getDeductions();
                //其它消费明细(租车表详情)
                JSONObject data = orderAccountBo.getData();
                //免赔
                if (hasDamageSafe) {
                    //账目类型是201 取消订单款且消费明细没有
                    if (orderAccountBo.getAccountType().equals(AccountTypeEnum.OUT_ORDER_FUND.getCode()) && CollectionUtils.isEmpty(deductions)) {
                        BigDecimal dameSafeAmount = getDameSafeAmount(data);
                        feeTypeBo.setNoDeductibleRefundAmount(feeTypeBo.getNoDeductibleRefundAmount().add(dameSafeAmount));
                    }
                }
                //遍历消费明细
                for (OrderAccountDeduction deduction : deductions) {
                    BigDecimal deductionAmount = deduction.getAmount();
                    //违约金
                    if (DeductionTypeEnum.lateFeeCode.contains(deduction.getType())) {
                        feeTypeBo.setLateFeeAmount(feeTypeBo.getLateFeeAmount().add(deductionAmount));
                        //免赔 提前取消违约金
                        if (deduction.getType().equals(DeductionTypeEnum.VIOLATE_CANCEL.getCode())) {
                            if (hasDamageSafe) {
                                BigDecimal dameSafeAmount = getDameSafeAmount(data);
                                feeTypeBo.setNoDeductibleRefundAmount(feeTypeBo.getNoDeductibleRefundAmount().add(dameSafeAmount));
                            }
                        }
                    }
                    //违章
                    if (DeductionTypeEnum.breakRulesRegulationCode.contains(deduction.getType())) {
                        feeTypeBo.setBreakRulesRegulationAmount(feeTypeBo.getBreakRulesRegulationAmount().add(deductionAmount));
                    }
                    //定损
                    if (DeductionTypeEnum.lossSpecifiedCode.contains(deduction.getType())) {
                        feeTypeBo.setLossSpecifiedAmount(feeTypeBo.getLossSpecifiedAmount().add(deductionAmount));
                    }
                    //其他消费
                    if (DeductionTypeEnum.consumerCode.contains(deduction.getType())) {
                        BigDecimal extendAmount = deductionAmount.subtract(accountDetailEntity.getOriginOrderAmount());
                        if (extendAmount.doubleValue() > 0) {
                            feeTypeBo.setExtraAmount(feeTypeBo.getExtraAmount().add(extendAmount));
                        }
                    }
                }
                //退款订单金额(不包含免赔和押金)
                feeTypeBo.setOrderRefundAmount(feeTypeBo.getOrderRefundAmount().add(accountDetailEntity.getOrderAmount()).subtract(feeTypeBo.getNoDeductibleRefundAmount()));
            }
        }
/*        //订单支付金额(不包含免赔，押金)减去退款的金额
        feeTypeBo.setTotalAmount(feeTypeBo.getTotalAmount().subtract(feeTypeBo.getOrderRefundAmount()));
        //订单押金减去退款押金
        feeTypeBo.setDepositAmount(feeTypeBo.getDepositAmount().subtract(feeTypeBo.getDepositRefundAmount()));
        //订单免赔金额减去退款的免赔金额
        feeTypeBo.setNoDeductibleAmount(feeTypeBo.getNoDeductibleAmount().subtract(feeTypeBo.getDepositRefundAmount()));*/
        return feeTypeBo;
    }


    /**
     * 获取免赔金额
     *
     * @param data
     * @return
     */
    public static BigDecimal getDameSafeAmount(JSONObject data) {
        if (!data.isEmpty()) {
            Object paramJson = data.get(StatisticsStatusEnum.PARMAM_JSON);
            JSONObject jsonObject = JSONUtil.parseObj(paramJson);
            BigDecimal safeAmount = jsonObject.get(StatisticsStatusEnum.NO_DEDUCTIBLE_AMOUNT, BigDecimal.class);
            return safeAmount == null ? BigDecimal.ZERO : safeAmount;
        }
        return BigDecimal.ZERO;
    }

    /**
     * 创建默认对象
     *
     * @param date       统计日期
     * @param stateGroup 状态
     * @param companyMap 公司map
     * @param targetObj  目标对象
     * @param <T>        目标对象类型
     * @return
     */
    public static <T extends OrderReceivedStatisticsBase> T wrapStatisticsObject(Date date, String stateGroup, Map<Integer, String> companyMap, T targetObj) {
        LocalDate localDate = LocalDate.from(date.toInstant().atZone(ZoneId.systemDefault()));
        String year = String.valueOf(localDate.getYear());
        String month = String.format("%s%d", year, localDate.getMonthValue());
        String weekOfYear = String.format("%s%d", year, localDate.get(WeekFields.of(Locale.CHINESE).weekOfYear()));
        String[] status = stateGroup.split("-");
        targetObj.setCrtTime(new Date());
        targetObj.setCompanyId(Integer.valueOf(status[0]));
        String companyName = Objects.isNull(companyMap) ? COMPANY_DEFAULT : StringUtils.hasText(companyMap.get(targetObj.getCompanyId())) ? companyMap.get(targetObj.getCompanyId()) : COMPANY_DEFAULT;
        targetObj.setCompanyName(companyName);
        targetObj.setHasPay(Integer.valueOf(status[3]));
        targetObj.setOrderOrigin(Integer.valueOf(status[1]));
        targetObj.setPayWay(Integer.valueOf(status[2]));
        targetObj.setDate(date);
        targetObj.setYear(year);
        targetObj.setMonth(month);
        targetObj.setWeekOfYear(weekOfYear);
        targetObj.setExtraAmount(BigDecimal.ZERO);
        targetObj.setLateFeeAmount(BigDecimal.ZERO);
        targetObj.setTotalAmount(BigDecimal.ZERO);
        targetObj.setTotalQuantity(0);
        targetObj.setOrderRefundAmount(BigDecimal.ZERO);
        targetObj.setStateGroup(stateGroup);
        return targetObj;
    }


    /**
     * 批量插入数据  mysql sql语句默认不能超过4M
     *
     * @param orderReceivedStatistics
     */
    public static <T> void insertReceivedStatisticsBatch(List<T> orderReceivedStatistics, InsertListMapper<T> mapper) {
        int orderSize = orderReceivedStatistics.size();
        int sqlAdq = orderSize / StatisticsStatusEnum.DEFAULT_SQL_SIZE;
        int sqlMod = orderSize % StatisticsStatusEnum.DEFAULT_SQL_SIZE;
        sqlAdq = sqlMod == 0 ? sqlAdq : sqlAdq + 1;
        for (int i = 0; i < sqlAdq; i++) {
            int fromIndex = StatisticsStatusEnum.DEFAULT_SQL_SIZE * i;
            int toIndex = StatisticsStatusEnum.DEFAULT_SQL_SIZE * (i + 1);
            toIndex = toIndex > orderSize ? orderSize : toIndex;
            List<T> orderRentVehicleReceivedStatisticsList = orderReceivedStatistics.subList(fromIndex, toIndex);
            mapper.insertList(orderRentVehicleReceivedStatisticsList);
        }
    }
}
