package com.webchat.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import com.webchat.common.enums.RedisKeyEnum;
import com.webchat.common.enums.ResourceBehaviorTypeEnum;
import com.webchat.common.enums.ResourceTypeEnum;
import com.webchat.common.util.JsonUtil;
import com.webchat.domain.convert.MomentEntityConvert;
import com.webchat.domain.vo.response.FriendApplyUserVO;
import com.webchat.domain.vo.response.MessageResourceVO;
import com.webchat.domain.vo.response.MomentResponseBaseVO;
import com.webchat.domain.vo.response.MomentResponseDetailVO;
import com.webchat.domain.vo.response.UserBaseResponseInfoVO;
import com.webchat.repository.dao.IFriendDAO;
import com.webchat.repository.dao.IMomentDAO;
import com.webchat.repository.dao.IMomentTimeLineDAO;
import com.webchat.repository.entity.MomentEntity;
import com.webchat.repository.entity.MomentTimeLineEntity;
import com.webchat.service.behavior.AbstractResourceBehaviorService;
import com.webchat.service.behavior.ResourceBehaviorFactory;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author:  <QQ.Eamil>1124602935@qq.com</QQ.Eamil>
 * @Date: 2021-7-11 0011 14:48
 * @Description: 无描述信息
 */
@Service
public class MomentCacheService implements ResourceMessageInterface {

    @Autowired
    private IMomentDAO momentDAO;
    @Autowired
    private RedisService redisService;
    @Autowired
    private UserService userService;
    @Autowired
    private CommentService commentService;
    @Autowired
    private FriendService friendService;
    @Autowired
    private IMomentTimeLineDAO momentTimeLineDAO;

    private static final int DEFAULT_DISPLAY_LIKE_USERS_COUNT = 5;

    public void refreshCommunityAboutCacheByPublish(MomentEntity entity) {
        // 刷新动态详情缓存
        refreshMomentDetailCache(entity);
        // 插入好用动态时间线缓存&写入数据库
        saveMoment2FansMomentTimeLineCache(entity);
    }

    private void saveMoment2FansMomentTimeLineCache(MomentEntity entity) {
        // 动态ID
        Long momentId = entity.getId();
        // 作者
        String userId = entity.getAuthor();
        Set<String> timeLineUserIds = new HashSet<>();
        timeLineUserIds.add(userId);
        List<FriendApplyUserVO> friendApplyUserVOS = friendService.listFriendUsers(userId, null);
        if (CollectionUtils.isNotEmpty(friendApplyUserVOS)) {
            Set<String> friends = friendApplyUserVOS.stream().map(f -> f.getApplyUser().getUserId()).collect(Collectors.toSet());
            timeLineUserIds.addAll(friends);
        }
        Date now = new Date();
        List<MomentTimeLineEntity> saveTimeLines = timeLineUserIds.stream().map(u -> {
            MomentTimeLineEntity momentTimeLineEntity = new MomentTimeLineEntity();
            momentTimeLineEntity.setMomentId(momentId);
            momentTimeLineEntity.setMomentUserId(userId);
            momentTimeLineEntity.setUserId(u);
            momentTimeLineEntity.setTime(now);
            momentTimeLineEntity.setDeleted(false);
            return momentTimeLineEntity;
        }).collect(Collectors.toList());
        /**
         * 加入自己和好友的动态时间线
         */
        momentTimeLineDAO.saveAll(saveTimeLines);
        /**
         * 加入自己和好友的动态时间线缓存
         */
        addUserMomentTimeLineCache(saveTimeLines);
    }

    /**
     * 加入缓存
     *
     * @param saveTimeLines
     */
    private void addUserMomentTimeLineCache(List<MomentTimeLineEntity> saveTimeLines) {
        RedisKeyEnum keyEnum = RedisKeyEnum.MOMENT_TIME_LINE_CACHE;
        for (MomentTimeLineEntity timeLineEntity : saveTimeLines) {
            String key = keyEnum.getKey(timeLineEntity.getUserId());
            redisService.zadd(key, String.valueOf(timeLineEntity.getMomentId()), timeLineEntity.getMomentId(), keyEnum.getExpireTime());
        }
    }

    public List<MomentResponseDetailVO> getUserMomentListFromTimeLineCache(String userId, int size, Long lastId) {
        String key = RedisKeyEnum.MOMENT_TIME_LINE_CACHE.getKey(userId);
        Set<String> momentIds = redisService.zreverseRangeByScore(key, lastId, 0, size);
        return this.batchGetMomentVoFromCache(momentIds);
    }

    /***
     * 批量查询动态缓存
     * @param cacheSet
     * @return
     */
    private List<MomentResponseDetailVO> batchGetMomentVoFromCache(Set<String> cacheSet) {
        List<MomentResponseDetailVO> communityResponseDetailVOList = new ArrayList<>();
        if (CollectionUtils.isEmpty(cacheSet)) {
            return Lists.newArrayList();
        }
        List<Long> cacheKeyLongs = cacheSet.stream().map(Long::valueOf).collect(Collectors.toList());
        List<String> cacheKeys = cacheSet.stream().map(k ->
                RedisKeyEnum.MOMENT_DETAIL_CACHE.getKey(String.valueOf(k))).collect(Collectors.toList());
        Map<String, String> multiResultMap = redisService.mgetAndParseMap(cacheKeys);
        List<String> keys = new ArrayList<>(cacheSet);
        List<String> userNameList = new ArrayList<>();
        List<Long> resourceIdList = new ArrayList<>();
        for (int i = 0; i < keys.size(); i++) {
            String id = keys.get(i);
            String cacheKey = cacheKeys.get(i);
            String cacheValue = multiResultMap.get(cacheKey);
            MomentResponseDetailVO momentResponseDetailVO;
            if (StringUtils.isNotBlank(cacheValue)) {
                momentResponseDetailVO = JsonUtil.fromJson(cacheValue, MomentResponseDetailVO.class);
            } else {
                momentResponseDetailVO = this.getCommunityDetailFromCache(Long.valueOf(id));
            }
            resourceIdList.add(Long.valueOf(id));
            if (momentResponseDetailVO != null) {
                userNameList.add(momentResponseDetailVO.getAuthor());
                momentResponseDetailVO.setClickCount(momentResponseDetailVO.getClickCount() == null ? 0L : momentResponseDetailVO.getClickCount());
                communityResponseDetailVOList.add(momentResponseDetailVO);
            }
        }
        // 批量查询评论量
        Map<Long, Long> commentCountMap = commentService.batchGetCommentCountFromCache(resourceIdList, ResourceTypeEnum.MOMENT.getType());
        // 批量查询点赞量
        AbstractResourceBehaviorService likeService =
                ResourceBehaviorFactory.getBehaviorService(ResourceBehaviorTypeEnum.LIKE.getBehavior());
        Map<Long, Long> likeCountMap = likeService.getBehaviorCountFromCache(ResourceTypeEnum.MOMENT.getType(), cacheKeyLongs);
        // 批量查询用户是否点赞
        Map<Long, Boolean> isLikeMap = new HashMap<>();
        String currentUserId = userService.getLoginCurrentUserId();
        if (org.apache.commons.lang3.StringUtils.isNotBlank(currentUserId)) {
            isLikeMap = likeService.getIsBehaviorFromCache(ResourceTypeEnum.MOMENT.getType(), cacheKeyLongs, currentUserId);
        }
        // 批量查询点赞用户列表
        Map<Long, Map<String, Long>> likeUsersMap =
                likeService.getBehaviorUsersFromCache(ResourceTypeEnum.MOMENT.getType(), cacheKeyLongs, DEFAULT_DISPLAY_LIKE_USERS_COUNT);
        if (!MapUtils.isEmpty(likeCountMap)) {
            for (Map<String, Long> userLikeMap : likeUsersMap.values()) {
                if (MapUtils.isNotEmpty(userLikeMap)) {
                    userNameList.addAll(userLikeMap.keySet());
                }
            }
        }
        // 批量查询用户信息
        Map<String, UserBaseResponseInfoVO> userBaseResponseInfoVOMap = userService.batchGetUserInfoFromCache(userNameList);
        for (MomentResponseDetailVO communityResponseDetailVO : communityResponseDetailVOList) {
            Long cid = communityResponseDetailVO.getId();
            communityResponseDetailVO.setCommentCount(commentCountMap.get(cid));
            communityResponseDetailVO.setLikeCount(likeCountMap.getOrDefault(cid, 0L));
            communityResponseDetailVO.setIsLike(isLikeMap.getOrDefault(cid, false));
            communityResponseDetailVO.setUserInfo(userBaseResponseInfoVOMap.get(communityResponseDetailVO.getAuthor()));
            Map<String, Long> userLikeMap = likeUsersMap.get(cid);
            communityResponseDetailVO.setLikeUsers(new ArrayList<>());
            if (MapUtils.isNotEmpty(userLikeMap)) {
                List<UserBaseResponseInfoVO> likeUserInfos =
                        userLikeMap.keySet().stream().map(uid -> userBaseResponseInfoVOMap.get(uid)).filter(user -> user != null).collect(
                                Collectors.toList());
                communityResponseDetailVO.setLikeUsers(likeUserInfos);
            }
        }
        return communityResponseDetailVOList;
    }

    /***
     * 删除内容，刷新缓存数据
     */
    public void refreshCommunityAboutCacheByDelete(MomentEntity entity, String userId) {


    }

    @Override
    public Map<String, MessageResourceVO> batchGetMessResource(List<String> resourceIdList) {
        return new HashMap<>();
    }

    private MomentResponseBaseVO refreshMomentCache(Long id) {
        MomentEntity entity = momentDAO.findAllById(id);
        return refreshMomentDetailCache(entity);
    }

    /***
     * 刷新动态详情缓存
     * @param entity
     * @return
     */
    public MomentResponseBaseVO refreshMomentDetailCache(MomentEntity entity) {
        if(entity == null) {
            return null;
        }
        MomentResponseBaseVO momentResponseBaseVO = MomentEntityConvert.convertVo(entity);
        String key = RedisKeyEnum.MOMENT_DETAIL_CACHE.getKey(entity.getId().toString());
        redisService.set(key, JsonUtil.toJsonString(momentResponseBaseVO), RedisKeyEnum.MOMENT_DETAIL_CACHE.getExpireTime());
        return momentResponseBaseVO;
    }

    /**
     * 查询社区内容详情
     * @param id
     * @return
     */
    public MomentResponseDetailVO getCommunityDetailFromCache(Long id) {
        String key = RedisKeyEnum.MOMENT_DETAIL_CACHE.getKey(id.toString());
        String val = redisService.get(key);
        MomentResponseDetailVO detailVO = new MomentResponseDetailVO();
        if (StringUtils.isBlank(val)) {
            MomentResponseBaseVO communityResponseBaseVO = refreshMomentCache(id);
            if (communityResponseBaseVO == null) {
                return null;
            }
            BeanUtils.copyProperties(communityResponseBaseVO, detailVO);
        } else {
            detailVO = JsonUtil.fromJson(val, MomentResponseDetailVO.class);
        }
        detailVO.setClickCount(detailVO.getClickCount() == null ? 0L : detailVO.getClickCount());
        detailVO.setCommentCount(commentService.getCommentCountFromCache(id, ResourceTypeEnum.MOMENT.getType()));
        List<Long> cacheKeyLongs = Arrays.asList(id);
        // 批量查询点赞量
        AbstractResourceBehaviorService likeService =
                ResourceBehaviorFactory.getBehaviorService(ResourceBehaviorTypeEnum.LIKE.getBehavior());
        Map<Long, Long> likeCountMap = likeService.getBehaviorCountFromCache(ResourceTypeEnum.MOMENT.getType(), cacheKeyLongs);
        // 批量查询用户是否点赞
        Map<Long, Boolean> isLikeMap = new HashMap<>();
        String currentUserId = userService.getLoginCurrentUserId();
        if (org.apache.commons.lang3.StringUtils.isNotBlank(currentUserId)) {
            isLikeMap = likeService.getIsBehaviorFromCache(ResourceTypeEnum.MOMENT.getType(), cacheKeyLongs, currentUserId);
        }
        List<String> userNameList = new ArrayList<>();
        userNameList.add(detailVO.getAuthor());
        // 批量查询点赞用户列表
        Map<Long, Map<String, Long>> likeUsersMap =
                likeService.getBehaviorUsersFromCache(ResourceTypeEnum.MOMENT.getType(), cacheKeyLongs, DEFAULT_DISPLAY_LIKE_USERS_COUNT);
        if (!MapUtils.isEmpty(likeCountMap)) {
            for (Map<String, Long> userLikeMap : likeUsersMap.values()) {
                if (MapUtils.isNotEmpty(userLikeMap)) {
                    userNameList.addAll(userLikeMap.keySet());
                }
            }
        }
        // 批量查询用户信息
        Map<String, UserBaseResponseInfoVO> userBaseResponseInfoVOMap = userService.batchGetUserInfoFromCache(userNameList);
        detailVO.setUserInfo(userBaseResponseInfoVOMap.get(detailVO.getAuthor()));
        detailVO.setLikeCount(likeCountMap.getOrDefault(id, 0L));
        detailVO.setIsLike(isLikeMap.getOrDefault(id, false));
        Map<String, Long> userLikeMap = likeUsersMap.get(id);
        detailVO.setLikeUsers(new ArrayList<>());
        if (MapUtils.isNotEmpty(userLikeMap)) {
            List<UserBaseResponseInfoVO> likeUserInfos =
                    userLikeMap.keySet().stream().map(uid -> userBaseResponseInfoVOMap.get(uid)).filter(user -> user != null).collect(
                            Collectors.toList());
            detailVO.setLikeUsers(likeUserInfos);
        }
        return detailVO;
    }
}
