package com.purui.prims.auth.authentication.adaptor;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.purui.prims.auth.api.authentication.adaptor.UserAdaptor;
import com.purui.prims.auth.api.authentication.pojo.User;
import com.purui.prims.auth.api.authentication.pojo.UserWithPassword;
import com.purui.prims.auth.api.authentication.request.UserReq;
import com.purui.prims.auth.api.authentication.response.RoleResp;
import com.purui.prims.auth.authentication.persistence.dataobject.RoleDO;
import com.purui.prims.auth.authentication.persistence.dataobject.UserDO;
import com.purui.prims.auth.authentication.persistence.repository.UserRepository;
import com.purui.prims.auth.authentication.utils.AESEncryptionUtil;
import com.purui.prims.auth.authentication.utils.UserTokenUtils;
import com.purui.prims.common.util.BeanMapper;
import com.purui.prims.common.util.ContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * DefaultUserAdaptor provides a default method to obtain user and organization information
 */
@Slf4j
public class DefaultUserAdaptor implements UserAdaptor {

    private List<UserDO> getUserDOList() {
        UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
        return userRepository.getUserList();
    }

    private UserDO getUser(String name) {
        UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
        return userRepository.getUser(name);
    }

    @Override
    public List<String> getUserNames() {
        return getUserDOList().stream().map(UserDO::getUserName).collect(Collectors.toList());
    }

    @Override
    public List<User> getUserList() {
        List<UserDO> userDOS = getUserDOList();
        return userDOS.stream().map(this::convert).collect(Collectors.toList());
    }

    @Override
    public List<RoleResp> getRoles() {
        UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
        return userRepository.getRoles().stream().map(roleDO -> {
            RoleResp roleResp = new RoleResp();
            BeanMapper.mapper(roleDO, roleResp);
            return roleResp;
        }).collect(Collectors.toList());
    }

    private User convert(UserDO userDO) {
        User user = new User();
        BeanUtils.copyProperties(userDO, user);
        if (userDO.getRoleId() != null) {
            UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
            RoleDO roleDO = userRepository.getRole(userDO.getRoleId());
            if (roleDO != null) {
                user.setRoleName(roleDO.getName());
            }
        }
        return user;
    }

    private UserDO convert(UserReq userReq) {
        UserDO userDO = new UserDO();
        BeanUtils.copyProperties(userReq, userDO);
        try {
            byte[] salt = AESEncryptionUtil.generateSalt(userDO.getUserName());
            userDO.setSalt(AESEncryptionUtil.getStringFromBytes(salt));
            log.info("salt: " + userDO.getSalt());
            userDO.setPassword(AESEncryptionUtil.encrypt(userReq.getPassword(), salt));
        } catch (Exception e) {
            throw new RuntimeException("密码异常，请联系管理员");
        }
        return userDO;
    }

    @Override
    public void register(UserReq userReq) {
        UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
        List<String> userDOS = getUserNames();
        if (userDOS.contains(userReq.getUserName())) {
            throw new RuntimeException(String.format("user %s exist", userReq.getUserName()));
        }
        UserDO userDO = convert(userReq);
        userRepository.addUser(userDO);
    }

    @Override
    public void update(UserReq userReq) {
        if (userReq.getId() == null || userReq.getId() == 0) {
            return;
        }
        UserDO userDO = convert(userReq);
        UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
        userRepository.updateUser(userDO);
    }

    @Override
    public String login(UserReq userReq, HttpServletRequest request) {
        UserTokenUtils userTokenUtils = ContextUtils.getBean(UserTokenUtils.class);
        String appKey = userTokenUtils.getAppKey(request);
        return login(userReq, appKey);
    }

    @Override
    public String login(UserReq userReq, String appKey) {
        UserTokenUtils userTokenUtils = ContextUtils.getBean(UserTokenUtils.class);
            UserWithPassword user = getUserWithPassword(userReq);
            return userTokenUtils.generateToken(user, appKey);
    }

    private UserWithPassword getUserWithPassword(UserReq userReq) {
        UserDO userDO = getUser(userReq.getUserName());
        if (userDO == null) {
            throw new RuntimeException("用户不存在!");
        }
        String password = userReq.getPassword();
        try {
            password = AESEncryptionUtil.encrypt(password,
                AESEncryptionUtil.getBytesFromString(userDO.getSalt()));
        } catch (Exception e) {
            throw new RuntimeException("密码不正确，请重试");
        }
        if (userDO.getPassword().equals(password)) {
            Optional<RoleResp> roleResp =
                getRoles().stream().filter(r -> r.getId().equals(userDO.getRoleId())).findFirst();
            String roleName = roleResp.isPresent() ? roleResp.get().getName() : "";
            UserWithPassword user = UserWithPassword.get(userDO.getId(), userDO.getUserName(), userDO.getDisplayName(),
                userDO.getEmail(), userDO.getPassword(), userDO.getIsAdmin(), userDO.getRoleId(), roleName);
            return user;
        } else {
            throw new RuntimeException("密码异常，请联系管理员");
        }

    }

    @Override
    public List<User> getUserByOrg(String key) {
        return Lists.newArrayList();
    }

    @Override
    public Set<String> getUserAllOrgId(String userName) {
        return Sets.newHashSet();
    }

}