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

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.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.apobates.forum.core.MoodCollectResult;
import com.apobates.forum.core.api.dao.PostsDao;
import com.apobates.forum.core.api.dao.PostsMoodRecordsDao;
import com.apobates.forum.core.api.service.PostsMoodRecordsService;
import com.apobates.forum.core.entity.Posts;
import com.apobates.forum.core.entity.PostsMoodRecords;
import com.apobates.forum.core.impl.event.ForumEventPublisher;
import com.apobates.forum.core.impl.event.PostsMoodEvent;
import com.apobates.forum.event.elderly.ActionDescriptor;
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;

@Service
public class PostsMoodRecordsServiceImpl implements PostsMoodRecordsService{
	@Autowired
	private PostsMoodRecordsDao postsMoodRecordsDao;
	@Autowired
	private PostsDao postsDao;
	@Autowired
	private ForumEventPublisher forumEventPublisher;
	
	@ActionDescriptor(action=ForumActionEnum.POSTS_LIKED, isRedress=false)
	@Override
	public long toggleMoodRecord(long id, long topicId, boolean liked, ActionEventCulpritor culpritor)throws IllegalStateException {
		//不能重复操作
		Optional<Boolean> moodStats = postsMoodRecordsDao.removeMoodRecord(id, culpritor.getMemberId());
		if(moodStats.isPresent()){
			//已经点过了都表示删除
			return 0;
		}
		PostsMoodRecords pmr = new PostsMoodRecords();
		pmr.setPostsId(id);
		pmr.setTopicId(topicId);
		pmr.setLiked(liked);
		pmr.setMemberId(culpritor.getMemberId());
		pmr.setMemberNickname(culpritor.getMemberNickname());
		pmr.setEntryDateTime(LocalDateTime.now());
		
		try{
			postsMoodRecordsDao.save(pmr);
			if(pmr.getId()>0){
				forumEventPublisher.publishPostsLikeEvent(new PostsMoodEvent(this, pmr));
				return pmr.getId();
			}
		}catch(Exception e){
			throw new IllegalStateException(e.getMessage());
		}
		throw new IllegalStateException("创建失败");
	}

	@Override
	public Stream<PostsMoodRecords> getByPosts(long postsId, boolean like) {
		return postsMoodRecordsDao.findAllByMood(postsId, like);
	}

	@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()));
		final Map<Long, Map<Boolean, Long>> rs = postsIdSet.thenCompose(pids -> CompletableFuture.supplyAsync(() -> postsMoodRecordsDao.collectMembers(pids))).join();
		return foldMoodCollectResult(rs, topicId);
	}

	@Override
	public Page<PostsMoodRecords> getAllByPosts(long postsId, Pageable pageable) {
		return postsMoodRecordsDao.findAllByPosts(postsId, pageable);
	}

	@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);
	}

	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());
	}
}
