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

import com.apobates.forum.core.dao.BoardTopicCategoryIndexDao;
import com.apobates.forum.core.dao.TopicCategoryDao;
import com.apobates.forum.core.entity.BoardTopicCategoryIndex;
import com.apobates.forum.core.entity.TopicCategory;
import com.apobates.forum.core.service.BoardTopicCategoryIndexService;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 *
 * @author xiaofanku
 * @since 20200525
 */
@Service
public class BoardTopicCategoryIndexServiceImpl implements BoardTopicCategoryIndexService{
    @Autowired
    private BoardTopicCategoryIndexDao boardTopicCategoryIndexDao;
    @Autowired
    private TopicCategoryDao topicCategoryDao;
    private final static Logger logger = LoggerFactory.getLogger(BoardTopicCategoryIndexServiceImpl.class);
    
    @Override
    public int deleteForTopic(long boardId, List<Integer> categoryIds) {
        if (null == categoryIds || categoryIds.isEmpty()) {
            return 0;
        }
        return boardTopicCategoryIndexDao.delete(boardId, categoryIds);
    }
    
    @Override
    public int create(int boardGroundId, long boardId, List<Integer> categoryIds) {
        if (null == categoryIds || categoryIds.isEmpty()) {
            return 0;
        }
        List<BoardTopicCategoryIndex> entities = categoryIds.stream().map(cateId->new BoardTopicCategoryIndex(boardGroundId, boardId, cateId)).collect(Collectors.toList());
        try{
            return boardTopicCategoryIndexDao.batchSave(entities);
        }catch(Exception e){
            if(logger.isDebugEnabled()){
                logger.debug("批量关联版块类型失败", e);
            }
        }
        return -1;
    }
    
    @Override
    public Stream<TopicCategory> getAllByBoard(final int boardGroupId, final long boardId) {
        return getAllByBoardAsync(boardGroupId, boardId).orTimeout(1, TimeUnit.SECONDS).join();
    }
    
    @Override
    public Stream<TopicCategory> getAllByBoardTopicCategories(final int boardGroupId, final long boardId) {
        CompletableFuture<Set<TopicCategory>> relatived = getAllByBoardAsync(boardGroupId, boardId).thenApply(tcs->tcs.collect(Collectors.toSet())).completeOnTimeout(Collections.emptySet(), 1, TimeUnit.SECONDS);
        CompletableFuture<Set<TopicCategory>> allCategories = CompletableFuture.supplyAsync(()->topicCategoryDao.findUsed()).thenApply(tcs->tcs.collect(Collectors.toSet())).completeOnTimeout(Collections.emptySet(), 1, TimeUnit.SECONDS);
        return relatived.thenCombine(allCategories, (r, ar)->{
           Set<TopicCategory> result = (null == r || r.isEmpty())?ar:r;
           result.add(TopicCategory.empty());
           return result;
        }).orTimeout(1, TimeUnit.SECONDS).join().stream();
    }
    
    @Override
    public Optional<BoardTopicCategoryIndex> getReportRelativeRecord() {
        List<BoardTopicCategoryIndex> rs = boardTopicCategoryIndexDao.findAllByCategory(TopicCategory.report().getId()).collect(Collectors.toList());
        if (null == rs || rs.isEmpty()) {
            return Optional.empty();
        }
        if (rs.size() > 1) {
            return Optional.empty();
        }
        return Optional.ofNullable(rs.get(0));
    }
    
    @Override
    public Optional<BoardTopicCategoryIndex> getFeedbackRelativeRecord() {
        List<BoardTopicCategoryIndex> rs = boardTopicCategoryIndexDao.findAllByCategory(TopicCategory.feedback().getId()).collect(Collectors.toList());
        if (null == rs || rs.isEmpty()) {
            return Optional.empty();
        }
        if (rs.size() > 1) {
            return Optional.empty();
        }
        return Optional.ofNullable(rs.get(0));
    }
    
    @Override
    public Set<Integer> getAllRelativeRecords() {
        return boardTopicCategoryIndexDao.findAllByCategory(List.of(TopicCategory.report().getId(), TopicCategory.feedback().getId())).map(BoardTopicCategoryIndex::getCategoryId).collect(Collectors.toSet());
    }
    private CompletableFuture<Stream<TopicCategory>> getAllByBoardAsync(final int boardGroupId, final long boardId) {
        return CompletableFuture.supplyAsync(()->boardTopicCategoryIndexDao.findAll(boardId, boardGroupId)).completeOnTimeout(Stream.empty(), 1, TimeUnit.SECONDS);
    }
}