package cn.freemud.demo.service.impl;

import cn.freemud.demo.entities.bo.goods.*;
import cn.freemud.demo.entities.bo.goods.update.UpdateAddGoodsBO;
import cn.freemud.demo.entities.bo.promotion.ActivityBO;
import cn.freemud.demo.entities.bo.promotion.GetActivityBO;
import cn.freemud.demo.manager.product.ProductManager;
import cn.freemud.demo.manager.promotion.PromotionManager;
import cn.freemud.demo.service.DistributeService;
import cn.freemud.demo.utils.CommonUtils;
import cn.freemud.entities.dto.CheckSpqInfoResponseDto;
import cn.freemud.entities.dto.activity.ActivityQueryDto;
import cn.freemud.entities.dto.calculate.CalculationSharingDiscountResponseDto;
import cn.freemud.entities.vo.CartGoods;
import cn.freemud.enums.ActivityTypeEnum;
import cn.freemud.enums.CalculationGoodsType;
import cn.freemud.enums.GoodsTypeEnum;
import com.freemud.sdk.api.assortment.shoppingcart.constant.CommonsConstant;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service
public class DistributeServiceImpl implements DistributeService {


    @Autowired
    private PromotionManager promotionManager;

    @Autowired
    private ProductManager productManager;



    @Override
    public ShoppingGoodsAmountBO initShoppingCart(CalculationDiscountBO.CalculationDiscountResult discountResult, List<CartGoods> cartGoodsList, String couponCode) {
        ShoppingGoodsAmountBO shoppingGoodsAmountBO = new ShoppingGoodsAmountBO();

        /**
         * 使用促销算价赋值行记录
         */
        List<CalculationDiscountBO.CalculationDiscountResult.Goods> goods = null;
        if (discountResult != null && CollectionUtils.isNotEmpty(discountResult.getGoods())) {
            goods = discountResult.getGoods();
        }
        long totalOriginalAmount = 0L, totalAmount = 0L, totalPackageAmount = 0L;
        long originalAmount = 0L, amount = 0L, packageAmount = 0L;
        for (CartGoods cartGoods : cartGoodsList) {

            originalAmount = 0L;amount = 0L;packageAmount = 0L;
            if (CommonUtils.isProductCoupon(cartGoods.getCouponCode(), cartGoods.getCartGoodsUid())){
                Map<String, CheckSpqInfoResponseDto> validCouponMap = discountResult.getValidCouponMap();
                if (validCouponMap != null && validCouponMap.get(cartGoods.getSpuId()) != null){
                    cartGoods.setSpuId(validCouponMap.get(cartGoods.getSpuId()).getSpuId());
                }
            }

            //原价行记录
            originalAmount = cartGoods.getOriginalPrice() * cartGoods.getQty();
            cartGoods.setOriginalAmount(originalAmount);

            this.rowRealAmount(goods, cartGoods, couponCode);
            //成交价行记录
            amount = cartGoods.getAmount();
            totalAmount += amount;
            totalOriginalAmount += cartGoods.getOriginalAmount();

            //包装费行记录
            packageAmount = cartGoods.getPackPrice() * cartGoods.getQty();
            cartGoods.setPackPrice(packageAmount);
            totalPackageAmount += packageAmount;
        }
        shoppingGoodsAmountBO.setOriginalTotalAmount(discountResult == null ? totalOriginalAmount : discountResult.getOriginalTotalAmount());
        shoppingGoodsAmountBO.setTotalAmount(discountResult == null ? totalAmount : discountResult.getTotalAmount());
        shoppingGoodsAmountBO.setNewPackAmount(totalPackageAmount);
        shoppingGoodsAmountBO.setTotalDiscountAmount(discountResult == null ? 0L : discountResult.getTotalDiscountAmount());
        return shoppingGoodsAmountBO;
    }

    @Override
    public FullReductionBO fullReduction(BaseBo baseRequestDTO, CalculationDiscountBO.CalculationDiscountResult discountResult, List<CartGoods> cartGoodsList, ActivityQueryDto activityQueryDto) {
        FullReductionBO fullReduction = new FullReductionBO();


        List<ActivityTypeEnum> activityTypeEnums = new LinkedList<>();
        /**
         * 每满减 TYPE_11\ 阶梯满减 TYPE_12
         */
        activityTypeEnums.add(ActivityTypeEnum.TYPE_11);
        activityTypeEnums.add(ActivityTypeEnum.TYPE_12);
        activityTypeEnums.add(ActivityTypeEnum.TYPE_3);
        activityTypeEnums.add(ActivityTypeEnum.TYPE_31);
        activityTypeEnums.add(ActivityTypeEnum.TYPE_230);

        GetActivityBO getActivityBO = new GetActivityBO();
        getActivityBO.setActivityTypeEnums(activityTypeEnums);
        getActivityBO.setActivityQueryDto(activityQueryDto);

        ActivityBO activityBO = promotionManager.queryActivityByType(getActivityBO, baseRequestDTO.getManagerService().getPromotionService());
        fullReduction.setActivityBO(activityBO);
        if (discountResult == null){
            return fullReduction;
        }

        List<CalculationDiscountBO.CalculationDiscountResult.Discount> discounts = discountResult.getDiscounts();
        List<CalculationDiscountBO.CalculationDiscountResult.Discount> fullDiscountsList = discounts
                .stream()
                .filter(d -> ActivityTypeEnum.TYPE_11.getCode().equals(d.getType()) || ActivityTypeEnum.TYPE_12.getCode().equals(d.getType()))
                .collect(Collectors.toList());
        /**
         * 设置到响应中 总的满减优惠金额
         */
        if (CollectionUtils.isNotEmpty(fullDiscountsList)) {

            long fullDiscount = 0L;
            fullDiscount = fullDiscountsList.stream().filter(d -> d.getDiscount() != null).mapToLong(CalculationDiscountBO.CalculationDiscountResult.Discount::getDiscount).sum();
            fullReduction.setDiscount(fullDiscount);
        }

        List<Integer> typeEnums = activityTypeEnums.stream().map(ActivityTypeEnum::getCode).collect(Collectors.toList());
        /**
         * 还原满减折扣到行记录上
         */
        Map<String, CalculationDiscountBO.CalculationDiscountResult.Goods> map = discountResult.getGoods()
                .stream()
                .filter(g -> null != g.getCartGoodsUid())
                .collect(Collectors.toMap(CalculationDiscountBO.CalculationDiscountResult.Goods::getCartGoodsUid, Function.identity(), (k1, k2) -> k1));

        long full = 0L;
        long sum = 0L;
        for (CartGoods cart : cartGoodsList) {
            CalculationDiscountBO.CalculationDiscountResult.Goods discountMap = map.get(cart.getCartGoodsUid());
            full = 0L;
            sum = 0L;
            if (null==discountMap) continue;
            if (CollectionUtils.isNotEmpty(discountMap.getDiscounts())) {
                sum = discountMap.getDiscounts()
                        .stream()
                        .filter(d -> typeEnums.contains(d.getType()) && !d.getType().equals(ActivityTypeEnum.TYPE_230.getCode()))
                        .mapToLong(CalculationDiscountBO.CalculationDiscountResult.Goods.GoodsDiscount::getDiscount)
                        .sum();
                cart.setAmount(cart.getAmount() + sum);
            }
            //小料
            if (CollectionUtils.isNotEmpty(cart.getProductMaterialList())) {
                List<CalculationDiscountBO.CalculationDiscountResult.Goods.SmallMaterial> materialDiscount = discountMap.getSmallMaterial();
                HashMap<String, Long> mDiscount = drawnFullDiscount(materialDiscount, typeEnums, 1);
                if (!mDiscount.isEmpty()) {
                    for (CartGoods.MaterialGoods mt : cart.getProductMaterialList()) {
                        Long md = mDiscount.get(mt.getSpuId());
                        if (md != null) {
                            mt.setAmount(mt.getAmount() + md);
                        }
                    }
                }
            }
            //可选商品
            if (CollectionUtils.isNotEmpty(cart.getProductGroupList())) {
                List<CalculationDiscountBO.CalculationDiscountResult.Goods.SmallMaterial> materialDiscount = discountMap.getSmallMaterial();
                HashMap<String, Long> mDiscount = drawnFullDiscount(materialDiscount, typeEnums, 2);
                if (!mDiscount.isEmpty()) {
                    for (CartGoods.ComboxGoods com : cart.getProductGroupList()) {
                        Long md = mDiscount.get(com.getGoodsId());
                        if (md != null) {
                            com.setAmount(com.getAmount() + md);
                            cart.setAmount(cart.getAmount() + md);
                        }
                    }
                }
            }
        }
        return fullReduction;
    }

    @Override
    public List<CartGoods> buyGift(CalculationDiscountBO.CalculationDiscountResult result, List<CartGoods> cartGoods, ActivityQueryDto activityQueryDto, BaseBo baseRequestDTO) {
        if (result == null || CollectionUtils.isEmpty(result.getGoods())) {
            return new ArrayList<>();
        }
        String menuType = baseRequestDTO == null ? null : baseRequestDTO.getMenuType();
        List<ProductBO> products = this.drawGiftInfo(result, baseRequestDTO);
        return this.gifAddCart(products, result);
    }

    @Override
    public List<ChooseGoodsBO> bugGiftAndSendCup(CalculationDiscountBO.CalculationDiscountResult result, List<CartGoods> cartGoods, ActivityQueryDto activityQueryDto, BaseBo baseRequestDTO) {
        if(result == null){
            return null;
        }

        //  过略出来买一赠一寄杯活动，没有直接返回
        List<CalculationDiscountBO.CalculationDiscountResult.Discount> discounts = result.getDiscounts();
        if(null == discounts || discounts.isEmpty()){
            return null;
        }
        List<CalculationDiscountBO.CalculationDiscountResult.Discount> buyOneGiveOneSendDiscounts = discounts
                .stream()
                .filter(discount -> ObjectUtils.equals(discount.getType(),ActivityTypeEnum.TYPE_63.getCode()))
                .collect(Collectors.toList());
        if(null == buyOneGiveOneSendDiscounts || buyOneGiveOneSendDiscounts.isEmpty()){
            return null;
        }

        if (buyOneGiveOneSendDiscounts == null || CollectionUtils.isEmpty(result.getGoods())) {
            return null;
        }
/*        String menuType = shoppingCartInfoRequestVo == null ? null : shoppingCartInfoRequestVo.getMenuType();
        // 构建赠品detail
        List<ProductBeanDTO> beanDTOList = this.drawGiftInfo(discountResult, activityQueryDto, menuType);
        this.setCartGoods(discountResult, cartGoodsList, beanDTOList);*/

        // 设置用户可以选择的寄送商品券码
        return this.buildSendGoods(result);
    }



    private void rowRealAmount(List<CalculationDiscountBO.CalculationDiscountResult.Goods> goods, CartGoods cartGoods, String couponCode) {

        CalculationDiscountBO.CalculationDiscountResult.Goods find = goods
                .stream().filter((k) -> k.getCartGoodsUid().equals(cartGoods.getCartGoodsUid()))
                .findFirst()
                .get();

        if (find == null) return;
        cartGoods.setAmount(find.getRealAmount());
        //cartGoods.setOriginalAmount(find.getOriginalPrice());
        cartGoods.setCurrentCouponDiscount(0);
        if (CollectionUtils.isNotEmpty(find.getDiscounts())){
            CalculationDiscountBO.CalculationDiscountResult.Goods.GoodsDiscount goodsDiscount = find.getDiscounts().stream()
                    .filter(p -> p.getActivityCode().equals(couponCode)).findFirst().orElse(null);
            if (goodsDiscount != null){
                cartGoods.setCurrentCouponDiscount(goodsDiscount.getDiscount() == null ? 0 : goodsDiscount.getDiscount().intValue());
            }
        }

        /**
         * 套餐的原价
         */
        Long originPrice = 0L;
        if (CollectionUtils.isNotEmpty(cartGoods.getProductComboList())) {
            for (CartGoods.ComboxGoods com : cartGoods.getProductComboList()) {
                originPrice += com.getFinalPrice() * cartGoods.getQty() * com.getQty();
            }
        }
        /**
         * 可选搭配
         */
        if (CollectionUtils.isNotEmpty(cartGoods.getProductGroupList())) {
            Integer type2 = 2;
            Map<String, CalculationDiscountBO.CalculationDiscountResult.Goods.SmallMaterial> gChoices = find.getSmallMaterial()
                    .stream().filter(d -> type2.equals(d.getType()))
                    .collect(Collectors.toMap(CalculationDiscountBO.CalculationDiscountResult.Goods.SmallMaterial::getGoodsId, Function.identity(), (k1, k2) -> k1));
            long amount = 0L;

            //可选搭配
            for (CartGoods.ComboxGoods choice : cartGoods.getProductGroupList()) {
                CalculationDiscountBO.CalculationDiscountResult.Goods.SmallMaterial mt = gChoices.get(choice.getGoodsId());
                if (mt == null) {
                    amount += choice.getAmount() * choice.getQty();
                }
                else {
                    amount += mt.getRealAmount();
                    choice.setCurrentCouponDiscount(0);
                    if (CollectionUtils.isNotEmpty(mt.getDiscounts())){
                        CalculationDiscountBO.CalculationDiscountResult.Goods.GoodsDiscount goodsDiscount = mt.getDiscounts().stream()
                                .filter(p -> p.getActivityCode().equals(couponCode)).findFirst().orElse(null);
                        if (goodsDiscount != null){
                            choice.setCurrentCouponDiscount(goodsDiscount.getDiscount() == null ? 0 : goodsDiscount.getDiscount().intValue());
                        }
                    }
                    choice.setAmount(mt.getRealAmount().longValue());
                }
                originPrice += choice.getFinalPrice() * choice.getQty()*cartGoods.getQty();
            }
            cartGoods.setAmount(cartGoods.getAmount() + amount);
        }
        /**
         * 小料
         */
        if (CollectionUtils.isNotEmpty(cartGoods.getProductMaterialList())) {
            Integer type1 = 1;
            Map<String, CalculationDiscountBO.CalculationDiscountResult.Goods.SmallMaterial> sChoices = find.getSmallMaterial()
                    .stream().filter(d -> type1.equals(d.getType()))
                    .collect(Collectors.toMap(CalculationDiscountBO.CalculationDiscountResult.Goods.SmallMaterial::getGoodsId, Function.identity(), (k1, k2) -> k1));

            for (CartGoods.MaterialGoods mg : cartGoods.getProductMaterialList()) {
                CalculationDiscountBO.CalculationDiscountResult.Goods.SmallMaterial sm = sChoices.get(mg.getSpuId());
                if (sm != null) {
                    mg.setCurrentCouponDiscount(0);
                    if (CollectionUtils.isNotEmpty(sm.getDiscounts())){
                        CalculationDiscountBO.CalculationDiscountResult.Goods.GoodsDiscount goodsDiscount = sm.getDiscounts().stream()
                                .filter(p -> p.getActivityCode().equals(couponCode)).findFirst().orElse(null);
                        if (goodsDiscount != null){
                            mg.setCurrentCouponDiscount(goodsDiscount.getDiscount() == null ? 0 : goodsDiscount.getDiscount().intValue());
                        }
                    }
                    mg.setAmount(sm.getRealAmount().longValue());
                }
                mg.setQty(mg.getQty() * cartGoods.getQty());
                mg.setOriginalAmount(mg.getFinalPrice() * mg.getQty());
            }
        }
        if (GoodsTypeEnum.SET_MEAL_GOODS.getGoodsType().equals(cartGoods.getGoodsType())) {
            cartGoods.setOriginalAmount(originPrice);
        }

    }

    /**
     * 抽取满减的折扣金额 按货对应
     * 小料和可选搭配
     */
    private HashMap<String, Long> drawnFullDiscount(List<CalculationDiscountBO.CalculationDiscountResult.Goods.SmallMaterial> materialDiscount, List<Integer> typeEnums, Integer type) {
        HashMap<String, Long> hashMap = new HashMap<>();
        if (CollectionUtils.isEmpty(materialDiscount)) return hashMap;
        for (CalculationDiscountBO.CalculationDiscountResult.Goods.SmallMaterial smallMaterial : materialDiscount) {
            if (CollectionUtils.isEmpty(smallMaterial.getDiscounts()) && !type.equals(smallMaterial.getType()))
                continue;
            for (CalculationDiscountBO.CalculationDiscountResult.Goods.GoodsDiscount discount : smallMaterial.getDiscounts()) {
                if (typeEnums.contains(discount.getType())) {
                    Long aLong = hashMap.get(discount.getGoodsId()) == null ? 0L : hashMap.get(discount.getGoodsId());
                    hashMap.put(discount.getGoodsId(), aLong + discount.getDiscount());
                }
            }
        }
        return hashMap;
    }

    /**
     * 赠品detail
     *
     * @param discountResult
     */
    private List<ProductBO> drawGiftInfo(CalculationDiscountBO.CalculationDiscountResult discountResult, BaseBo baseRequestDTO) {

        List<ProductBO> productBeanList = new ArrayList<>();
        List<String> gifts = this.getProductIdsForGift(discountResult);

        if (CollectionUtils.isEmpty(gifts)) return productBeanList;

        GetProductBO getProductBO = new GetProductBO();
        getProductBO.setGoodsId(gifts);
        getProductBO.setPartnerId(baseRequestDTO.getPartnerId());
        getProductBO.setStoreId(baseRequestDTO.getShopId());
        getProductBO.setMenuType(baseRequestDTO.getMenuType());
        List<ProductBO> productsInfo = productManager.getProductsInfo(getProductBO, baseRequestDTO.getManagerService().getProductService());

        return productsInfo;
    }

    /**
     * 抽取赠品
     * goodsId->goods
     *
     * @param discountResult
     * @return
     */
    private List<String> getProductIdsForGift(CalculationDiscountBO.CalculationDiscountResult discountResult) {

        List<String> gifts = new ArrayList<>();
        if (CollectionUtils.isEmpty(discountResult.getGoods())) {
            return gifts;
        }
        gifts = discountResult.getGoods()
                .stream()
                .filter(d -> CalculationGoodsType.TYPE_1.getType().equals(d.getCartGoodType()))
                .map(CalculationDiscountBO.CalculationDiscountResult.Goods::getGoodsId)
                .collect(Collectors.toList());
        return gifts;
    }


    private List<CartGoods> gifAddCart(List<ProductBO> products , CalculationDiscountBO.CalculationDiscountResult discountResult) {
        List<CartGoods> giftGoods = new ArrayList<>();
        Map<String, CalculationDiscountBO.CalculationDiscountResult.Goods> discountForGift = this.getDiscountForGift(discountResult);

        for (ProductBO product : products) {
            String k = product.getSpuId();
            CalculationDiscountBO.CalculationDiscountResult.Goods goods = discountForGift.get(k);
            CalculationDiscountBO.CalculationDiscountResult.Goods.GoodsDiscount discount = goods.getDiscounts()
                    .stream()
                    .filter(g -> ActivityTypeEnum.TYPE_63.getCode().equals(g.getType()) ||ActivityTypeEnum.TYPE_62.getCode().equals(g.getType()) || ActivityTypeEnum.TYPE_61.getCode().equals(g.getType())
                            || ActivityTypeEnum.TYPE_230.getCode().equals(g.getType()))
                    .findFirst()
                    .get();
            CartGoods cartGood = new CartGoods();
            cartGood.setGoodsId(goods.getGoodsId());
            cartGood.setGoodsType(1);
            cartGood.setSpuId(goods.getGoodsId());
            cartGood.setSkuId(goods.getGoodsId());
            cartGood.setOriginalPrice(product.getFinalPrice());
            cartGood.setPackPrice(product.getPackPrice());
            cartGood.setOriginalAmount(goods.getOriginalPrice() * goods.getGoodsQuantity());
            cartGood.setAmount(goods.getRealAmount());
            cartGood.setName(product.getName());
            cartGood.setSpuName(product.getName());
            cartGood.setCategoryName(product.getName());
            cartGood.setPic(product.getPicture());
            cartGood.setSkuName(product.getName());
            cartGood.setActivityType(discount.getType());
            cartGood.setStockLimit(ObjectUtils.equals(1, product.getStockLimit()));
            cartGood.setCustomerCode(product.getCustomerCode());
            cartGood.setUnit(product.getUnit());
            cartGood.setWeight(product.getWeight());
            cartGood.setQty(goods.getGoodsQuantity());
            cartGood.setClassificationId(product.getCategory());
            cartGood.setClassificationName(product.getCategoryName());
            // nodeId标识activeCode,用于计算均摊时每个商品在每个活动上均摊金额
            cartGood.setNodeId(discount.getActivityCode());
            giftGoods.add(cartGood);
        }
        return giftGoods;
    }

    private Map<String, CalculationDiscountBO.CalculationDiscountResult.Goods> getDiscountForGift(CalculationDiscountBO.CalculationDiscountResult discountResult) {

        Map<String, CalculationDiscountBO.CalculationDiscountResult.Goods> gifts = discountResult.getGoods()
                .stream()
                .filter(d -> CalculationGoodsType.TYPE_1.getType().equals(d.getCartGoodType()))
                .collect(Collectors.toMap(CalculationDiscountBO.CalculationDiscountResult.Goods::getGoodsId, Function.identity(), (k1, k2) -> k1));
        return gifts;
    }



    /**
     * 构建用户可以商品券信息
     *
     * @param discountResult
     * @return
     */
    private List<ChooseGoodsBO> buildSendGoods(CalculationDiscountBO.CalculationDiscountResult discountResult) {

        // 赠送、换购商品信息集合
        List<CalculationDiscountBO.CalculationDiscountResult.SendActivity> sendGoods = discountResult.getSendGoods();
        if (sendGoods == null || sendGoods.isEmpty()) {
            return null;
        }

        // 抽取买一赠一寄件活动送的商品
        List<CalculationDiscountBO.CalculationDiscountResult.SendActivity> buyOneGiveOneSendGoods = sendGoods
                .stream()
                .filter(sendGood -> ObjectUtils.equals(sendGood.getActivityType(), ActivityTypeEnum.TYPE_63.getCode()))
                .collect(Collectors.toList());

        if (null == buyOneGiveOneSendGoods || buyOneGiveOneSendGoods.isEmpty()) {
            return null;
        }

        List<ChooseGoodsBO> chooseGoods =  new ArrayList<>() ;
        buyOneGiveOneSendGoods.forEach(sendActivity -> {

            // 这个是真正的送的券
            List<CalculationDiscountBO.CalculationDiscountResult.SendActivity.SendGoods> innerSendGoods = sendActivity.getSendGoods();
            if (innerSendGoods == null || innerSendGoods.isEmpty()) {
                return;
            }

            innerSendGoods.forEach(innerSendGood -> {
                ChooseGoodsBO chooseGood = new ChooseGoodsBO();
                chooseGood.setActiveCode(sendActivity.getActivityCode());
                chooseGood.setActiveType(sendActivity.getActivityType());
                chooseGood.setGoodsId(innerSendGood.getGoodsId());
                chooseGood.setQty(innerSendGood.getSendNumber());
                chooseGood.setCouponQty(1);
                chooseGood.setCartGoodsUid(innerSendGood.getOriginalGoodsUid());
                chooseGood.setCouponCode(innerSendGood.getSendCouponCode());
                chooseGood.setCouponName(innerSendGood.getSendCouponName());
                chooseGood.setSendCoupon(innerSendGood.getSendCoupon());
                chooseGood.setGoodsName(innerSendGood.getGoodsName());
                chooseGoods.add(chooseGood);
            });

        });
        return chooseGoods;
    }

}
