content: package com.java2nb.novel.service.impl;
  
  import com.github.pagehelper.PageHelper;
  import com.java2nb.novel.core.bean.UserDetails;
  import com.java2nb.novel.core.enums.ResponseStatus;
  import com.java2nb.novel.entity.User;
  import com.java2nb.novel.entity.*;
  import com.java2nb.novel.mapper.*;
  import com.java2nb.novel.service.UserService;
  import com.java2nb.novel.vo.BookReadHistoryVO;
  import com.java2nb.novel.vo.BookShelfVO;
  import com.java2nb.novel.vo.UserFeedbackVO;
  import io.github.xxyopen.model.page.PageBean;
  import io.github.xxyopen.model.page.builder.pagehelper.PageBuilder;
  import io.github.xxyopen.util.IdWorker;
  import io.github.xxyopen.util.MD5Util;
  import io.github.xxyopen.web.exception.BusinessException;
  import io.github.xxyopen.web.util.BeanUtil;
  import lombok.RequiredArgsConstructor;
  import lombok.extern.slf4j.Slf4j;
  import org.apache.commons.codec.Charsets;
  import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider;
  import org.mybatis.dynamic.sql.render.RenderingStrategies;
  import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
  import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider;
  import org.springframework.beans.BeanUtils;
  import org.springframework.stereotype.Service;
  import org.springframework.transaction.annotation.Transactional;
  
  import java.util.Date;
  import java.util.List;
  
  import static com.java2nb.novel.mapper.BookDynamicSqlSupport.id;
  import static com.java2nb.novel.mapper.UserBookshelfDynamicSqlSupport.userBookshelf;
  import static com.java2nb.novel.mapper.UserDynamicSqlSupport.*;
  import static com.java2nb.novel.mapper.UserFeedbackDynamicSqlSupport.userFeedback;
  import static com.java2nb.novel.mapper.UserReadHistoryDynamicSqlSupport.userReadHistory;
  import static org.mybatis.dynamic.sql.SqlBuilder.*;
  import static org.mybatis.dynamic.sql.select.SelectDSL.select;
  
  /**
   * @author 11797
   */
  @Service
  @Slf4j
  @RequiredArgsConstructor
  public class UserServiceImpl implements UserService {
  
      private final FrontUserMapper userMapper;
  
      private final FrontUserBookshelfMapper userBookshelfMapper;
  
      private final FrontUserReadHistoryMapper userReadHistoryMapper;
  
      private final UserFeedbackMapper userFeedbackMapper;
  
      private final UserBuyRecordMapper userBuyRecordMapper;
  
      private final IdWorker idWorker = IdWorker.INSTANCE;
  
  
      @Override
      public UserDetails register(User user) {
          //查询用户名是否已注册
          SelectStatementProvider selectStatement = select(count(id))
              .from(UserDynamicSqlSupport.user)
              .where(username, isEqualTo(user.getUsername()))
              .build()
              .render(RenderingStrategies.MYBATIS3);
          long count = userMapper.count(selectStatement);
          if (count > 0) {
              //用户名已注册
              throw new BusinessException(ResponseStatus.USERNAME_EXIST);
          }
          User entity = new User();
          BeanUtils.copyProperties(user, entity);
          //数据库生成注册记录
          Long id = idWorker.nextId();
          entity.setId(id);
          entity.setNickName(entity.getUsername());
          Date currentDate = new Date();
          entity.setCreateTime(currentDate);
          entity.setUpdateTime(currentDate);
          entity.setPassword(MD5Util.MD5Encode(entity.getPassword(), Charsets.UTF_8.name()));
          userMapper.insertSelective(entity);
          //生成UserDetail对象并返回
          UserDetails userDetails = new UserDetails();
          userDetails.setId(id);
          userDetails.setUsername(entity.getUsername());
          userDetails.setNickName(entity.getNickName());
          return userDetails;
      }
  
      @Override
      public UserDetails login(User user) {
          //根据用户名密码查询记录
          SelectStatementProvider selectStatement = select(id, username, nickName)
              .from(UserDynamicSqlSupport.user)
              .where(username, isEqualTo(user.getUsername()))
              .and(password, isEqualTo(MD5Util.MD5Encode(user.getPassword(), Charsets.UTF_8.name())))
              .build()
              .render(RenderingStrategies.MYBATIS3);
          List<User> users = userMapper.selectMany(selectStatement);
          if (users.size() == 0) {
              throw new BusinessException(ResponseStatus.USERNAME_PASS_ERROR);
          }
          //生成UserDetail对象并返回
          UserDetails userDetails = new UserDetails();
          user = users.get(0);
          userDetails.setId(user.getId());
          userDetails.setNickName(user.getNickName());
          userDetails.setUsername(user.getUsername());
          return userDetails;
      }
  
      @Override
      public Boolean queryIsInShelf(Long userId, Long bookId) {
          SelectStatementProvider selectStatement = select(count(UserBookshelfDynamicSqlSupport.id))
              .from(userBookshelf)
              .where(UserBookshelfDynamicSqlSupport.userId, isEqualTo(userId))
              .and(UserBookshelfDynamicSqlSupport.bookId, isEqualTo(bookId))
              .build()
              .render(RenderingStrategies.MYBATIS3);
  
          return userBookshelfMapper.count(selectStatement) > 0;
      }
  
      @Override
      public void addToBookShelf(Long userId, Long bookId, Long preContentId) {
          if (!queryIsInShelf(userId, bookId)) {
              UserBookshelf shelf = new UserBookshelf();
              shelf.setUserId(userId);
              shelf.setBookId(bookId);
              shelf.setPreContentId(preContentId);
              shelf.setCreateTime(new Date());
              userBookshelfMapper.insert(shelf);
          }
  
      }
  
      @Override
      public void removeFromBookShelf(Long userId, Long bookId) {
          DeleteStatementProvider deleteStatement = deleteFrom(userBookshelf)
              .where(UserBookshelfDynamicSqlSupport.userId, isEqualTo(userId))
              .and(UserBookshelfDynamicSqlSupport.bookId, isEqualTo(bookId))
              .build()
              .render(RenderingStrategies.MYBATIS3);
          userBookshelfMapper.delete(deleteStatement);
  
      }
  
      @Override
      public PageBean<BookShelfVO> listBookShelfByPage(Long userId, int page, int pageSize) {
          PageHelper.startPage(page, pageSize);
          return PageBuilder.build(userBookshelfMapper.listBookShelf(userId));
      }
  
      @Transactional(rollbackFor = Exception.class)
      @Override
      public void addReadHistory(Long userId, Long bookId, Long preContentId) {
  
          Date currentDate = new Date();
          //删除该书以前的历史记录
          DeleteStatementProvider deleteStatement = deleteFrom(userReadHistory)
              .where(UserReadHistoryDynamicSqlSupport.bookId, isEqualTo(bookId))
              .and(UserReadHistoryDynamicSqlSupport.userId, isEqualTo(userId))
              .build()
              .render(RenderingStrategies.MYBATIS3);
          userReadHistoryMapper.delete(deleteStatement);
  
          //插入该书新的历史记录
          UserReadHistory userReadHistory = new UserReadHistory();
          userReadHistory.setBookId(bookId);
          userReadHistory.setUserId(userId);
          userReadHistory.setPreContentId(preContentId);
          userReadHistory.setCreateTime(currentDate);
          userReadHistory.setUpdateTime(currentDate);
          userReadHistoryMapper.insertSelective(userReadHistory);
  
          //更新书架的阅读历史
          UpdateStatementProvider updateStatement = update(userBookshelf)
              .set(UserBookshelfDynamicSqlSupport.preContentId)
              .equalTo(preContentId)
              .set(UserBookshelfDynamicSqlSupport.updateTime)
              .equalTo(currentDate)
              .where(UserBookshelfDynamicSqlSupport.userId, isEqualTo(userId))
              .and(UserBookshelfDynamicSqlSupport.bookId, isEqualTo(bookId))
              .build()
              .render(RenderingStrategies.MYBATIS3);
  
          userBookshelfMapper.update(updateStatement);
  
  
      }
  
      @Override
      public void addFeedBack(Long userId, String content) {
          UserFeedback feedback = new UserFeedback();
          feedback.setUserId(userId);
          feedback.setContent(content);
          feedback.setCreateTime(new Date());
          userFeedbackMapper.insertSelective(feedback);
      }
  
      @Override
      public PageBean<UserFeedback> listUserFeedBackByPage(Long userId, int page, int pageSize) {
          PageHelper.startPage(page, pageSize);
          SelectStatementProvider selectStatement = select(UserFeedbackDynamicSqlSupport.content,
              UserFeedbackDynamicSqlSupport.createTime)
              .from(userFeedback)
              .where(UserFeedbackDynamicSqlSupport.userId, isEqualTo(userId))
              .orderBy(UserFeedbackDynamicSqlSupport.id.descending())
              .build()
              .render(RenderingStrategies.MYBATIS3);
          List<UserFeedback> userFeedbacks = userFeedbackMapper.selectMany(selectStatement);
          PageBean<UserFeedback> pageBean = PageBuilder.build(userFeedbacks);
          pageBean.setList(BeanUtil.copyList(userFeedbacks, UserFeedbackVO.class));
          return pageBean;
      }
  
      @Override
      public User userInfo(Long userId) {
          SelectStatementProvider selectStatement = select(username, nickName, userPhoto, userSex, accountBalance)
              .from(user)
              .where(id, isEqualTo(userId))
              .build()
              .render(RenderingStrategies.MYBATIS3);
          return userMapper.selectMany(selectStatement).get(0);
      }
  
      @Override
      public PageBean<BookReadHistoryVO> listReadHistoryByPage(Long userId, int page, int pageSize) {
          PageHelper.startPage(page, pageSize);
          return PageBuilder.build(userReadHistoryMapper.listReadHistory(userId));
      }
  
      @Override
      public void updateUserInfo(Long userId, User user) {
          user.setId(userId);
          user.setUpdateTime(new Date());
          userMapper.updateByPrimaryKeySelective(user);
  
      }
  
      @Override
      public void updatePassword(Long userId, String oldPassword, String newPassword) {
          SelectStatementProvider selectStatement = select(password)
              .from(user)
              .where(id, isEqualTo(userId))
              .build()
              .render(RenderingStrategies.MYBATIS3);
          if (!userMapper.selectMany(selectStatement).get(0).getPassword()
              .equals(MD5Util.MD5Encode(oldPassword, Charsets.UTF_8.name()))) {
              throw new BusinessException(ResponseStatus.OLD_PASSWORD_ERROR);
          }
          UpdateStatementProvider updateStatement = update(user)
              .set(password)
              .equalTo(MD5Util.MD5Encode(newPassword, Charsets.UTF_8.name()))
              .where(id, isEqualTo(userId))
              .build()
              .render(RenderingStrategies.MYBATIS3);
          userMapper.update(updateStatement);
  
      }
  
      @Override
      public void addAmount(Long userId, int amount) {
          userMapper.addUserBalance(userId, amount);
      }
  
      @Override
      public boolean queryIsBuyBookIndex(Long userId, Long bookIndexId) {
  
          return userBuyRecordMapper.count(c ->
              c.where(UserBuyRecordDynamicSqlSupport.userId, isEqualTo(userId))
                  .and(UserBuyRecordDynamicSqlSupport.bookIndexId, isEqualTo(bookIndexId))) > 0;
      }
  
      @Transactional(rollbackFor = Exception.class)
      @Override
      public void buyBookIndex(Long userId, UserBuyRecord buyRecord) {
          //查询用户余额
          long balance = userInfo(userId).getAccountBalance();
          if (balance < buyRecord.getBuyAmount()) {
              //余额不足
              throw new BusinessException(ResponseStatus.USER_NO_BALANCE);
          }
          buyRecord.setUserId(userId);
          buyRecord.setCreateTime(new Date());
          //生成购买记录
          userBuyRecordMapper.insertSelective(buyRecord);
  
          //减少用户余额
          userMapper.update(update(user)
              .set(UserDynamicSqlSupport.accountBalance)
              .equalTo(balance - buyRecord.getBuyAmount())
              .where(id, isEqualTo(userId))
              .build()
              .render(RenderingStrategies.MYBATIS3));
      }
  
      @Override
      public int queryBuyMember(Long bookId, Date startTime, Date endTime) {
          return userMapper.selectStatistic(select(countDistinct(UserBuyRecordDynamicSqlSupport.userId))
              .from(UserBuyRecordDynamicSqlSupport.userBuyRecord)
              .where(UserBuyRecordDynamicSqlSupport.bookId, isEqualTo(bookId))
              .and(UserBuyRecordDynamicSqlSupport.createTime, isGreaterThanOrEqualTo(startTime))
              .and(UserBuyRecordDynamicSqlSupport.createTime, isLessThanOrEqualTo(endTime))
              .build()
              .render(RenderingStrategies.MYBATIS3));
      }
  
      @Override
      public int queryBuyCount(Long bookId, Date startTime, Date endTime) {
          return userMapper.selectStatistic(select(count(UserBuyRecordDynamicSqlSupport.id))
              .from(UserBuyRecordDynamicSqlSupport.userBuyRecord)
              .where(UserBuyRecordDynamicSqlSupport.bookId, isEqualTo(bookId))
              .and(UserBuyRecordDynamicSqlSupport.createTime, isGreaterThanOrEqualTo(startTime))
              .and(UserBuyRecordDynamicSqlSupport.createTime, isLessThanOrEqualTo(endTime))
              .build()
              .render(RenderingStrategies.MYBATIS3));
      }
  
      @Override
      public int queryBuyAccount(Long bookId, Date startTime, Date endTime) {
          return userMapper.selectStatistic(select(sum(UserBuyRecordDynamicSqlSupport.buyAmount))
              .from(UserBuyRecordDynamicSqlSupport.userBuyRecord)
              .where(UserBuyRecordDynamicSqlSupport.bookId, isEqualTo(bookId))
              .and(UserBuyRecordDynamicSqlSupport.createTime, isGreaterThanOrEqualTo(startTime))
              .and(UserBuyRecordDynamicSqlSupport.createTime, isLessThanOrEqualTo(endTime))
              .build()
              .render(RenderingStrategies.MYBATIS3));
      }
  
      @Override
      public int queryBuyTotalMember(List<Long> bookIds, Date startTime, Date endTime) {
          return userMapper.selectStatistic(select(countDistinct(UserBuyRecordDynamicSqlSupport.userId))
              .from(UserBuyRecordDynamicSqlSupport.userBuyRecord)
              .where(UserBuyRecordDynamicSqlSupport.bookId, isIn(bookIds))
              .and(UserBuyRecordDynamicSqlSupport.createTime, isGreaterThanOrEqualTo(startTime))
              .and(UserBuyRecordDynamicSqlSupport.createTime, isLessThanOrEqualTo(endTime))
              .build()
              .render(RenderingStrategies.MYBATIS3));
      }
  
  
  }
  