package com.apobates.forum.core.api.dao;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Stream;
import com.apobates.forum.core.entity.Album;
import com.apobates.forum.core.entity.ForumEntityStatusEnum;
import com.apobates.forum.core.entity.Posts;
import com.apobates.forum.core.entity.Topic;
import com.apobates.forum.core.entity.TopicTag;
import com.apobates.forum.utils.persistence.Page;
import com.apobates.forum.utils.persistence.Pageable;
import com.apobates.forum.utils.persistence.PagingAndSortingRepository;

/**
 * 话题的持久层接口
 * 
 * @author xiaofanku
 * @since 20190326
 */
public interface TopicDao extends PagingAndSortingRepository<Topic, Long> {
	/**
	 * 更新话题的状态枚举
	 * 
	 * @param id     话题ID
	 * @param status 更新的状态枚举
	 * @return
	 */
	Optional<Boolean> editStatus(long id, ForumEntityStatusEnum status);
	
	/**
	 * 更新话题的标题
	 * 
	 * @param id               话题ID
	 * @param updateTopicTitle 更新的话题主题
	 * @return
	 */
	Optional<Boolean> editTitle(long id, String updateTopicTitle);
	
	/**
	 * 更新话题的置顶状态
	 * 
	 * @param id       话题ID
	 * @param topValue 更新的置顶状态值
	 * @return
	 */
	Optional<Boolean> editTop(long id, boolean topValue);

	/**
	 * 更新话题的精华状态
	 * 
	 * @param id         话题ID
	 * @param goodsValue 更新的精华状态值
	 * @return
	 */
	Optional<Boolean> editGoods(long id, boolean goodsValue);
	
	/**
	 * 更新话题的像册ID
	 * 
	 * @param id      话题ID
	 * @param albumId 像册ID
	 * @return
	 */
	Optional<Boolean> editAlbum(long id, long albumId);
	
	/**
	 * 更新话题的排序日期
	 * 
	 * @param id             话题ID
	 * @param updateDateTime 更新的日期
	 * @return
	 */
	Optional<Boolean> updateRankingDate(long id, LocalDateTime updateDateTime);
	
	/**
	 * 移除话题关联的像册
	 * 
	 * @param id 话题ID
	 * @return
	 */
	boolean removeAlbum(long id);
	
	/**
	 * 移动话题到目标版块
	 * 
	 * @param id                 话题ID
	 * @param targetBoardId      目标版块ID
	 * @param targetBoardGroupId 目标版块所在版块组(卷)ID
	 * @return 成功返回话题的回复数, -1话题移到目标版块失败,-2绑定话题统计到目标版块失败,-3更新话题的回复为目标版块失败
	 */
	int moveTopic(long id, long targetBoardId, int targetBoardGroupId)throws IllegalStateException;
	
	/**
	 * 移除子栏目中指定的文章
	 * @since 20200427
	 * @param id     子栏目的文章ID
	 * @param termId 子栏目的ID
	 * @return
	 */
	Optional<Boolean> removeTermArticle(long id, long termId);
	
	/**
	 * 查看指定版块下的所有话题,不包括删除,置顶;包括加精,普通
	 * 
	 * @param boardId  版块ID
	 * @param pageable 分页请求参数
	 * @return
	 */
	Page<Topic> findAllByBoard(long boardId, Pageable pageable);
	
	/**
	 * 
	 * @param boardId       版块ID
	 * @param categoryValue 话题类型的Key(Topic.topicCategoryValue = TopicCategory.value)
	 * @param pageable      分页请求参数
	 * @return
	 */
	Page<Topic> findAllByBoard(long boardId, String categoryValue, Pageable pageable);
	
	/**
	 * [会员发布的话题]查看指定会员发布的话题,不计状态
	 * 
	 * @param memberId 会员ID
	 * @param pageable 分页请求参数
	 * @return
	 */
	Page<Topic> findAllByMember(long memberId, Pageable pageable);
	long findAllByMemberCount(long memberId);
	
	/**
	 * [会员回复的话题]查看指定会员回复的话题,不包含话题的作者是该会员
	 * 
	 * @param memberId 会员ID
	 * @param pageable 分页请求参数
	 * @return
	 */
	Page<Topic> findAllByMemberReply(long memberId, Pageable pageable);
	long findAllByMemberReplyCount(long memberId);
	
	/**
	 * 查看指定子栏目下的所有文章
	 * @since 20200427
	 * @param termId   子栏目ID
	 * @param pageable 分页请求参数
	 * @return
	 */
	Page<Topic> findAllTermArticle(long termId, Pageable pageable);
	
	/**
	 * 根据标签 查看相关的话题
	 * 
	 * @param tages    标签名集合
	 * @param pageable 分页请求参数
	 * @return
	 */
	Page<Topic> findAllByTag(Collection<String> tagNames, Pageable pageable);
	
	/**
	 * 查看指定版块最近的话题,不包括删除;置顶;包括加精,普通;以rankingDateTime倒序
	 * 
	 * @param boardId 版块ID
	 * @param size    显示的数量
	 * @return
	 */
	Stream<Topic> findAllByBoard(long boardId, int size);
	
	/**
	 * 查看指定版块最近的话题,忽略状态;以entryDateTime倒序
	 * 
	 * @param boardId 版块ID
	 * @param size    显示的数量
	 * @return
	 */
	Stream<Topic> findAllByBoardIgnoreStatus(long boardId, int size);
	
	/**
	 * [版块新话题推送]自参考日期以后版块最近的话题
	 * 
	 * @param boardId  版块ID
	 * @param prevDate 参考日期
	 * @return
	 */
	Stream<Topic> findAllRecentByBoard(long boardId, LocalDateTime prevDate);
	
	/**
	 * 查看指定版块置顶的话题,不包括删除的
	 * 
	 * @param boardId 版块ID
	 * @return
	 */
	Stream<Topic> findAllByBoardOfTop(long boardId);

	/**
	 * [会员中心x.html]查看指定会员最近发布的话题,不包含删除的.按发布日期排序
	 * 
	 * @param memberId 会员ID
	 * @param size     显示的数量
	 * @return
	 */
	Stream<Topic> findAllByMember(long memberId, int size);

	/**
	 * [会员中心x.html]查看指定会员最近回复的话题,不包含话题的作者是该会员
	 * 
	 * @param memberId 会员ID
	 * @param size     显示的数量
	 * @return
	 */
	Stream<Topic> findAllByMemberReply(long memberId, int size);

	/**
	 * 查看会员发布的受欢迎的话题列表
	 * 
	 * @param memberId 会员ID
	 * @param size     显示的数量
	 * @return
	 */
	Stream<Topic> findAllByMemberPopular(long memberId, int size);
	
	/**
	 * [站内动态]查看最近的话题,不包括删除的,不包含1号版块的
	 * 
	 * @param size 显示的数量
	 * @return
	 */
	Stream<Topic> findAllOfRecent(int size);
	
	/**
	 * [后台最近话题]查看最近的话题,忽略状态
	 * 
	 * @param size 显示的数量
	 * @return
	 */
	Stream<Topic> findAllOfRecentIgnoreCondition(int size);
	
	/**
	 * 查看指定版块组最近发布的话题,不包括删除的
	 * 
	 * @param boardGroupId 版块组(卷)ID
	 * @param size         显示的数量
	 * @return
	 */
	Stream<Topic> findAllOfRecent(int boardGroupId, int size);
	
	/**
	 * 查看指定版块组的精华话题,不包含删除的
	 * 
	 * @param boardGroupId 版块组(卷)ID
	 * @param size         显示的数量
	 * @return
	 */
	Stream<Topic> findAllByBoardGroupOfGoods(int boardGroupId, int size);
	
	/**
	 * 按回复日期查看指定数量的话题
	 * 
	 * @param size 显示的数量
	 * @return
	 */
	Stream<Topic> findAllByReplyDate(int size);
	
	/**
	 * 查看指定版块发布的话题,最先发布的排在最前面(Topic.entryDateTime ASC)
	 * 
	 * @param boardId 版块ID
	 * @param status  话题的状态
	 * @return
	 */
	Stream<Topic> findAllByBoard(long boardId, ForumEntityStatusEnum status);
	
	/**
	 * 查看子栏目最近发布的文章
	 * @since 20200427
	 * @param size 显示的数量
	 * @return
	 */
	Stream<Topic> findAllOfRecentTermArticle(int size);
	
	/**
	 * 查看指定版块组中回复最多的话题,不包含删除的
	 * 回复的数量使用ranking属性
	 * 
	 * @param boardGroupId 版块组(卷)ID
	 * @param size         显示的数量
	 * @return
	 */
	List<Topic> findAllByBoardGroupByMaxReply(int boardGroupId, int size);
	
	/**
	 * 查看回复最多的话题
	 * 
	 * @param size 显示的数量
	 * @return
	 */
	List<Topic> findAllByMaxReply(int size);
	
	/**
	 * 查看指定的话题
	 * @param idList 话题ID列表
	 * @return
	 */
	List<Topic> findAllById(Collection<Long> idList);
	
	/**
	 * 级联加载版块组(卷), 版块
	 * 
	 * @param id 话题ID
	 * @return
	 */
	Topic findOneForIndex(long id);
	
	/**
	 * 查看栏目中的第一篇文章
	 * @since 20200427
	 * @param termId 子栏目ID
	 * @return
	 */
	Optional<Topic> findOneArticleForTerm(long termId);
	
	/**
	 * 查看子栏目中指定文章的下一篇
	 * @since 20200427
	 * @param termId    子栏目ID
	 * @param articleId 文章ID
	 * @return
	 */
	Optional<Topic> findNextTermArticle(long termId, long articleId);
	
	/**
	 * 查看子栏目中指定文章的上一篇
	 * @since 20200427
	 * @param termId    子栏目ID
	 * @param articleId 文章ID
	 * @return
	 */
	Optional<Topic> findPrevTermArticle(long termId, long articleId);
	
	/**
	 * 统计版块在指定日期的话题数量
	 * 
	 * @param start  开始日期
	 * @param finish 结束日期
	 * @return Key=版块ID, Value=发布的话题合计,不计状态
	 */
	Map<Long,Long> statsBoardTopicSize(LocalDateTime start, LocalDateTime finish);
	
	/**
	 * 分组统计指定日期范围内的每日话题数量
	 * 
	 * @param start  开始日期
	 * @param finish 结束日期
	 * @return Key=YYYY-MM-DD, Value=话题数量
	 */
	TreeMap<String,Long> groupTopicSize(LocalDateTime start, LocalDateTime finish);
	
	/**
	 * 统计版块在指定日期的话题数量
	 * 
	 * @param boardId 版块ID
	 * @param start   开始日期
	 * @param finish  结束日期
	 * @return
	 */
	long statsBoardTopicSize(long boardId, LocalDateTime start, LocalDateTime finish);
	
	/**
	 * 分组统计不同状态的话题数量
	 * 
	 * @return Key=Topic.status, Value=话题数量
	 */
	EnumMap<ForumEntityStatusEnum,Long> groupTopicesForStatus();
	
	/**
	 * 分组统计不同分类的话题数量
	 * 
	 * @return Key=Topic.topicCategoryName, Value=话题数量
	 */
	Map<String,Long> groupTopicesForCategory();
	
	/**
	 * 分组统计不同版块的话题数量,版块统计内有此数据
	 * 
	 * @return Key=Topic.boardId, Value=话题数量
	 */
	Map<Long,Long> groupTopicesForBoard();
	
	/**
	 * 
	 * @param entity
	 * @param posts
	 * @param album
	 * @return
	 */
	Optional<Topic> pushTopic(Topic entity, Posts posts, Album album);
	
	/**
	 * 
	 * @param topicId
	 * @param title
	 * @param content
	 * @param album
	 * @param tags
	 * @param modifyMember
	 * @param modifyMemberNickname
	 */
	void modifyTopic(long topicId, String title, String content, Album album, Set<TopicTag> tags, long modifyMember, String modifyMemberNickname);
}
