
package com.tmerclub.cloud.discount.manager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.tmerclub.cloud.api.discount.constant.DiscountRule;
import com.tmerclub.cloud.api.discount.vo.DiscountSumItemVO;
import com.tmerclub.cloud.api.discount.vo.DiscountSumVO;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.order.vo.ChooseDiscountItemVO;
import com.tmerclub.cloud.common.order.vo.DiscountItemOrderVO;
import com.tmerclub.cloud.common.order.vo.DiscountOrderVO;
import com.tmerclub.cloud.common.order.vo.ShopCartItemVO;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.common.util.BooleanUtil;
import com.tmerclub.cloud.common.util.PriceUtil;
import com.tmerclub.cloud.discount.constant.SuitableProdTypeEnum;
import com.tmerclub.cloud.discount.model.Discount;
import com.tmerclub.cloud.discount.service.DiscountService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 满减活动金额计算
 *
 * @author tmerclub
 */
@Service
public class DiscountManager {

    private final Logger LOGGER = LoggerFactory.getLogger(DiscountManager.class);

    @Autowired
    private DiscountService discountService;


    /**
     * 方法的作用
     * 1.计算优惠金额
     * 2. 并往productItems 设置满减优惠信息
     *
     * @param shopId
     * @param productItems
     * @return
     */
    public DiscountSumVO calculateDiscount(Long shopId, List<? extends ShopCartItemVO> productItems) {
        DiscountSumVO discountSum = new DiscountSumVO();
        discountSum.setTotalReduceAmount(0L);
        List<DiscountOrderVO> discounts = discountService.listDiscountsAndItemsByShopId(shopId);
        // 旧的商品数据，也就是第一次传入的商品数据
        List<ShopCartItemVO> oldProdItems = new ArrayList<>(productItems);
        // 以优惠活动id为key， 每个满减活动的活动信息 为value的map
        // {优惠活动id：每个满减活动的活动信息}
        Map<Long, DiscountSumItemVO> discountIdDiscountSumItemMap = new HashMap<>(productItems.size());
        //保存满减的金额
        Long amount = 0L;
        if (productItems.size() == 1 && productItems.get(0).getDiscountId() == 0) {
            // 立即提交订单, 选择满减最高的活动
            ShopCartItemVO productItemDto = productItems.get(0);
            for (DiscountOrderVO discount : discounts) {
                long spuId = Objects.nonNull(productItemDto.getMainComboSpuId()) ? productItemDto.getMainComboSpuId() : productItemDto.getSpuId();
                //判断商品是否参与该活动
                boolean hasDiscount = isHasDiscount(discount, spuId);
                if (!hasDiscount) {
                    continue;
                }
                //添加到活动列表
                DiscountOrderVO discountDto = new DiscountOrderVO();
                discountDto.setDiscountName(discount.getDiscountName());
                discountDto.setDiscountId(discount.getDiscountId());
                if (CollUtil.isEmpty(productItemDto.getDiscounts())) {
                    productItemDto.setDiscounts(new ArrayList<>(0));
                }
                productItemDto.getDiscounts().add(discountDto);
                //获取最高满减的活动
                DiscountSumItemVO discountSumItemDto = new DiscountSumItemVO();
                discountSumItemDto.setCount(productItemDto.getCount());
                if (productItemDto.getIsChecked() == 0) {
                    discountSumItemDto.setProdsPrice(0L);
                } else {
                    discountSumItemDto.setProdsPrice(productItemDto.getActualTotal());
                }
                findDiscountItemAndGetReduceAmount(discount, discountSumItemDto);
                discountIdDiscountSumItemMap.put(discount.getDiscountId(), discountSumItemDto);
                //该活动的满减金额大于前一个，则把满减活动替换成当前的活动
                if (productItemDto.getDiscountId() == 0 || amount < discountSumItemDto.getReduceAmount()) {
                    productItemDto.setDiscountId(discount.getDiscountId());
                    discountSum.setTotalReduceAmount(discountSumItemDto.getReduceAmount());
                    amount = discountSumItemDto.getReduceAmount();
                }
            }
            LOGGER.info("立即提交订单，选择满减最高的活动，满减活动id：{}", productItemDto.getDiscountId());
        } else {
            // 购物车
            for (DiscountOrderVO discount : discounts) {
                // 获取当前优惠的商品
                List<ShopCartItemVO> hasCurrentDiscountProds = mergeDiscountProd(oldProdItems, discount);
                DiscountSumItemVO discountSumItem = getDiscountSumItemVO();
                // 计算参与该活动的所有商品的商品金额，商品数量
                for (ShopCartItemVO hasDiscountProd : hasCurrentDiscountProds) {
                    if (BooleanUtil.isTrue(hasDiscountProd.getIsChecked())) {
                        // 套餐商品不计算进去
                        if (Objects.nonNull(hasDiscountProd.getComboId()) && hasDiscountProd.getComboId() > 0) {
                            continue;
                        }
                        discountSumItem.setCount(discountSumItem.getCount() + hasDiscountProd.getCount());
                        discountSumItem.setProdsPrice(discountSumItem.getProdsPrice() + hasDiscountProd.getTotalAmount());
                    }
                }
                findDiscountItemAndGetReduceAmount(discount, discountSumItem);
                discountIdDiscountSumItemMap.put(discount.getDiscountId(), discountSumItem);
                discountSum.setTotalReduceAmount(discountSum.getTotalReduceAmount() + discountSumItem.getReduceAmount());
            }
            LOGGER.info("购物车，计算满减活动，满减活动id：{}", discountIdDiscountSumItemMap.keySet());
        }
        discountSum.setDiscountIdDiscountSumItemMap(discountIdDiscountSumItemMap);
        return discountSum;
    }

    private static DiscountSumItemVO getDiscountSumItemVO() {
        DiscountSumItemVO discountSumItem = new DiscountSumItemVO();
        discountSumItem.setDiscount(0L);
        discountSumItem.setDiscountItemId(-1L);
        discountSumItem.setCount(0);
        discountSumItem.setProdsPrice(0L);
        discountSumItem.setNeedAmount(0L);
        discountSumItem.setReduceAmount(0L);
        return discountSumItem;
    }

    public ChooseDiscountItemVO getChooseDiscountItemVO(DiscountSumVO discountSum, Long discountId) {

        ChooseDiscountItemVO chooseDiscountItemVO = null;
        // 参与活动
        if (discountId != -1 && discountId != 0) {
            Map<Long, DiscountSumItemVO> discountIdDiscountSumItemMap = discountSum.getDiscountIdDiscountSumItemMap();
            DiscountSumItemVO discountSumItemVO = discountIdDiscountSumItemMap.get(discountId);
            if (discountSumItemVO == null) {
                return null;
            }

            Discount discount = discountService.getDiscountByDiscountId(discountId);
            if (Objects.nonNull(discount)) {
                chooseDiscountItemVO = BeanUtil.map(discount, ChooseDiscountItemVO.class);

                chooseDiscountItemVO.setProdsPrice(discountSumItemVO.getProdsPrice());
                chooseDiscountItemVO.setCount(discountSumItemVO.getCount());
                chooseDiscountItemVO.setNeedAmount(discountSumItemVO.getNeedAmount());
                chooseDiscountItemVO.setDiscountItemId(discountSumItemVO.getDiscountItemId());
                chooseDiscountItemVO.setDiscount(discountSumItemVO.getDiscount());
                chooseDiscountItemVO.setReduceAmount(discountSumItemVO.getReduceAmount());
            }
        }
        return chooseDiscountItemVO;
    }

    /**
     * 1. 找出当前优惠活动属于那个优惠项
     * 2. 计算满减
     *
     * @param discount 优惠活动
     */
    private void findDiscountItemAndGetReduceAmount(DiscountOrderVO discount, DiscountSumItemVO discountSumItemVO) {
        // 枚举DiscountRule(0 满钱减钱 1满件减钱 2 满钱打折 3满件打折)
        Integer discountRule = discount.getDiscountRule();
        // 减免类型 0按满足最高层级减一次 1每满一次减一次
        Integer discountType = discount.getDiscountType();

        List<DiscountItemOrderVO> discountItems = discount.getDiscountItems();

        double prodCount = discountSumItemVO.getCount();
        Long prodsPrice = discountSumItemVO.getProdsPrice();

        Long totalReduceAmount = 0L;
        Long discountItemId = -1L;
        for (DiscountItemOrderVO discountItem : discountItems) {
            // 优惠（元/折）
            Long reduceAmount = discountItem.getDiscount();

            discountItemId = discountItem.getDiscountItemId();
            Long needAmount = discountItem.getNeedAmount();
            discountSumItemVO.setNeedAmount(needAmount);
            discountSumItemVO.setDiscount(reduceAmount);
            // 当规则为满钱减钱时
            if (Objects.equals(discountRule, DiscountRule.M2M.value()) && prodsPrice >= needAmount) {
                totalReduceAmount = getTotalReduceAmountBySubMoney(discountType, prodsPrice, reduceAmount, needAmount);
                break;
            }
            // 当规则为满件打折时 9.5折就是95、9.5元就是950，此时数据库存的是件数*100，还需除以100进行判断
            needAmount = PriceUtil.toDecimalPrice(needAmount).longValue();
            if (Objects.equals(discountRule, DiscountRule.P2D.value()) && prodCount >= needAmount) {
                // （商品金额 * （1000 - 折扣比例）） / 1000 ，原本是正常除以10，因为比例乘以了100所以此处也是除以1000
                totalReduceAmount = PriceUtil.divideByBankerRounding(prodsPrice * (1000 - reduceAmount), 1000);
                break;
            }
        }
        // 如果是每满一次减一次，则需要判断上限 不为满钱减钱或者满足最高层级减一次情况下，需要判断上限
        if (discountType != 0 || !Objects.equals(discount.getDiscountRule(), 0)) {
            totalReduceAmount = Math.min(discount.getMaxReduceAmount(), totalReduceAmount);
        }
        discountSumItemVO.setReduceAmount(totalReduceAmount);
        discountSumItemVO.setDiscountItemId(discountItemId);
    }

    private Long getTotalReduceAmountBySubMoney(Integer discountType, Long prodsPriceOrCount, Long reduceAmount, Long needAmount) {
        Long totalReduceAmount;
        if (discountType == 0) {
            // 当商品价格大于最高层级时
            totalReduceAmount = reduceAmount;
        } else {
            // 查看满足多少次条件(向下取整)
            long multi = prodsPriceOrCount / needAmount;
            totalReduceAmount = reduceAmount * multi;
        }
        return totalReduceAmount;
    }

    /**
     * 合并当前优惠的商品
     * 注：如果oldProdItems商品有该优惠，则将其抽取出来，并且在oldProdItems中移除该商品
     *
     * @param oldProdItems 商品项
     * @param discount     活动
     * @return
     */
    private List<ShopCartItemVO> mergeDiscountProd(List<ShopCartItemVO> oldProdItems, DiscountOrderVO discount) {

        // 拥有当前优惠活动的商品
        List<ShopCartItemVO> hasCurrentDiscountProds = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (ShopCartItemVO productItem : oldProdItems) {
            long spuId = Objects.nonNull(productItem.getMainComboSpuId()) ? productItem.getMainComboSpuId() : productItem.getSpuId();
            // 查看商品是否包含优惠活动
            boolean hasDiscount = isHasDiscount(discount, spuId);
//            if(productItem.getIsChecked() == 0){
//                hasDiscount = false;
//            }
            // 购物车商品数据中插入满减活动列表
            DiscountOrderVO discountOrderVO = new DiscountOrderVO();
            discountOrderVO.setDiscountId(discount.getDiscountId());
            discountOrderVO.setDiscountName(discount.getDiscountName());
            if (CollectionUtil.isEmpty(productItem.getDiscounts())) {
                productItem.setDiscounts(new ArrayList<>(0));
            }
            if (Objects.equals(discount.getSuitableSpuType(), SuitableProdTypeEnum.ALL_SPU.value()) || discount.getSpuIds().contains(spuId)) {
                productItem.getDiscounts().add(discountOrderVO);
            }

            // 商品选择了这个活动
            boolean prodChooseDiscount = Objects.equals(productItem.getDiscountId(), discount.getDiscountId());

            // 如果商品不包含该优惠活动
            // 或用户选择不参与该活动，将活动清除
            if (!hasDiscount && prodChooseDiscount) {
                //  将往productItems 设置满减优惠信息为【-1】
                productItem.setDiscountId(-1L);
            }
            // 如果 商品参与了该活动，将会分为几个步骤
            // 判断商品是否在这个活动中（如果用户没有为商品主动选择优惠活动，或选择的优惠活动与该满减的优惠活动一样 则视为商品在活动中）
            else if (hasDiscount && prodChooseDiscount) {

                // 2. 将往productItems 设置满减优惠信息为【当前活动】
                productItem.setDiscountId(discount.getDiscountId());

                // 3. 将该活动的商品统一起来
                hasCurrentDiscountProds.add(productItem);
            }
            // 如果商品参与该活动
            // 且用户没有主动放弃该活动
            else if (hasDiscount && productItem.getDiscountId() == 0) {

                // 2. 将往productItems 设置满减优惠信息为【当前活动】
                productItem.setDiscountId(discount.getDiscountId());

                // 3. 将该活动的商品统一起来
                hasCurrentDiscountProds.add(productItem);
            }
        }

        return hasCurrentDiscountProds;
    }

    /**
     * 查看商品是否包含优惠活动
     *
     * @param discount 当前优惠活动信息
     * @param spuId    当前商品id
     * @return
     */
    private boolean isHasDiscount(DiscountOrderVO discount, Long spuId) {
        boolean hasDiscount = false;
        List<Long> spuIds = discount.getSpuIds();
        // 所有商品都含有该优惠
        if (Objects.equals(discount.getSuitableSpuType(), 0)) {
            hasDiscount = true;
        } else if (Objects.equals(discount.getSuitableSpuType(), 1)) {
            // 指定商品含有该优惠
            for (Long spuIdVO : spuIds) {
                if (Objects.equals(spuIdVO, spuId)) {
                    hasDiscount = true;
                    break;
                }
            }
        }
        return hasDiscount;
    }


}
