package cn.reghao.autodop.dmaster.rbac.service;

import cn.reghao.jdkutil.security.Cryptor;
import cn.reghao.jdkutil.security.Md5Cryptor;
import cn.reghao.jdkutil.security.Salt;
import cn.reghao.autodop.dmaster.rbac.db.crud.UserCrud;
import cn.reghao.autodop.dmaster.rbac.db.query.UserQuery;
import cn.reghao.autodop.dmaster.rbac.model.dto.UserInfo;
import cn.reghao.autodop.dmaster.rbac.model.dto.UserRole;
import cn.reghao.autodop.dmaster.rbac.model.po.UserAuthority;
import cn.reghao.autodop.dmaster.rbac.model.po.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.security.NoSuchAlgorithmException;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2020-06-19 16:36:53
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {
    private final UserQuery userQuery;
    private final UserCrud userCrud;
    private final Cryptor cryptor;

    public UserServiceImpl(UserQuery userQuery, UserCrud userCrud)
            throws NoSuchAlgorithmException {
        this.userQuery = userQuery;
        this.userCrud = userCrud;
        this.cryptor = new Md5Cryptor();
    }

    @Override
    public User getUser(String username) {
        User user = userQuery.findByUsername(username);
        if (user != null) {
            setGrantedAuthorities(user);
        }
        return user;
    }

    private void setGrantedAuthorities(User user) {
        Set<UserAuthority> grantedAuthorities = user.getRole().stream()
                .map(UserAuthority::new)
                .collect(Collectors.toSet());
        user.setAuthorities(grantedAuthorities);
    }

    @Override
    public void createUser(User user) {
        String username = user.getUsername();
        User userEntity = userQuery.findByUsername(username);
        if (userEntity != null) {
            log.error("用户 {} 已存在", username);
            return;
        }

        setEncryptPassword(user);
        user.setAvatarUrl("/imgs/avatar/default.png");
        userCrud.save(user);
    }

    private void setEncryptPassword(User user) {
        String password = user.getPassword();
        String salt = Salt.get(64);
        String encryptPwd = cryptor.encrypt(password + salt);
        user.setPassword(encryptPwd);
        user.setSalt(salt);
    }

    // TODO 密码修改后是否应该清除用户 session?
    @Override
    public void modifyUserPassword(Integer userId, String newPassword) {
        User userEntity = userQuery.findById(userId);
        if (userEntity != null) {
            userEntity.setPassword(newPassword);
            setEncryptPassword(userEntity);
            userCrud.save(userEntity);
        } else {
            log.error("用户不存在");
        }
    }

    @Override
    public void modifyUserInfo(UserInfo userInfo) {
        User userEntity = userQuery.findById(userInfo.getUserId());
        if (userEntity == null) {
            log.error("用户不存在");
            return;
        }

        userEntity.setNickname(userInfo.getNickname());
        userEntity.setMobilePhone(userInfo.getMobilePhone());
        userEntity.setEmail(userInfo.getEmail());
        userCrud.save(userEntity);
    }

    @Override
    public void setUserRoles(UserRole userRole) {
        User userEntity = userQuery.findById(userRole.getUserId());
        if (userEntity == null) {
            log.error("用户不存在");
            return;
        }

        Set<UserAuthority> authorities = userRole.getRoles().stream()
                .map(role -> new UserAuthority(role.getTitle()))
                .collect(Collectors.toSet());
        userEntity.setAuthorities(authorities);
        userCrud.save(userEntity);
    }

    @Override
    public void setUserStatus(Integer userId, Boolean enable) {
        User userEntity = userQuery.findById(userId);
        if (userEntity == null) {
            log.error("用户不存在");
            return;
        }

        userEntity.setIsEnabled(enable);
        userCrud.save(userEntity);
    }

    // TODO 删除用户后还需清除用户 session
    @Override
    public void deleteUser(Integer userId) {
        User userEntity = userQuery.findById(userId);
        if (userEntity != null) {
            userCrud.delete(userEntity);
        }
    }
}
