
package com.tmerclub.cloud.coupon.util;

import cn.hutool.core.collection.CollectionUtil;
import com.tmerclub.cloud.api.coupon.constant.CouponProdType;
import com.tmerclub.cloud.api.coupon.constant.CouponType;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.order.vo.CouponOrderVO;
import com.tmerclub.cloud.common.order.vo.ShopCartItemVO;
import com.tmerclub.cloud.common.util.PriceUtil;

import java.util.*;

/**
 * 协助优惠券进行选择
 * @author tmerclub
 */
public class ChooseCouponHelper {
    /**
     * 购物项
     */
    private final List<ShopCartItemVO> shopCartItems;
    /**
     * 含有的优惠券列表
     */
    private final List<CouponOrderVO> shopCoupons;
    /**
     * 选中的优惠券id
     */
    private final List<Long> couponIds;

    /**
     * 用户是否选中优惠券
     */
    private final Integer userChangeCoupon;
    /**
     * 选中的优惠券
     */
    private CouponOrderVO chooseCoupon;

    /**
     * 可用优惠券的商品实际金额（商品实际金额 - 商品分摊金额）
     */
    private Long prodCanUseCouponActualTotal;

    /**
     * 优惠金额
     */
    private Long couponReduce;

    /**
     * 优惠券在订单中的优惠金额
     */
    private Long couponInOrderAmount;


    /**
     * 优惠金额关联店铺map
     */
    private final Map<Long, Long> shopReduceMap = new HashMap<>(12);

    public ChooseCouponHelper(List<ShopCartItemVO> shopCartItems, List<CouponOrderVO> shopCoupons, List<Long> couponIds, Integer userChangeCoupon) {
        this.shopCartItems = shopCartItems;
        this.shopCoupons = shopCoupons;
        this.couponIds = couponIds;
        this.userChangeCoupon = userChangeCoupon;
    }

    public CouponOrderVO getChooseCoupon() {
        return chooseCoupon;
    }


    public Long getCouponReduce() {
        return this.couponReduce;
    }

    public Map<Long, Long> getShopReduceMap() {
        return shopReduceMap;
    }

    public ChooseCouponHelper invoke() {
        // 没有商品直接返回
        if (CollectionUtil.isEmpty(shopCartItems)) {
            return this;
        }


        // 用户选中的关于该店铺的优惠券，一家店只能选择一张优惠券
        chooseCoupon = null;

        // 可用优惠券的商品实际金额（商品实际金额 - 商品分摊金额）
        prodCanUseCouponActualTotal = 0L;
        Date now = new Date();
        for (CouponOrderVO shopCoupon : shopCoupons) {
            if (shopCoupon.getStartTime().getTime() > now.getTime() || shopCoupon.getEndTime().getTime() < now.getTime()) {
                continue;
            }
            // 该优惠券关联的商品id
            List<Long> prodIds = shopCoupon.getSpuIds();
            // 可用优惠券的商品实际金额（商品实际金额 - 商品分摊金额）
            prodCanUseCouponActualTotal = 0L;
            for (ShopCartItemVO shopCartItem : shopCartItems) {
                // 套餐不参与优惠券活动
                if (Objects.nonNull(shopCartItem.getComboId()) && shopCartItem.getComboId() != 0) {
                    continue;
                }
                shopCartItem.setIsShareReduce(0);
                long spuId = Objects.nonNull(shopCartItem.getMainComboSpuId()) ? shopCartItem.getMainComboSpuId() : shopCartItem.getSpuId();
                // 该商品是否在该优惠券可用
                boolean isCouponsProd = isCouponsProd(spuId, prodIds, shopCoupon.getSuitableProdType());
                if (isCouponsProd) {
                    shopCartItem.setIsShareReduce(1);
                    prodCanUseCouponActualTotal = prodCanUseCouponActualTotal + shopCartItem.getActualTotal();
                }
            }
            Date date = new Date();
            // 如果该商品实际总金额大于等于优惠券最低使用金额，并且开始时间大于优惠券的使用时间，则优惠券可用
            if (prodCanUseCouponActualTotal >= shopCoupon.getCashCondition() && shopCoupon.getStartTime().getTime() < date.getTime()) {
                // 将优惠券标记为可用状态
                shopCoupon.setCanUse(true);
                shopCoupon.setProdCanUseCouponActualTotal(prodCanUseCouponActualTotal);
                calculateCouponReduce(shopCoupon);
                // 聚合 用户选中的关于该店铺的优惠券
                if (CollectionUtil.isNotEmpty(couponIds)) {
                    for (Long couponId : couponIds) {
                        if (Objects.equals(couponId, shopCoupon.getCouponId())) {
                            chooseCoupon = shopCoupon;
                            break;
                        }
                    }
                }
                if (chooseCoupon != null && !Objects.equals(userChangeCoupon, 1)) {
                    // 选择优惠最大
                    chooseCoupon = shopCoupon.getCouponReduce() > chooseCoupon.getCouponReduce() ? shopCoupon : chooseCoupon;
                }
                // 如果用户没有选择优惠券，系统默认选择一张可用优惠券
                if (chooseCoupon == null && !Objects.equals(userChangeCoupon, 1)) {
                    chooseCoupon = shopCoupon;
                }
            }
        }
        for (CouponOrderVO shopCoupon : shopCoupons) {
            // 该优惠券关联的商品id
            List<Long> prodIds = shopCoupon.getSpuIds();
            if (Objects.nonNull(chooseCoupon) && !Objects.equals(shopCoupon.getCouponUserId(), chooseCoupon.getCouponUserId())) {
                continue;
            }
            for (ShopCartItemVO shopCartItem : shopCartItems) {
                shopCartItem.setIsShareReduce(0);
                long spuId = Objects.nonNull(shopCartItem.getMainComboSpuId()) ? shopCartItem.getMainComboSpuId() : shopCartItem.getSpuId();
                // 该商品是否在该优惠券可用
                boolean isCouponsProd = isCouponsProd(spuId, prodIds, shopCoupon.getSuitableProdType());
                if (isCouponsProd) {
                    shopCartItem.setIsShareReduce(1);
                }
            }
        }
        if (chooseCoupon != null) {
            // 计算优惠券优惠金额
            calculateCouponReduce(chooseCoupon);
            // 设置分摊优惠金额
            setShareReduce();
            if (couponReduce > 0) {
                // 优惠券金额可用时才能勾选
                chooseCoupon.setChoose(true);
            }
        }
        return this;
    }

    /**
     * 判断某个商品是否在此优惠券中
     *
     * @param prodId         在该店铺中的商品商品id
     * @param couponProdIds  优惠券关联的商品id
     * @param couponProdType 优惠券适用商品类型
     * @return 商品是否在此优惠券中
     */
    private boolean isCouponsProd(Long prodId, List<Long> couponProdIds, Integer couponProdType) {

        if (CouponProdType.ALL.value().equals(couponProdType)) {
            return true;
        }
        if (CouponProdType.PROD_IN.value().equals(couponProdType)) {
            if (CollectionUtil.isEmpty(couponProdIds)) {
                return false;
            }
            for (Long couponProdId : couponProdIds) {
                if (Objects.equals(couponProdId, prodId)) {
                    return true;
                }
            }
            return false;
        }
        return false;
    }


    /**
     * 计算优惠金额
     */
    private void calculateCouponReduce(CouponOrderVO chooseCoupon) {
        couponReduce = 0L;
        couponInOrderAmount = 0L;
        // 代金券
        if (CouponType.C2M.value().equals(chooseCoupon.getCouponType())) {
            couponInOrderAmount = chooseCoupon.getReduceAmount();
        }
        // 折扣券
        if (CouponType.C2D.value().equals(chooseCoupon.getCouponType())) {
            couponInOrderAmount = chooseCoupon.getProdCanUseCouponActualTotal() -
                    PriceUtil.divideByBankerRounding((long) (chooseCoupon.getProdCanUseCouponActualTotal() * chooseCoupon.getCouponDiscount()), 10);
            chooseCoupon.setReduceAmount(couponInOrderAmount);
        }
        couponReduce = couponReduce + couponInOrderAmount;
        chooseCoupon.setCouponReduce(couponReduce);
    }

    /**
     * 设置分摊优惠金额
     */
    private void setShareReduce() {
        long sumReduce = 0L;
        shopCartItems.sort(Comparator.comparing(ShopCartItemVO::getActualTotal));
        for (int i = 0; i < shopCartItems.size(); i++) {
            ShopCartItemVO shopCartItem = shopCartItems.get(i);
            // 套餐商品不参与优惠券，或者优惠金额不分摊
            boolean notShareReduce = (Objects.nonNull(shopCartItem.getComboId()) && shopCartItem.getComboId() != 0) || shopCartItem.getIsShareReduce() != 1;
            if (notShareReduce) {
                continue;
            }
            // 分摊金额计算
            // 步骤一： 计算优惠分摊的比例 = 优惠券的总优惠金额） / 可用优惠券的商品实际金额（商品实际金额 - 商品分摊金额）
            // 步骤二： 计算商品的优惠券分摊金额 = 分摊比例 * 商品实际金额
            // 实际计算： 优惠券分摊金额 = (商品实际金额 * 优惠券的总优惠金额） / 可用优惠券的商品实际金额（商品实际金额 - 商品分摊金额）
            // couponInOrderAmount这个不做整除100的操作是因为会丢失精度，在这里把最后乘100的操作去除就好了
            long shareReduce = PriceUtil.divideByBankerRounding(couponInOrderAmount * shopCartItem.getActualTotal(), prodCanUseCouponActualTotal);

            // 如果是最后一项，直接将剩余的优惠金额赋值给他
            if (i + 1 == shopCartItems.size()) {
                shareReduce = Math.min(couponReduce - sumReduce, shopCartItem.getTotalAmount());
            }

            // 实际金额只有0.01就不要参与优惠金额分摊了
            if (shopCartItem.getActualTotal() == 1) {
                shareReduce = 0L;
            }
            // 商品实际金额等于优惠券分摊金额，商品实际金额最低为0.01，所以优惠券优惠金额要减去0.01
            if (shareReduce == shopCartItem.getActualTotal()) {
                shareReduce = shareReduce - Constant.MIN_SPU_AMOUNT;
            }
            // 分摊的优惠金额不能大于商品实际金额, 取最小值
            else if (shareReduce > shopCartItem.getActualTotal()) {
                // 分摊的优惠金额 不能大于商品金额
                shareReduce = shopCartItem.getActualTotal() - Constant.MIN_SPU_AMOUNT;
            }

            // 写入优惠金额
            if (Objects.equals(chooseCoupon.getShopId(), 0L)) {
                // 平台分摊的每一个购物项优惠金额
                shopCartItem.setPlatformShareReduce(shopCartItem.getPlatformShareReduce() + shareReduce);
                shopCartItem.setPlatformCouponAmount(shareReduce);
            } else {
                // 商家分摊的每一个购物项优惠金额
                shopCartItem.setShareReduce(shopCartItem.getShareReduce() + shareReduce);
                shopCartItem.setShopCouponAmount(shareReduce);
            }
            shopCartItem.setActualTotal(shopCartItem.getActualTotal() - shareReduce);
            sumReduce = shareReduce + sumReduce;
        }

        shopCartItems.sort(Comparator.comparing(ShopCartItemVO::getActualTotal).reversed());
        // 如果优惠金额分摊后还有剩余，就再分摊一次
        for (ShopCartItemVO shopCartItem : shopCartItems) {
            // 套餐商品不参与优惠券， 或者优惠券不分滩
            boolean notShareReduce = (Objects.nonNull(shopCartItem.getComboId()) && shopCartItem.getComboId() != 0) || shopCartItem.getIsShareReduce() != 1;
            // 可分摊优惠金额，且优惠金额还有剩余
            if (!notShareReduce && sumReduce < chooseCoupon.getReduceAmount()) {
                sumReduce = this.reassembleAmount(sumReduce, shopCartItem);
            }

            Long actualShareReduce = Objects.equals(chooseCoupon.getShopId(), 0L) ? shopCartItem.getPlatformCouponAmount() : shopCartItem.getShopCouponAmount();
            if (Objects.isNull(actualShareReduce)) {
                actualShareReduce = Constant.ZERO_LONG;
            }
            // 将对应店铺优惠券优惠的金额放入map中
            if (shopReduceMap.containsKey(shopCartItem.getShopId())) {
                Long shopReduce = shopReduceMap.get(shopCartItem.getShopId());
                shopReduceMap.put(shopCartItem.getShopId(), shopReduce + actualShareReduce);
            } else {
                shopReduceMap.put(shopCartItem.getShopId(), actualShareReduce);
            }
        }
        couponReduce = sumReduce;
        // 最终如果使用的优惠金额为0,则表示没有使用任何优惠券
        if(sumReduce == 0L && chooseCoupon.getReduceAmount() > 0L){
            couponReduce = 0L;
            for (CouponOrderVO shopCoupon : shopCoupons) {
                if(Objects.equals(chooseCoupon.getCouponId(),shopCoupon.getCouponId())){
                    shopCoupon.setChoose(false);
                    shopCoupon.setCanUse(false);
                    chooseCoupon = null;
                    break;
                }
            }
        }
    }

    private long reassembleAmount(long sumReduce, ShopCartItemVO shopCartItem) {
        // 当前分摊的优惠金额小于优惠券优惠金额， 再给各个商品分摊下， 按实际金额从大到小
        long shareReduce = Constant.ZERO_LONG;
        // 如果实际金额 大于 0.01, 就再加一点优惠金额
        if (shopCartItem.getActualTotal() > Constant.MIN_SPU_AMOUNT) {
            long actualShareReduce = chooseCoupon.getReduceAmount() - sumReduce;
            // 计算还可以分摊的金额 - 商品剩余可用于分摊的金额 和 优惠券剩余的可分摊金额 取最小值
            shareReduce = Math.min(shopCartItem.getActualTotal() - Constant.MIN_SPU_AMOUNT, actualShareReduce);
        }
        if (shareReduce <= 0) {
            return sumReduce;
        }

        // 写入优惠金额
        if (Objects.equals(chooseCoupon.getShopId(), 0L)) {
            // 平台分摊的每一个购物项优惠金额
            shopCartItem.setPlatformShareReduce(shopCartItem.getPlatformShareReduce() + shareReduce);
            shopCartItem.setPlatformCouponAmount(shopCartItem.getPlatformCouponAmount() + shareReduce);
        } else {
            // 商家分摊的每一个购物项优惠金额
            shopCartItem.setShareReduce(shopCartItem.getShareReduce() + shareReduce);
            shopCartItem.setShopCouponAmount(shopCartItem.getShopCouponAmount() + shareReduce);
        }
        sumReduce = sumReduce + shareReduce;
        shopCartItem.setActualTotal(shopCartItem.getActualTotal() + shareReduce);
        return sumReduce;
    }
}
