package com.ycwl.basic.repository;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.ycwl.basic.mapper.OrderMapper;
import com.ycwl.basic.model.pc.order.entity.OrderEntity;
import com.ycwl.basic.model.pc.order.entity.OrderItemEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
public class OrderRepository {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    public static final String ORDER_CACHE_KEY = "order:%s";
    public static final String ORDER_ITEMS_CACHE_KEY = "order:%s:items";
    public static final String ORDER_ITEM_CACHE_KEY = "order:item:%s";
    public static final String ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY = "order:user:%s:type:%s:id:%s";

    public OrderEntity getOrder(Long orderId) {
        if (redisTemplate.hasKey(String.format(ORDER_CACHE_KEY, orderId))) {
            return JSON.parseObject(redisTemplate.opsForValue().get(String.format(ORDER_CACHE_KEY, orderId)), OrderEntity.class);
        }
        OrderEntity orderEntity = orderMapper.get(orderId);
        if (orderEntity != null) {
            redisTemplate.opsForValue().set(String.format(ORDER_CACHE_KEY, orderId), JSON.toJSONString(orderEntity), 60, TimeUnit.SECONDS);
        }
        return orderEntity;
    }

    public List<OrderItemEntity> getOrderItems(Long orderId) {
        if (redisTemplate.hasKey(String.format(ORDER_ITEMS_CACHE_KEY, orderId))) {
            return JSON.parseArray(redisTemplate.opsForValue().get(String.format(ORDER_ITEMS_CACHE_KEY, orderId)), Long.class)
                    .stream().map(this::getOrderItemByOrderItemId).collect(Collectors.toList());
        }
        List<OrderItemEntity> orderItemEntities = orderMapper.listOrderItemByOrderId(orderId);
        if (orderItemEntities != null) {
            redisTemplate.opsForValue().set(
                    String.format(ORDER_ITEMS_CACHE_KEY, orderId),
                    JSONArray.toJSONString(orderItemEntities.stream().map(OrderItemEntity::getId).collect(Collectors.toList()))
            );
        }
        return orderItemEntities;
    }

    public OrderItemEntity getOrderItemByOrderItemId(Long orderItemId) {
        if (redisTemplate.hasKey(String.format(ORDER_ITEM_CACHE_KEY, orderItemId))) {
            return JSON.parseObject(redisTemplate.opsForValue().get(String.format(ORDER_ITEM_CACHE_KEY, orderItemId)), OrderItemEntity.class);
        }
        OrderItemEntity orderItemEntity = orderMapper.getOrderItem(orderItemId);
        if (orderItemEntity != null) {
            redisTemplate.opsForValue().set(String.format(ORDER_ITEM_CACHE_KEY, orderItemId), JSON.toJSONString(orderItemEntity));
        }
        return orderItemEntity;
    }

    public boolean checkUserBuyItem(Long userId, int goodsType, Long goodsId) {
        synchronized (this) {
            if (redisTemplate.hasKey(String.format(ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY, userId, goodsType, goodsId))) {
                return "1".equals(redisTemplate.opsForValue().get(String.format(ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY, userId, goodsType, goodsId)));
            }
            OrderEntity orderEntity = orderMapper.getUserBuyItem(userId, goodsType, goodsId);
            if (orderEntity == null) {
                redisTemplate.opsForValue().set(String.format(ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY, userId, goodsType, goodsId), "0", 60, TimeUnit.SECONDS);
                return false;
            }
            if (Integer.valueOf(1).equals(orderEntity.getStatus())) {
                redisTemplate.opsForValue().set(String.format(ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY, userId, goodsType, goodsId), "1");
                return true;
            } else {
                redisTemplate.opsForValue().set(String.format(ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY, userId, goodsType, goodsId), "0", 60, TimeUnit.SECONDS);
                return false;
            }
        }
    }

    public OrderEntity getUserBuyItem(Long userId, int goodsType, Long goodsId) {
        return orderMapper.getUserBuyItem(userId, goodsType, goodsId);
    }

    public boolean checkUserBuyFaceSourceImage(Long userId, Long faceId) {
        return checkUserBuyItem(userId, 2, faceId);
    }

    public boolean checkUserBuyFaceSourceVideo(Long userId, Long faceId) {
        return checkUserBuyItem(userId, 1, faceId);
    }

    public boolean checkUserBuyVideo(Long userId, Long videoId) {
        return checkUserBuyItem(userId, 0, videoId);
    }

    public void clearUserBuyItemCache(Long userId, int goodsType, Long goodsId) {
        redisTemplate.delete(String.format(ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY, userId, goodsType, goodsId));
    }

    public void clearOrderCache(Long orderId) {
        OrderEntity order = getOrder(orderId);
        redisTemplate.delete(String.format(ORDER_CACHE_KEY, orderId));
        getOrderItems(orderId).forEach(orderItem -> {
            redisTemplate.delete(String.format(ORDER_ITEM_CACHE_KEY, orderItem.getId()));
            clearUserBuyItemCache(order.getMemberId(), orderItem.getGoodsType(), orderItem.getGoodsId());
        });
        redisTemplate.delete(String.format(ORDER_ITEMS_CACHE_KEY, orderId));
    }

    public void updateOrder(Long orderId, OrderEntity updateEntity) {
        updateEntity.setId(orderId);
        orderMapper.updateOrder(updateEntity);
        clearOrderCache(orderId);
    }
}
