package cn.freemud.adapter;

import cn.freemud.entities.dto.ActivityCalculationDiscountResponseDto;
import cn.freemud.entities.dto.promotion.*;
import cn.freemud.entities.dto.shoppingCart.ActivityDiscountsDto;
import cn.freemud.entities.dto.shoppingCart.ShoppingCartGoodsDto;
import cn.freemud.entities.vo.ActivityDiscountsVo;
import cn.freemud.enums.ActivityChannelEnum;
import cn.freemud.enums.ActivityTypeEnum;
import cn.freemud.enums.CreateOrderType;
import com.freemud.application.sdk.api.ordercenter.enums.ProductTypeEnum;
import com.freemud.application.sdk.api.promotioncenter.dto.promotion.ApportionGoodsDTO;
import com.freemud.application.sdk.api.promotioncenter.request.promotion.CalculationDiscountRequest;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.ObjectUtils;

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

/**
 * All rights Reserved, Designed By www.freemud.com
 *
 * @version V1.0
 * @Title:
 * @Package: com.freemud.sdk.api.assortment.promotion.adapter
 * @Descripttion:
 * @author: shuhu.hou
 * @date: 2019/9/9
 * @Copyright: 2017 www.freemud.cn Inc. All rights reserved.
 * 注意：本内容仅限于上海非码科技内部传阅，禁止外泄以及用于其他的商业目.
 */
public class PromotionAdapter {

    public static ShoppingCartGoodsResponse.CartGoodsDetailDto convertCartGoods2DetailGoods(OrderBeanRequest.ProductBean orderProductBean, int originalDiscountAmount, List<CalculationApportionGoodsDto> apportionGoodsList, Map<String, String> duplicateGoodsMap,Boolean isApportion) {
        Integer totalDiscount = originalDiscountAmount;
        List<CalculationApportionGoodsDto> apportionGoodsByGoodsId = apportionGoodsList.stream().filter(a -> ObjectUtils.equals(orderProductBean.getProductId(), a.getGoodsId())).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(apportionGoodsByGoodsId)) {
            Long discountPrice = 0L;
            int goodsTotalQty = apportionGoodsByGoodsId.stream().mapToInt(CalculationApportionGoodsDto::getGoodsQuantity).sum();
            for(CalculationApportionGoodsDto apportionGoods : apportionGoodsByGoodsId) {
                if (isApportion) {
                    discountPrice += apportionGoods.getApportionDetails().stream().filter(d -> ObjectUtils.notEqual(ActivityTypeEnum.TYPE_32.getCode(), d.getActivityType())
                            && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_104.getCode(), d.getActivityType()) && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_2.getCode(), d.getActivityType())
                    ).mapToLong(t -> t.getActivityApportionAmount() * apportionGoods.getGoodsQuantity()).sum() * orderProductBean.getNumber() / goodsTotalQty;
                }else {
                    discountPrice += apportionGoods.getApportionDetails().stream().filter(d -> ObjectUtils.notEqual(ActivityTypeEnum.TYPE_32.getCode(), d.getActivityType())
                            && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_104.getCode(), d.getActivityType()) && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_2.getCode(), d.getActivityType())
                            && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_12.getCode(), d.getActivityType()) && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_11.getCode(), d.getActivityType())
                            && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_3.getCode(), d.getActivityType())
                    ).mapToLong(t -> t.getActivityApportionAmount() * apportionGoods.getGoodsQuantity()).sum() * orderProductBean.getNumber() / goodsTotalQty;
                }
            }
            String currentGoodsIdMap = duplicateGoodsMap.get(orderProductBean.getProductId());
            if(currentGoodsIdMap != null) {
                String[] value = currentGoodsIdMap.split(",");
                if (Integer.parseInt(value[0]) > 1) {
                    int totalDiscountPrice = Integer.parseInt(value[1]) + discountPrice.intValue();
                    int index = Integer.parseInt(value[0]) - 1;
                    duplicateGoodsMap.put(orderProductBean.getProductId(), String.format("%s,%s", index, totalDiscountPrice));
                } else {
                    //最后一行
                    Long totalDiscountAmount = 0L;
                    for (CalculationApportionGoodsDto apportionGoods : apportionGoodsByGoodsId) {
                        if (isApportion) {
                            totalDiscountAmount += apportionGoods.getApportionDetails().stream().filter(d -> ObjectUtils.notEqual(ActivityTypeEnum.TYPE_32.getCode(), d.getActivityType())
                                    && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_104.getCode(), d.getActivityType()) && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_2.getCode(), d.getActivityType())
                            ).mapToLong(t -> t.getActivityApportionAmount() * apportionGoods.getGoodsQuantity()).sum();
                        }else {
                            totalDiscountAmount += apportionGoods.getApportionDetails().stream().filter(d -> ObjectUtils.notEqual(ActivityTypeEnum.TYPE_32.getCode(), d.getActivityType())
                                    && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_104.getCode(), d.getActivityType()) && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_104.getCode(), d.getActivityType())
                                    && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_12.getCode(), d.getActivityType()) && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_11.getCode(), d.getActivityType())
                                    && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_3.getCode(), d.getActivityType())
                            ).mapToLong(t -> t.getActivityApportionAmount() * apportionGoods.getGoodsQuantity()).sum();
                        }
                    }
                    //折扣为：总折扣金额-已折扣金额
                    discountPrice = totalDiscountAmount - Integer.parseInt(value[1]);
                }
            }
            totalDiscount += discountPrice.intValue();
        }
        return convertCartGoods2DetailGoodsCommon(orderProductBean, totalDiscount, apportionGoodsByGoodsId, isApportion);
    }

    public static List<ShoppingCartGoodsResponse.CartGoodsDetailDto> convertCartGoods2DetailGoods(List<OrderBeanRequest.ProductBean> comboFixedProductList, Long totalDiscountAmount) {
        List<ShoppingCartGoodsResponse.CartGoodsDetailDto> result = new ArrayList<>();
        if (CollectionUtils.isEmpty(comboFixedProductList)) {
            return result;
        }
        Long totalOriginalPrice = comboFixedProductList.stream().mapToLong(t -> {
            if (Objects.equals(t.getProductType(), ProductTypeEnum.WEIGHT_PRODUCT.getCode())) {
                return new BigDecimal(t.getPrice() + "").multiply(t.getWeight()).longValue();
            }
            return t.getPrice() * t.getNumber();
        }).sum();

        int size = comboFixedProductList.size();
        Integer tempDiscount = 0;
        for (OrderBeanRequest.ProductBean comboProduct : comboFixedProductList) {
            //获取当前套餐可选或固定商品的均摊价格
            if (size-- == 1) {
                result.add(convertCartGoods2DetailGoodsCommon(comboProduct, totalDiscountAmount.intValue() - tempDiscount, null,true));
            } else {
                Long currentDiscountAmount = (comboProduct.getNumber() * comboProduct.getPrice() * totalDiscountAmount) / totalOriginalPrice;
                if(Objects.equals(comboProduct.getProductType(), ProductTypeEnum.WEIGHT_PRODUCT.getCode())) {
                    currentDiscountAmount = new BigDecimal(comboProduct.getPrice()+"").multiply(comboProduct.getWeight()).longValue() * totalDiscountAmount / totalOriginalPrice;
                }
                tempDiscount += currentDiscountAmount.intValue();
                result.add(convertCartGoods2DetailGoodsCommon(comboProduct, currentDiscountAmount.intValue(), null,true));
            }
        }
        return result;
    }

    public static ShoppingCartGoodsResponse.CartGoodsDetailDto convertCartGoods2DetailGoodsCommon(OrderBeanRequest.ProductBean orderProductBean, Integer totalDiscountAmount, List<CalculationApportionGoodsDto> apportionGoodsList,Boolean isApportion) {
        ShoppingCartGoodsResponse.CartGoodsDetailDto cartGoodsDetailDto = new ShoppingCartGoodsResponse.CartGoodsDetailDto();
        cartGoodsDetailDto.setProductId(orderProductBean.getProductId());
        cartGoodsDetailDto.setOriginalPrice(orderProductBean.getPrice());
        cartGoodsDetailDto.setQty(orderProductBean.getNumber());
        cartGoodsDetailDto.setWeight(orderProductBean.getWeight());
        cartGoodsDetailDto.setTotalDiscountAmount(totalDiscountAmount);
        cartGoodsDetailDto.setSequence(orderProductBean.getSequence());
        cartGoodsDetailDto.setProductType(orderProductBean.getProductType());
        cartGoodsDetailDto.setActivityDiscountsDtos(new ArrayList<>());
        if(Objects.equals(orderProductBean.getProductType(), ProductTypeEnum.WEIGHT_PRODUCT.getCode())) {
            cartGoodsDetailDto.setOriginalTotalAmount(new BigDecimal(orderProductBean.getPrice()+"").multiply(orderProductBean.getWeight()).longValue());
        } else {
            cartGoodsDetailDto.setOriginalTotalAmount(orderProductBean.getNumber() * orderProductBean.getPrice());
        }
        cartGoodsDetailDto.setSettlementPrice(cartGoodsDetailDto.getOriginalTotalAmount() - totalDiscountAmount);
        if(Objects.equals(orderProductBean.getProductType(), ProductTypeEnum.WEIGHT_PRODUCT.getCode())) {
            cartGoodsDetailDto.setFinalPrice(cartGoodsDetailDto.getSettlementPrice());
        } else {
            cartGoodsDetailDto.setFinalPrice(cartGoodsDetailDto.getSettlementPrice() / orderProductBean.getNumber());
        }
        if(CollectionUtils.isNotEmpty(apportionGoodsList)) {
            List<CalculationApportionGoodsDto> apportionGoodsByGoodsId = apportionGoodsList.stream().filter(a -> ObjectUtils.equals(orderProductBean.getProductId(), a.getGoodsId())).collect(Collectors.toList());
            setActivityDiscounts(apportionGoodsByGoodsId, cartGoodsDetailDto,isApportion);
        }
        return cartGoodsDetailDto;
    }

    public static void updateCartGoodsDetail(ShoppingCartGoodsResponse.CartGoodsDetailDto cartGoodsDetailDto, int totalDiscountAmount) {
        cartGoodsDetailDto.setTotalDiscountAmount(totalDiscountAmount);
        cartGoodsDetailDto.setSettlementPrice(cartGoodsDetailDto.getOriginalTotalAmount() - totalDiscountAmount);
        if(Objects.equals(cartGoodsDetailDto.getProductType(), ProductTypeEnum.WEIGHT_PRODUCT.getCode())) {
            cartGoodsDetailDto.setFinalPrice(cartGoodsDetailDto.getSettlementPrice());
        } else {
            cartGoodsDetailDto.setFinalPrice(cartGoodsDetailDto.getSettlementPrice() / cartGoodsDetailDto.getQty());
        }
    }

    private static void setActivityDiscounts(List<CalculationApportionGoodsDto> apportionGoodsList, ShoppingCartGoodsResponse.CartGoodsDetailDto cartGoodsDetailDto, Boolean isApportion) {
        if(CollectionUtils.isEmpty(apportionGoodsList)) {
            return;
        }
        List<ActivityDiscountsDto> activityDiscountsDtoList = new ArrayList<>();
        int goodsTotalQty = apportionGoodsList.stream().mapToInt(apportionGoods -> apportionGoods.getGoodsQuantity()).sum();
        for (CalculationApportionGoodsDto apportionGoods : apportionGoodsList) {
            /**
             * 1. 商品券：cartGoodsDetailDto.couponCode非空，保留ApportionGoods#ApportionDetails#apportionType中32的
             * 2. 普通商品：cartGoodsDetailDto.couponCode空，去掉32的
             */
            List<CalculationApportionDetailDto> apportionDetails =new ArrayList<>();
            if (isApportion) {
                 apportionDetails = apportionGoods.getApportionDetails().stream().filter(detail -> !detail.getActivityType().equals(ActivityTypeEnum.TYPE_32.getCode())
                        && !detail.getActivityType().equals(ActivityTypeEnum.TYPE_104.getCode()) && !detail.getActivityType().equals(ActivityTypeEnum.TYPE_2.getCode())).collect(Collectors.toList());
            }else {
                 apportionDetails = apportionGoods.getApportionDetails().stream().filter(detail -> !detail.getActivityType().equals(ActivityTypeEnum.TYPE_32.getCode())
                        && !detail.getActivityType().equals(ActivityTypeEnum.TYPE_104.getCode()) && !detail.getActivityType().equals(ActivityTypeEnum.TYPE_2.getCode())
                        && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_12.getCode(), detail.getActivityType()) && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_11.getCode(), detail.getActivityType())
                        && ObjectUtils.notEqual(ActivityTypeEnum.TYPE_3.getCode(), detail.getActivityType())).collect(Collectors.toList());
            }
            for (CalculationApportionDetailDto detail : apportionDetails) {
                List<ActivityDiscountsDto> currentDiscount = activityDiscountsDtoList.stream().filter(discount -> ObjectUtils.equals(discount.getActivityCode(), detail.getActivityCode())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(currentDiscount)) {
                    currentDiscount.get(0).setDiscountAmount(currentDiscount.get(0).getDiscountAmount() + detail.getActivityApportionAmount().intValue() * apportionGoods.getGoodsQuantity() * cartGoodsDetailDto.getQty() / goodsTotalQty);
                } else {
                    ActivityDiscountsDto activityDiscountsDto = new ActivityDiscountsDto();
                    activityDiscountsDto.setActivityCode(detail.getActivityCode());
                    activityDiscountsDto.setActivityName(detail.getActivityName());
                    activityDiscountsDto.setActivityType(detail.getActivityType());
                    activityDiscountsDto.setDiscountAmount(detail.getActivityApportionAmount().intValue() * apportionGoods.getGoodsQuantity() * cartGoodsDetailDto.getQty() / goodsTotalQty);
                    activityDiscountsDtoList.add(activityDiscountsDto);
                }
            }
        }
        cartGoodsDetailDto.setActivityDiscountsDtos(activityDiscountsDtoList);
    }


    /**
     * 构建 ActivityCalculationDiscountRequestDto
     *
     * @param partnerId
     * @param storeId
     * @param userId
     * @param appId
     * @param orderType
     * @return
     */
    public static CalculationDiscountRequestDto getActivityCalculationDiscountRequestDto(String partnerId, String storeId, String userId, String appId, Integer orderType) {
        CalculationDiscountRequestDto activityCalculationDiscountRequestDto = new CalculationDiscountRequestDto();
        activityCalculationDiscountRequestDto.setPartnerCode(partnerId);
        activityCalculationDiscountRequestDto.setStoreId(storeId);
        //activityCalculationDiscountRequestDto.setIsShowGoodsActivity(1);
        activityCalculationDiscountRequestDto.setUserId(userId);
        activityCalculationDiscountRequestDto.setVer(1);
        activityCalculationDiscountRequestDto.setAppId(appId);
        activityCalculationDiscountRequestDto.setApplication("isaas");
//        ActivityChannelEnum activityChannelEnum = orderTypeConvert2ActivityChannel(orderType);
//        if (!Objects.isNull(activityChannelEnum)) {
//            activityCalculationDiscountRequestDto.setChannel(activityChannelEnum.getCode());
//        }
        return activityCalculationDiscountRequestDto;
    }

    /**
     * 将calculationDiscountGoods 封装后加入 calculationDiscountGoodsList
     *
     * @param calculationDiscountGoodsList
     * @param goodsId
     * @param goodsQuantity
     * @param originalPrice
     */
    public static void addCalculationDiscountGoods(List<CalculationDiscountGoodsDto> calculationDiscountGoodsList,
                                                   String goodsId, Integer goodsQuantity, Integer originalPrice) {
        CalculationDiscountGoodsDto calculationDiscountGoods = new CalculationDiscountGoodsDto();
        calculationDiscountGoods.setCartGoodsUid(UUID.randomUUID().toString());
        calculationDiscountGoods.setGoodsId(goodsId);
        calculationDiscountGoods.setGoodsQuantity(goodsQuantity);
        calculationDiscountGoods.setOriginalPrice(originalPrice);
        CalculationDiscountGoodsDto oldCalculationDiscountGoods = calculationDiscountGoodsList.stream().filter(t -> Objects.equals(t.getGoodsId(), goodsId) && Objects.equals(t.getOriginalPrice(), originalPrice)).findFirst().orElse(null);
        if(oldCalculationDiscountGoods != null) {
            oldCalculationDiscountGoods.setGoodsQuantity(oldCalculationDiscountGoods.getGoodsQuantity() + calculationDiscountGoods.getGoodsQuantity());
        } else {
            calculationDiscountGoodsList.add(calculationDiscountGoods);
        }

//        if (CollectionUtils.isNotEmpty(comboProductList)) {
//            calculationDiscountGoods.setMeal(true);
//            List<CalculationMealGoodsDto> calculationMealGoodsDtoList = new ArrayList<>();
//            comboProductList.stream().filter(OrderBeanRequest.ProductBean::getIsFixedProduct).forEach( productBean -> {
//                CalculationMealGoodsDto calculationMealGoodsDto = new CalculationMealGoodsDto();
//                calculationMealGoodsDto.setGoodsId(productBean.getProductId());
//                calculationMealGoodsDto.setGoodsQuantity(productBean.getNumber());
//                Long comboOriginalPrice = productBean.getPrice();
//                Long comboNowPricePrice = productBean.getSettlementPrice() / productBean.getNumber();
//                if (Objects.equals(productBean.getProductType(), ProductTypeEnum.WEIGHT_PRODUCT.getCode())) {
//                    comboOriginalPrice = productBean.getSettlementPrice() / productBean.getNumber();
//                }
//                calculationMealGoodsDto.setOriginalPrice(comboOriginalPrice.intValue());
//                calculationMealGoodsDto.setNowPrice(comboNowPricePrice.intValue());
//                calculationMealGoodsDtoList.add(calculationMealGoodsDto);
//            });
//            calculationDiscountGoods.setGroupCombox(calculationMealGoodsDtoList);
//        }
//        calculationDiscountGoodsList.add(calculationDiscountGoods);

    }

    private static ActivityChannelEnum orderTypeConvert2ActivityChannel(Integer orderType) {
        if (Objects.equals(CreateOrderType.TAKE_OUT.getCode(), orderType)) {
            return ActivityChannelEnum.delivery;
        } else if (Objects.equals(CreateOrderType.COLLECT_GOODS.getCode(), orderType)) {
            return ActivityChannelEnum.pickup;
        } else {
            return ActivityChannelEnum.pickup;
        }
    }
}
