package cn.freemud.service.cache;

import cn.freemud.entities.vo.CartGoods;
import cn.freemud.enums.ResponseResult;
import cn.freemud.interceptor.ServiceException;
import com.alibaba.fastjson.JSON;
import com.freemud.sdk.api.assortment.shoppingcart.constant.RedisKeyConstant;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author Clover.z
 * @Date 2021/10/28
 * @Desc 购物车对应的赠品缓存
 */
@Component
@RequiredArgsConstructor
public class GiftCacheManager {

    private final RedisTemplate<String, String> redisTemplate;

    /**
     * 购物车中赠品缓存有效期，默认3天
     */
    @Value("${saas.shoppingCart.giftCache.expireDay:3}")
    private Integer expireDay;

    /**
     * 重置购物车赠品缓存
     * @param giftList 赠品行信息
     * @param activityCode 赠品对应的活动号（不传则覆盖缓存所有数据，传则只会重置指定活动的赠品数据）
     * @param partnerId 商户号
     * @param storeCode 门店号
     * @param userId 用户userId
     * @return 返回更新后的赠品信息
     */
    public List<CartGoods> resetGiftCache(@NotNull List<CartGoods> giftList,
                                          String activityCode,
                                          @NotBlank String partnerId,
                                          @NotBlank String storeCode,
                                          @NotBlank String userId) {
        String redisKey = MessageFormat.format(RedisKeyConstant.SAAS_SHOPPING_CART_GIFT_KEY, partnerId, storeCode, userId);
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(redisKey);
        List<String> values = operations.values();
        // 将缓存转为对象
        List<CartGoods> oldGiftList = CollectionUtils.isEmpty(values)
                                        ? new ArrayList<>()
                                        : values.stream().map(v -> JSON.parseObject(v, CartGoods.class)).collect(Collectors.toList());
        // 存放最新的赠品缓存信息
        Map<String, String> newValues = new HashMap<>();
        for (CartGoods gift : giftList) {
            // 匹配赠品的商品属性，将原有赠品的属性更新到新计算出的赠品中
            Iterator<CartGoods> it = oldGiftList.iterator();
            while (it.hasNext()) {
                CartGoods old = it.next();
                boolean isSameType = StringUtils.isBlank(activityCode) || activityCode.equals(old.getActivityCode());
                // 买赠活动，多个不同属性的同一商品，赠品属性不能乱
                boolean oriSource = StringUtils.isBlank(gift.getOriginalGoodsUid()) || gift.getOriginalGoodsUid().equals(old.getOriginalGoodsUid());
                if (! old.getGoodsId().equals(gift.getGoodsId()) || ! isSameType || !oriSource) continue;
                // 赠品匹配上了，copy赠品属性
                gift.setExtra(old.getExtra());
                gift.setSubName(old.getSubName());
                gift.setCartGoodsUid(old.getCartGoodsUid());
                // 如果赠品为多个同一商品，并且每个商品都有不同的属性，所以这里要移除掉已经匹配上的商品
                it.remove();
                break;
            }
            newValues.put(gift.getCartGoodsUid(), JSON.toJSONString(gift));
        }
        // oldGiftList中剩下的， 属于其他活动的数据，不变，需要原样放入缓存中
        if (StringUtils.isNotBlank(activityCode)) {
            oldGiftList = oldGiftList.stream().filter(old -> !activityCode.equals(old.getActivityCode())).collect(Collectors.toList());
            for (CartGoods old : oldGiftList) {
                newValues.put(old.getCartGoodsUid(), JSON.toJSONString(old));
            }
        }
        if (CollectionUtils.isNotEmpty(values)) {
            //旧值不为空，清掉
            redisTemplate.delete(redisKey);
        }
        if (!newValues.isEmpty()) {
            operations.putAll(newValues);
            operations.expire(expireDay, TimeUnit.DAYS);
        }
        return giftList;
    }


    /**
     * 查询赠品的购物车信息
     * @param partnerId 商户号
     * @param storeCode 门店号
     * @param userId 用户id
     * @param uid 购物车行id
     * @return
     */
    public CartGoods queryGiftGoods(@NotBlank String partnerId,
                                    @NotBlank String storeCode,
                                    @NotBlank String userId,
                                    @NotBlank String uid) {
        String redisKey = MessageFormat.format(RedisKeyConstant.SAAS_SHOPPING_CART_GIFT_KEY, partnerId, storeCode, userId);
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(redisKey);
        String value = operations.get(uid);
        if (StringUtils.isBlank(value)) throw new ServiceException(ResponseResult.SHOPPING_CART_GETINFO_INVAILD);

        return JSON.parseObject(value, CartGoods.class);
    }

    /**
     * 查询赠品的购物车信息
     * @param partnerId 商户号
     * @param storeCode 门店号
     * @param userId 用户id
     * @param goods 赠品信息
     * @return
     */
    public void updateGiftGoods(@NotBlank String partnerId,
                                @NotBlank String storeCode,
                                @NotBlank String userId,
                                @NotNull CartGoods goods) {
        String redisKey = MessageFormat.format(RedisKeyConstant.SAAS_SHOPPING_CART_GIFT_KEY, partnerId, storeCode, userId);
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(redisKey);
        operations.put(goods.getCartGoodsUid(), JSON.toJSONString(goods));
    }

    /**
     * 清空赠品的购物车信息
     * @param partnerId 商户号
     * @param storeCode 门店号
     * @param userId 用户id
     * @return
     */
    public void clearGiftCache(@NotBlank String partnerId,
                               @NotBlank String storeCode,
                               @NotBlank String userId) {
        String redisKey = MessageFormat.format(RedisKeyConstant.SAAS_SHOPPING_CART_GIFT_KEY, partnerId, storeCode, userId);
        redisTemplate.delete(redisKey);
    }
}
