package cn.edu.whu.boot.user.services.impl;

import cn.edu.whu.boot.allocation.exceptions.InvalidUserRoleCodeException;
import cn.edu.whu.boot.common.service.CacheService;
import cn.edu.whu.boot.user.entities.Role;
import cn.edu.whu.boot.user.entities.User;
import cn.edu.whu.boot.user.mapper.UserMapper;
import cn.edu.whu.boot.user.services.RoleService;
import cn.edu.whu.boot.user.services.UserService;
import cn.edu.whu.boot.common.utils.user.PasswordEncoder;
import cn.edu.whu.boot.xml.domain.RedisKeyType;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;

    private final RoleService roleService;

    private final CacheService cacheService;

    private final SessionDAO sessionDAO;

    public UserServiceImpl(UserMapper userMapper, RoleService roleService, CacheService cacheService, SessionDAO sessionDAO) {
        this.userMapper = userMapper;
        this.roleService = roleService;
        this.cacheService = cacheService;
        this.sessionDAO = sessionDAO;
    }

    @Override
    public User createUser(String username, String realName, String password, String phone, String email, int code) throws InvalidUserRoleCodeException {
        // 查询邀请码对应的角色
        Optional<Role> role = roleService.findByCode(code);
        if (!role.isPresent()) {
            throw new InvalidUserRoleCodeException("邀请码错误");
        }
        // 生成盐值
        String salt = UUID.randomUUID().toString();
        // hash 密码
        String hashedPwd = PasswordEncoder.encode(password, salt);
        User newUser = new User();
        newUser.setUsername(username);
        newUser.setRealName(realName);
        newUser.setPassword(hashedPwd);
        newUser.setSalt(salt);
        newUser.setPhone(phone);
        newUser.setEmail(email);
        newUser.setRole(role.get().getId());
        return userMapper.insert(newUser);
    }

    @Override
    public User createUser(String username, String realName, String password, int role) {
        User user = new User();
        user.setUsername(username);
        user.setRealName(realName);
        user.setRole(role);
        // 生成盐值
        String salt = UUID.randomUUID().toString();
        user.setSalt(salt);
        // hash 密码
        String hashedPwd = PasswordEncoder.encode(password, salt);
        user.setPassword(hashedPwd);
        return userMapper.insert(user);
    }

    @Override
    public Optional<User> findById(int id) {
        return Optional.ofNullable(userMapper.findById(id));
    }

    @Override
    public Optional<User> findByUsername(String name) {
        return Optional.ofNullable(userMapper.findByUsername(name));
    }

    @Override
    public int countLikeUsername(String username) {
        return userMapper.countLikeUsername("%" + username + "%");
    }

    @Override
    public List<User> findLikeUsernamePagination(String username, int pageSize, int pageNum) {
        if (username.isEmpty() || pageSize <= 0 || pageNum <= 0) {
            return Collections.emptyList();
        }
        return userMapper.findLikeUsernameWithinPage("%" + username + "%", pageSize, pageSize * (pageNum - 1));
    }

    @Override
    public Optional<User> findByPhone(String phone) {
        return Optional.ofNullable(userMapper.findByPhone(phone));
    }

    @Override
    public Optional<User> findByEmail(String email) {
        return Optional.ofNullable(userMapper.findByEmail(email));
    }

    @Override
    public User updateUser(User user) {
        return userMapper.update(user);
    }

    @Override
    public List<User> findByRole(int role) {
        return userMapper.findByRole(role);
    }

    @Override
    public List<User> findAll() {
        return userMapper.findAll();
    }

    @Override
    public List<User> findAllPagination(int pageSize, int pageNum) {
        if (pageSize <= 0 || pageNum <= 0) {
            return Collections.emptyList();
        }
        return userMapper.findWithinPage(pageSize, pageSize * (pageNum - 1));
    }

    @Override
    public int countAll() {
        return userMapper.countAll();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteById(int id) {
        return userMapper.deleteById(id);
    }

    @Override
    public List<User> getOnlineUsers() {
        // 通过统计目前还活跃的 session 来粗略估计当前在线用户数量
        return sessionDAO
                .getActiveSessions()
                .stream()
                .map(session -> {
                    if (session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY) != null) {
                        SimplePrincipalCollection simplePrincipalCollection = (SimplePrincipalCollection)
                                session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
                        return (User) simplePrincipalCollection.getPrimaryPrincipal();
                    } else {
                        return null;
                    }
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    @Override
    public String findRealNameById(int id) {
        String realName;
        Object value = cacheService.get(RedisKeyType.REAL_NAME.toString() + id);
        if (value != null) {
            realName = (String) value;
        } else {
            // 查询数据库，并更新缓存
            Optional<User> optionalUser = findById(id);
            if (!optionalUser.isPresent()) {
                return "";
            }
            realName = optionalUser.get().getRealName();
            cacheService.set(RedisKeyType.REAL_NAME.toString() + id, realName, 24 * 60 * 60);
        }
        return realName;
    }
}