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

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.EnumMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.apobates.forum.core.api.dao.BoardStatsDao;
import com.apobates.forum.core.entity.BoardStats;
import com.apobates.forum.event.elderly.ForumActionEnum;


@Repository
public class BoardStatsDaoImpl implements BoardStatsDao{
	@PersistenceContext
	private EntityManager entityManager;
	private final static Logger logger = LoggerFactory.getLogger(BoardStatsDaoImpl.class);
	
	@Transactional(propagation = Propagation.REQUIRED)
	@Override
	public void save(BoardStats entity) {
		entityManager.persist(entity);
	}

	@Override
	public Optional<BoardStats> findOne(Long primaryKey) {
		return Optional.empty();
	}

	@Override
	public Optional<Boolean> edit(BoardStats updateEntity) {
		return Optional.empty();
	}

	@Override
	public Stream<BoardStats> findAll() {
		return entityManager.createQuery("SELECT bs FROM BoardStats bs", BoardStats.class).getResultStream();
	}

	@Override
	public long count() {
		return -1L;
	}
	
	@Override
	public Optional<BoardStats> findOneByBoard(long boardId) {
		try {
			BoardStats bs = entityManager.createQuery("SELECT bs FROM BoardStats bs WHERE bs.boardId = ?1", BoardStats.class).setParameter(1, boardId).getSingleResult();
			return Optional.ofNullable(bs);
		}catch(javax.persistence.NoResultException e) {
			if(logger.isDebugEnabled()){
				logger.debug(e.getMessage(), e);
			}
		}
		return Optional.empty();
	}
	
	@Transactional(propagation = Propagation.REQUIRED)
	@Override
	public Optional<Boolean> updateTopic(
			long boardId, 
			String recentTopicTitle, 
			long recentTopicId,
			LocalDateTime recentTopicDate, 
			long recentTopicMemberId, 
			String recentTopicMemberNickname) {
		try{
			int affect = entityManager.createQuery("UPDATE BoardStats bs SET bs.topices = bs.topices + 1, bs.recentTopicTitle = ?1, bs.recentTopicId = ?2, bs.recentTopicDate = ?3, bs.recentTopicMemberId = ?4, bs.recentTopicMemberNickname = ?5, bs.updateDate = ?6 WHERE bs.boardId = ?7")
					.setParameter(1, recentTopicTitle)
					.setParameter(2, recentTopicId)
					.setParameter(3, recentTopicDate)
					.setParameter(4, recentTopicMemberId)
					.setParameter(5, recentTopicMemberNickname)
					.setParameter(6, LocalDateTime.now())
					.setParameter(7, boardId)
					.executeUpdate();
			return affect == 1?Optional.of(true):Optional.empty();
		}catch(Exception e) {
			if(logger.isDebugEnabled()){
				logger.debug(e.getMessage(), e);
			}
		}
		return Optional.empty();
	}
	
	@Transactional(propagation = Propagation.REQUIRED)
	@Override
	public Optional<Boolean> updatePosts(long boardId) {
		try{
			int affect = entityManager.createQuery("UPDATE BoardStats bs SET bs.postses = bs.postses + 1, bs.updateDate = ?1 WHERE bs.boardId = ?2")
					.setParameter(1, LocalDateTime.now())
					.setParameter(2, boardId)
					.executeUpdate();
			return affect == 1?Optional.of(true):Optional.empty();
		}catch(Exception e) {
			if(logger.isDebugEnabled()){
				logger.debug(e.getMessage(), e);
			}
		}
		return Optional.empty();
	}
	
	@Transactional(propagation = Propagation.REQUIRED)
	@Override
	public Optional<Boolean> createStats(long boardId, int volumesId) {
		try {
			entityManager.persist(new BoardStats(boardId, volumesId));
			return Optional.of(true);
		}catch(Exception e) {
			if(logger.isDebugEnabled()){
				logger.debug(e.getMessage(), e);
			}
		}
		return Optional.empty();
	}
	
	@Transactional(propagation = Propagation.REQUIRED)
	@Override
	public Optional<Boolean> plusFavorites(long boardId, long memberId) {
		try{
			int affect = entityManager.createQuery("UPDATE BoardStats bs SET bs.favorites = bs.favorites + 1, bs.updateDate = ?1 WHERE bs.boardId = ?2")
					.setParameter(1, LocalDateTime.now())
					.setParameter(2, boardId)
					.executeUpdate();
			try{
				//为下次取消收藏清路
				entityManager.createNativeQuery("DELETE FROM apo_action_event_set WHERE `TYPE` = ?1 AND `ACTION` = ?2 AND MEMBERID = ?3 AND BOARDID = ?4")
					.setParameter(1, "B")
					.setParameter(2, "BOARD_FAVORITE_CANCEL")
					.setParameter(3, memberId)
					.setParameter(4, boardId)
					.executeUpdate();
			}catch(Exception e){
				logger.info("[BoardStatsDao]favorite plus has exception:"+e.getMessage());
			}
			return affect == 1?Optional.of(true):Optional.empty();
		}catch(Exception e) {
			if(logger.isDebugEnabled()){
				logger.debug(e.getMessage(), e);
			}
		}
		return Optional.empty();
	}
	
	@Transactional(propagation = Propagation.REQUIRED)
	@Override
	public Optional<Boolean> negateFavorites(long boardId, long memberId) {
		try{
			int affect = entityManager.createQuery("UPDATE BoardStats bs SET bs.favorites = bs.favorites - 1, bs.updateDate = ?1 WHERE bs.boardId = ?2")
					.setParameter(1, LocalDateTime.now())
					.setParameter(2, boardId)
					.executeUpdate();
			try{
				//为下次收藏清路
				entityManager.createNativeQuery("DELETE FROM apo_action_event_set WHERE `TYPE` = ?1 AND `ACTION` = ?2 AND MEMBERID = ?3 AND BOARDID = ?4")
					.setParameter(1, "B")
					.setParameter(2, "BOARD_FAVORITE")
					.setParameter(3, memberId)
					.setParameter(4, boardId)
					.executeUpdate();
			}catch(Exception e){
				logger.info("[BoardStatsDao]favorite negate has exception:"+e.getMessage());
			}
			return affect == 1?Optional.of(true):Optional.empty();
		}catch(Exception e) {
			if(logger.isDebugEnabled()){
				logger.debug(e.getMessage(), e);
			}
		}
		return Optional.empty();
	}

	@Transactional(propagation = Propagation.REQUIRED)
	@Override
	public Optional<Boolean> balanceTopicPosts(long plusBoardId, long minusBoardId, long postsSize)throws IllegalStateException {
		logger.info("[MTV][12]新版块[+1]: "+plusBoardId+", 原版块[-1]: "+minusBoardId+", 回复的数量: "+postsSize);
		//原版块话题-1,新版块话题+1
		//原版块回复-d.successValue,新版块回复+d.successValue
		try {
			entityManager.createQuery("UPDATE BoardStats bs SET bs.topices = bs.topices - ?1, bs.postses = bs.postses - ?2 WHERE bs.boardId = ?3")
						.setParameter(1, 1)
						.setParameter(2, postsSize)
						.setParameter(3, minusBoardId)
						.executeUpdate();
		}catch(Exception e) {
			logger.info("[MTV][13]原版块[-1]: "+minusBoardId+", 平衡失败: "+e.getMessage());
			throw new IllegalStateException(e.getMessage());
		}
		try {
			entityManager.createQuery("UPDATE BoardStats bs SET bs.topices = bs.topices + ?1, bs.postses = bs.postses + ?2 WHERE bs.boardId = ?3")
						.setParameter(1, 1)
						.setParameter(2, postsSize)
						.setParameter(3, plusBoardId)
						.executeUpdate();
			return Optional.of(true);
		}catch(Exception e) {
			logger.info("[MTV][14]新版块[+1]: "+plusBoardId+", 平衡失败: "+e.getMessage());
			throw new IllegalStateException(e.getMessage());
		}
	}

	@Override
	public Stream<BoardStats> findAllByBoardId(Collection<Long> boardIdList) {
		if(boardIdList == null || boardIdList.isEmpty()){
			return Stream.empty();
		}
		return entityManager.createQuery("SELECT bs FROM BoardStats bs WHERE bs.boardId IN ?1", BoardStats.class).setParameter(1, boardIdList).getResultStream();
	}

	@Override
	public EnumMap<ForumActionEnum, Long> sumTopicAndPosts() {
		final String SQL="SELECT SUM(TOPICES), SUM(POSTSES) FROM apo_board_stats";
		@SuppressWarnings("unchecked")
		List<Object[]> result = entityManager.createNativeQuery(SQL).getResultList();
		if(null == result || result.isEmpty()){
			return new EnumMap<>(ForumActionEnum.class);
		}
		//
		EnumMap<ForumActionEnum, Long> data = new EnumMap<>(ForumActionEnum.class);
		for(Object[] columns : result){
			Long ts = 0L;
			try{
				ts = ((BigDecimal)columns[0]).longValue();
			}catch(ClassCastException e){
				ts = (Long)columns[0];
			}
			Long ps = 0L;
			try{
				ps = ((BigDecimal)columns[1]).longValue();
			}catch(ClassCastException e){
				ps = (Long)columns[1];
			}
			
			data.put(ForumActionEnum.TOPIC_PUBLISH, ts);
			data.put(ForumActionEnum.POSTS_REPLY, ps);
		}
		return data;
	}

	@Transactional(propagation = Propagation.REQUIRES_NEW)
	@Override
	public Optional<Boolean> updateTopices(long boardId) {
		try {
			entityManager.createQuery("UPDATE BoardStats bs SET bs.topices = bs.topices + ?1 WHERE bs.boardId = ?2")
				.setParameter(1, 1)
				.setParameter(2, boardId)
				.executeUpdate();
			return Optional.of(true);
		}catch(Exception e) {
			if(logger.isDebugEnabled()){
				logger.debug(e.getMessage(), e);
			}
		}
		return Optional.empty();
	}

	@Override
	public Stream<BoardStats> findAllByBoardGroup(int volumesId) {
		return entityManager.createQuery("SELECT bs FROM BoardStats bs WHERE bs.volumesId = ?1", BoardStats.class).setParameter(1, volumesId).getResultStream();
	}

	@SuppressWarnings("unchecked")
	@Override
	public Stream<BoardStats> findAllForNotOriginBoard() {
		final String SQL="SELECT bs.* FROM apo_board_stats AS bs JOIN apo_board AS b ON bs.BOARDID = b.ID WHERE b.ORIGIN = ?1";
		return entityManager.createNativeQuery(SQL,BoardStats.class).setParameter(1, false).getResultStream();
	}

}
