package com.apobates.forum.core.impl.service;

import com.apobates.forum.core.MoodCollectResult;
import com.apobates.forum.core.dao.PostsDao;
import com.apobates.forum.core.dao.PostsMoodRecordsDao;
import com.apobates.forum.core.entity.Posts;
import com.apobates.forum.core.entity.PostsMoodRecords;
import com.apobates.forum.core.impl.ActionDescriptor;
import com.apobates.forum.core.impl.event.PostsMoodEvent;
import com.apobates.forum.core.service.PostsMoodRecordsService;
import com.apobates.forum.event.elderly.ActionEventCulpritor;
import com.apobates.forum.event.elderly.ForumActionEnum;
import com.apobates.forum.utils.Commons;
import com.apobates.forum.utils.persistence.Page;
import com.apobates.forum.utils.persistence.Pageable;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.github.davidmarquis.redisq.producer.MessageProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

/**
 *
 * @author xiaofanku
 * @since 20200527
 */
@Service
public class PostsMoodRecordsServiceImpl implements PostsMoodRecordsService{
    @Autowired
    private PostsMoodRecordsDao postsMoodRecordsDao;
    @Autowired
    private PostsDao postsDao;
    @Autowired @Qualifier("postsMoodProducer")
    private MessageProducer<PostsMoodEvent> postsMoodProducer;
    private final static Logger logger = LoggerFactory.getLogger(PostsMoodRecordsServiceImpl.class);
    
    @Override
    public Page<PostsMoodRecords> getAllByPosts(long postsId, Pageable pageable) {
        return postsMoodRecordsDao.findAllByPosts(postsId, pageable);
    }
    
    @Override
    public Stream<PostsMoodRecords> getByPosts(long postsId, boolean liked) {
        return postsMoodRecordsDao.findAllByMood(postsId, liked);
    }
    
    @Override
    public List<MoodCollectResult> getByTopic(final long topicId, final int page, final int pageSize) {
        CompletableFuture<Set<Long>> postsIdSet = CompletableFuture.supplyAsync(()->postsDao.findAllByTopic(topicId, page, pageSize)).thenApply(ps->ps.map(Posts::getId).collect(Collectors.toSet())).completeOnTimeout(Collections.emptySet(), 1, TimeUnit.SECONDS);
        final Map<Long, Map<Boolean, Long>> rs = postsIdSet.thenCompose(pids->CompletableFuture.supplyAsync(()->postsMoodRecordsDao.collectMembers(pids)).completeOnTimeout(Collections.emptyMap(), 1, TimeUnit.SECONDS)).orTimeout(1, TimeUnit.SECONDS).join();
        return foldMoodCollectResult(rs, topicId);
    }
    
    @Override
    public List<MoodCollectResult> getByPosts(long topicId, Set<Long> postsIdSet) {
        if (topicId == 0 || null == postsIdSet || postsIdSet.isEmpty()) {
            return Collections.emptyList();
        }
        Map<Long, Map<Boolean, Long>> rs = postsMoodRecordsDao.collectMembers(postsIdSet);
        return foldMoodCollectResult(rs, topicId);
    }
    @ActionDescriptor(action=ForumActionEnum.POSTS_LIKED, isBool=false)
    @Override
    public long toggleMoodRecord(long id, long topicId, boolean like, ActionEventCulpritor culpritor) {
        //不能重复操作
        Optional<Boolean> moodStats = postsMoodRecordsDao.removeMoodRecord(id, culpritor.getMemberId());
        if (moodStats.isPresent()) {
            //已经点过了都表示删除
            return -1L;
        }
        PostsMoodRecords pmr = new PostsMoodRecords();
        pmr.setPostsId(id);
        pmr.setTopicId(topicId);
        pmr.setLiked(like);
        pmr.setMemberId(culpritor.getMemberId());
        pmr.setMemberNickname(culpritor.getMemberNickname());
        pmr.setEntryDateTime(LocalDateTime.now());
        
        try {
            postsMoodRecordsDao.save(pmr);
            if (pmr.getId() > 0) {
                postsMoodProducer.create(new PostsMoodEvent(pmr)).submit();
                return pmr.getId();
            }
        } catch (Exception e) {
            if(logger.isDebugEnabled()){
                logger.debug("回复喜好记录创建失败", e);
            }
        }
        return 0L;
    }
    private List<MoodCollectResult> foldMoodCollectResult(final Map<Long, Map<Boolean, Long>> mrStats, final long topicId){
        BiFunction<Long, Map<Boolean, Long>, MoodCollectResult> bi = (postsId, moodStats)->{
            long likes = Commons.optional(moodStats.getOrDefault(true, 0L), 0L), hates = Commons.optional(moodStats.getOrDefault(false, 0L), 0L);
            return new MoodCollectResult(topicId, postsId, likes, hates);
        };
        return mrStats.keySet().parallelStream().map((postsId)->bi.apply(postsId, mrStats.get(postsId))).collect(Collectors.toList());
    }
}