
package com.tmerclub.cloud.delivery.manager;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.tmerclub.cloud.api.delivery.constant.TransportChargeType;
import com.tmerclub.cloud.api.delivery.constant.TransportFreeType;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.order.vo.*;
import com.tmerclub.cloud.common.product.constant.PreSaleType;
import com.tmerclub.cloud.common.product.constant.SupplierDeliveryType;
import com.tmerclub.cloud.common.util.Arith;
import com.tmerclub.cloud.delivery.service.TransportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

/**
 * @author tmerclub
 */
@Component
public class TransportManager {

    @Autowired
    private TransportService transportService;

    public long calculateTransfee(List<ShopCartItemVO> shopCartItems, UserDeliveryInfoVO userDeliveryInfo) {
        Map<Long, ShopTransFeeVO> shopIdWithShopTransFee = new HashMap<>(16);
        // 该店铺的供应商商品运费
        Map<Long, ShopTransFeeVO> supplierIdWithShopTransFeeMap = new HashMap<>(16);
        Map<Long, ShopTransFeeVO> preSaleTransFeeMap;
        if (MapUtil.isNotEmpty(userDeliveryInfo.getPreSaleTransFeeMap())) {
            preSaleTransFeeMap = userDeliveryInfo.getPreSaleTransFeeMap();
        } else {
            preSaleTransFeeMap = new HashMap<>(16);
        }


        // 商品的总运费
        long totalTransfee = 0L;

        // 1 去除没有店铺配送的订单和运费模板的订单
        List<ShopCartItemVO> transPortList = removeNotTransPort(shopCartItems);

        if (CollectionUtil.isEmpty(transPortList)) {
            return 0;
        }

        Long shopId = shopCartItems.get(0).getShopId();

        Map<Long, List<ShopCartItemVO>> shopCartItemsMap = transPortList.stream().collect(Collectors.groupingBy(ShopCartItemVO::getShopId));
        // 店铺id为key的购物项Map
        for (Map.Entry<Long, List<ShopCartItemVO>> shopKeyCartItemEntry : shopCartItemsMap.entrySet()) {
            List<ShopCartItemVO> shopCartItemList = shopKeyCartItemEntry.getValue();
            // 进行二次拆分下，如果是全款预售商品，则单独运费计算
            Map<String, List<ShopCartItemVO>> deliveryTemplateIdMap = new HashMap<>(16);
            Map<String, Long> deliveryAmountMap = new HashMap<>(16);
            for (ShopCartItemVO shopCartItemVO : shopCartItemList) {
                Long deliverytKey = shopCartItemVO.getShopId();
                // 如果不是预售商品，跟之前一样
                if (Objects.equals(shopCartItemVO.getPreSaleType(), PreSaleType.DISABLE.value())) {
                    List<ShopCartItemVO> deliveryShopCartItemList = new ArrayList<>(16);
                    if (Objects.equals(shopCartItemVO.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value())) {
                        deliverytKey = shopCartItemVO.getSupplierId();
                    }
                    deliveryShopCartItemList = deliveryTemplateIdMap.getOrDefault(deliverytKey + "_" + shopCartItemVO.getDeliveryTemplateId(), new ArrayList<>(Constant.INITIAL_CAPACITY));
                    deliveryShopCartItemList.add(shopCartItemVO);
                    String key;
                    // 因为可能存在多个固定运费的商品一起下单的情况,处理下key
                    if(Objects.equals(shopCartItemVO.getDeliveryTemplateId(),-1L)) {
                        key = deliverytKey + "_" + shopCartItemVO.getDeliveryTemplateId() + "_" + shopCartItemVO.getSpuId();
                    }else{
                        key = deliverytKey + "_" + shopCartItemVO.getDeliveryTemplateId();
                    }
                    deliveryTemplateIdMap.put(key, deliveryShopCartItemList);
                    deliveryAmountMap.put(key, shopCartItemVO.getDeliveryAmount());
                    continue;
                }
                // 如果是预售商品，则使用单独的key以便计算运费
                long key = -(shopCartItemVO.getDeliveryTemplateId() + shopCartItemVO.getSkuId());
                if (Objects.equals(shopCartItemVO.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value())) {
                    deliverytKey = shopCartItemVO.getSupplierId();
                }
                deliveryTemplateIdMap.put(deliverytKey + "_" + key,  Collections.singletonList(shopCartItemVO));
                deliveryAmountMap.put(deliverytKey + "_" + key, shopCartItemVO.getDeliveryAmount());
            }
            // 运费模板id为key的购物项Map
            for (Map.Entry<String, List<ShopCartItemVO>> templateKeyShopCartItemEntry : deliveryTemplateIdMap.entrySet()) {
                String[] keys = templateKeyShopCartItemEntry.getKey().split("_");
                Long deliveryTemplateId = Long.valueOf( keys[1]);
                Long spuId = 0L;
                if(Objects.equals(deliveryTemplateId, -1L) && keys.length > 2){
                    spuId = Long.valueOf(keys[2]);
                }
                Long deliveryAmount = deliveryAmountMap.get(templateKeyShopCartItemEntry.getKey());
                List<ShopCartItemVO> deliveryShopCartItems = templateKeyShopCartItemEntry.getValue();
                // 相同的运费模板，肯定供应商id也是一样的
                Long supplierId = deliveryShopCartItems.get(0).getSupplierId();
                Integer supplierDeliveryType = deliveryShopCartItems.get(0).getSupplierDeliveryType();
                // 运费模板的运费
                ShopTransFeeVO.DeliveryTemplateTransFee templateTransFee = this.repeatListTransfee(deliveryTemplateId, deliveryShopCartItems, userDeliveryInfo, deliveryAmount);
                Long transfee = templateTransFee.getTransfee();
                Long freeTransfee = templateTransFee.getFreeTransfee();
                totalTransfee += transfee;
                // 开始计算店铺的运费
                if (Objects.equals(supplierId, 0L) || Objects.equals(supplierId, -1L) || Objects.equals(supplierDeliveryType, SupplierDeliveryType.SHOP_DELIVERY.value())) {
                    handleShopTransFee(shopIdWithShopTransFee, preSaleTransFeeMap, shopId, deliveryTemplateId, deliveryShopCartItems, transfee, freeTransfee,spuId);
                    continue;
                }
                handleSupplierTransFee(supplierIdWithShopTransFeeMap, deliveryTemplateId, supplierId, transfee);
            }
        }
        Map<Long, ShopTransFeeVO> transFeeMap = userDeliveryInfo.getShopIdWithShopTransFee();
        if (Objects.nonNull(transFeeMap)) {
            shopIdWithShopTransFee.putAll(transFeeMap);
        }
        userDeliveryInfo.setShopIdWithShopTransFee(shopIdWithShopTransFee);
        if (Objects.isNull(userDeliveryInfo.getSupplierIdWithShopTransFeeMap())) {
            userDeliveryInfo.setSupplierIdWithShopTransFeeMap(new HashMap<>(supplierIdWithShopTransFeeMap.size()));
        }
        userDeliveryInfo.getSupplierIdWithShopTransFeeMap().put(shopId, supplierIdWithShopTransFeeMap);
        userDeliveryInfo.setPreSaleTransFeeMap(preSaleTransFeeMap);
        return totalTransfee;
    }

    private static void handleSupplierTransFee(Map<Long, ShopTransFeeVO> supplierIdWithShopTransFeeMap, Long deliveryTemplateId, Long supplierId, Long transfee) {
        // 开始计算供应商的运费
        ShopTransFeeVO supplierIdWithShopTransFee = supplierIdWithShopTransFeeMap.get(supplierId);
        // 如果商家没有计算运费就初始化运费
        if (Objects.isNull(supplierIdWithShopTransFee)) {
            supplierIdWithShopTransFee = new ShopTransFeeVO();
            supplierIdWithShopTransFee.setTransfee(transfee);
            supplierIdWithShopTransFee.setSupplierId(supplierId);
            supplierIdWithShopTransFee.setDeliveryTemplateId(deliveryTemplateId);
            // 没有减免运费的计算
            supplierIdWithShopTransFee.setFreeTransfee(0L);
            supplierIdWithShopTransFeeMap.put(supplierId, supplierIdWithShopTransFee);
        }
        // 累加非同一个运费模板的运费
        else if (!Objects.equals(supplierIdWithShopTransFee.getDeliveryTemplateId(), deliveryTemplateId)) {
            supplierIdWithShopTransFee.setTransfee(transfee + supplierIdWithShopTransFee.getTransfee());
            supplierIdWithShopTransFee.setSupplierId(supplierId);
        }
    }

    private static void handleShopTransFee(Map<Long, ShopTransFeeVO> shopIdWithShopTransFee, Map<Long, ShopTransFeeVO> preSaleTransFeeMap, Long shopId, Long deliveryTemplateId, List<ShopCartItemVO> deliveryShopCartItems, Long transfee, Long freeTransfee, Long spuId) {
        ShopTransFeeVO shopTransFee = shopIdWithShopTransFee.get(shopId);
        // 如果运费模板是-1且spuId不为0就表示为多个不同的固定运费的商品累加运费
        boolean addTransFee = !Objects.equals(spuId,0L) && Objects.equals(deliveryTemplateId,-1L);
        // 如果商家没有计算运费就初始化运费
        if (Objects.isNull(shopTransFee)) {
            shopTransFee = new ShopTransFeeVO();
            shopTransFee.setTransfee(transfee);
            shopTransFee.setDeliveryTemplateId(deliveryTemplateId);
            // 减免运费
            shopTransFee.setFreeTransfee(freeTransfee);
            shopIdWithShopTransFee.put(shopId, shopTransFee);
        }
        // 累加非同一个运费模板的运费
        else if (!Objects.equals(shopTransFee.getDeliveryTemplateId(), deliveryTemplateId) || addTransFee) {
            shopTransFee.setTransfee(transfee + shopTransFee.getTransfee());
            shopTransFee.setFreeTransfee(freeTransfee + shopTransFee.getFreeTransfee());
        }
        // 如果运费模板为负数则表示是单独的预售商品
        if (deliveryTemplateId < 0) {
            shopTransFee = new ShopTransFeeVO();
            shopTransFee.setTransfee(transfee);
            shopTransFee.setDeliveryTemplateId(deliveryShopCartItems.get(0).getDeliveryTemplateId());
            // 没有减免运费的计算
            shopTransFee.setFreeTransfee(0L);
            preSaleTransFeeMap.put(deliveryShopCartItems.get(0).getSkuId(), shopTransFee);
        }
    }

    /**
     * 去除没有店铺后的订单
     *
     * @param productItems 原用户所有的未处理订单
     * @return 有运费模板的订单
     */
    private List<ShopCartItemVO> removeNotTransPort(List<ShopCartItemVO> productItems) {
        // 保存去掉没有运费模板重复的订单
        List<ShopCartItemVO> resList = new ArrayList<>(Constant.INITIAL_CAPACITY);

        for (ShopCartItemVO productItem : productItems) {
            if (productItem.getDeliveryTemplateId() == null) {
                continue;
            }
            resList.add(productItem);
        }
        return resList;
    }


    /**
     * 计算出运费模板重复的订单运费
     *
     * @param productItems 运费模板是重复的订单
     * @param userDeliveryInfo
     * @return
     */
    private ShopTransFeeVO.DeliveryTemplateTransFee repeatListTransfee(Long deliveryTemplateId, List<ShopCartItemVO> productItems, UserDeliveryInfoVO userDeliveryInfo, Long deliveryAmount) {
        UserAddrVO userAddr = userDeliveryInfo.getUserAddr();

        // 商品运费模板 - 校验配送范围中存储的，优先从map中获取，没有再到mysql中查
        Map<Long, TransportVO> transportMap = userDeliveryInfo.getTransportMap();
        if (transportMap == null) {
            transportMap = new HashMap<>(Constant.INITIAL_CAPACITY);
        }

        ShopTransFeeVO.DeliveryTemplateTransFee templateTransFee = new ShopTransFeeVO.DeliveryTemplateTransFee();
        // 商品的件数 (总的件数)
        int prodCount = 0;
        // 商品的重量
        double totalWeight = 0.0;
        // 商品的体积
        double totalVolume = 0.0;
        // 商品总金额
        long totalAmount = 0;

        for (ShopCartItemVO productItem : productItems) {
            prodCount += productItem.getCount();
            double itemTotalWeight = productItem.getWeight() == null ? 0 : productItem.getWeight().doubleValue();
            totalWeight += Arith.mul(itemTotalWeight, productItem.getCount());
            double itemTotalVolume = productItem.getVolume() == null ? 0 : productItem.getVolume().doubleValue();
            totalVolume += Arith.mul(itemTotalVolume, productItem.getCount());
            totalAmount += productItem.getTotalAmount();
        }

        if (Objects.isNull(userAddr)) {
            templateTransFee.setTransfee(0L);
            templateTransFee.setFreeTransfee(0L);
            return templateTransFee;
        }
        // 用户所在区域的id
        Long areaId = userAddr.getAreaId();
        // 如果为负数则表示是单独的预售商品
        if (deliveryTemplateId < 0) {
            deliveryTemplateId = productItems.get(0).getDeliveryTemplateId();
        }
        if (deliveryTemplateId == -1L) {
            templateTransFee.setTransfee(prodCount * deliveryAmount);
            templateTransFee.setFreeTransfee(0L);
            return templateTransFee;
        }

        if (deliveryTemplateId == 0) {
            templateTransFee.setTransfee(0L);
            templateTransFee.setFreeTransfee(0L);
            return templateTransFee;
        }

        //找出该产品的运费项  运费模板
        TransportVO transport = transportMap.get(deliveryTemplateId);
        if (transport == null) {
            transport = transportService.getTransportAndAllItemsById(deliveryTemplateId);
            transportMap.put(deliveryTemplateId, transport);
        }
        //商家把运费模板删除
        if (Objects.isNull(transport)) {
            templateTransFee.setTransfee(0L);
            templateTransFee.setFreeTransfee(0L);
            return templateTransFee;
        }

        // 用于计算运费的件数
        double piece = 0.0;

        if (Objects.equals(TransportChargeType.COUNT.value(), transport.getChargeType())) {
            // 按件数计算运费
            piece = prodCount;
        } else if (Objects.equals(TransportChargeType.WEIGHT.value(), transport.getChargeType())) {
            // 按重量计算运费
            piece = totalWeight;
        } else if (Objects.equals(TransportChargeType.VOLUME.value(), transport.getChargeType())) {
            // 按体积计算运费
            piece = totalVolume;
        }
        // 运费模板运费
        long transfee = getTransfee(areaId, transport, piece);
        templateTransFee.setTransfee(transfee);
        templateTransFee.setFreeTransfee(0L);

        //如果有包邮的条件
        if (transport.getHasFreeCondition() == 1) {
            // 获取所有的包邮条件
            List<TransfeeFreeVO> transfeeFrees = transport.getTransFeeFrees();
            for (TransfeeFreeVO transfeeFree : transfeeFrees) {
                List<AreaVO> freeCityList = transfeeFree.getFreeCityList();
                for (AreaVO freeCity : freeCityList) {
                    if (!Objects.equals(freeCity.getAreaId(), areaId)) {
                        continue;
                    }
                    //包邮方式 （0 满x件/重量/体积包邮 1满金额包邮 2满x件/重量/体积且满金额包邮）
                    boolean isFree = (Objects.equals(transfeeFree.getFreeType(), TransportFreeType.COUNT.value()) && piece >= transfeeFree.getPiece()) ||
                            (Objects.equals(transfeeFree.getFreeType(), TransportFreeType.AMOUNT.value()) && totalAmount >= transfeeFree.getAmount()) ||
                            (Objects.equals(transfeeFree.getFreeType(), TransportFreeType.COUNT_AND_AMOUNT.value()) && piece >= transfeeFree.getPiece() && totalAmount >= transfeeFree.getAmount());
                    if (isFree) {
                        templateTransFee.setFreeTransfee(templateTransFee.getTransfee());
                        templateTransFee.setTransfee(0L);
                    }
                }
            }
        }
        return templateTransFee;
    }

    private long getTransfee(Long areaId, TransportVO transport, double piece) {
        TransfeeVO transfee = null;
        List<TransfeeVO> transfees = transport.getTransFees();
        for (TransfeeVO dbTransfee : transfees) {
            // 将该商品的运费设置为默认运费
            if (transfee == null && CollectionUtil.isEmpty(dbTransfee.getCityList())) {
                transfee = dbTransfee;
            }
            // 如果在运费模板中的城市找到该商品的运费，则将该商品由默认运费设置为该城市的运费
            boolean isContainer = dbTransfee.getCityList().stream().anyMatch(area -> area.getAreaId().equals(areaId));
            if (isContainer) {
                transfee = dbTransfee;
                break;
            }
            // 如果在运费模板中的城市找到该商品的运费，则退出整个循环
            if (transfee != null && CollectionUtil.isNotEmpty(transfee.getCityList())) {
                break;
            }
        }

        // 如果无法获取到任何运费相关信息，则返回0运费
        if (transfee == null) {
            return 0L;
        }
        // 产品的运费
        long fee = transfee.getFirstFee();
        // 如果件数大于首件数量，则开始计算超出的运费
        if (piece > transfee.getFirstPiece()) {
            // 续件数量
            double prodContinuousPiece = Arith.sub(piece, transfee.getFirstPiece());
            // 续件数量的倍数，向上取整
            int mulNumber = (int) Math.ceil(Arith.div(prodContinuousPiece, transfee.getContinuousPiece()));
            // 续件数量运费
            long continuousFee = mulNumber * transfee.getContinuousFee();
            fee += continuousFee;
        }
        return fee;
    }

}
