package com.tofly.auth.oauth;

import com.tofly.auth.feign.BaseUserService;
import com.tofly.common.core.constant.CommonConstants;
import com.tofly.common.core.constant.SecurityConstants;
import com.tofly.common.core.entity.ResultRespone;
import com.tofly.common.oauth.auth.ToflyUser;
import com.tofly.entity.pojo.User;
import com.tofly.entity.pojo.UserInfo;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

@Service
@Slf4j
@AllArgsConstructor
public class ToFlyUserDetailsService implements UserDetailsService {

    private final CacheManager cacheManager;
    private final BaseUserService baseUserService;

    @Override
    @SneakyThrows
    public UserDetails loadUserByUsername(String username){
        //首先从缓存中获取，当调用时，我们可以将用户信息存储到缓存，或者程序启动时加载到缓存
        Cache cache = cacheManager.getCache("user_details");

        if (cache != null && cache.get(username) != null && cache.get(username).get()!=null) {
            return (ToflyUser) cache.get(username).get();
        }
        log.info("当前登录用户 ========================> username:{}", username);
        ResultRespone<UserInfo> result = baseUserService.getInfo(username, SecurityConstants.FROM_IN);
        UserDetails userDetails=getUserDetails(result,username);
        //放入缓存
        cache.put(username,userDetails);
        return userDetails;
    }

    /**
     * 将用户设置为对应的oauth形式
     * @param result
     * @return
     */
    private UserDetails getUserDetails(ResultRespone<UserInfo> result,String username) {
        if (result == null || result.getResult() == null) {
            throw new UsernameNotFoundException(username+"用户或者密码错误");
        }

        UserInfo userInfo=result.getResult();
        User user=userInfo.getSysUser();
        if(CommonConstants.USER_STUTAS_FAIL.equals(user.getStatusFlag())){
            throw new UserCheckAuthenticationException("用户已处于禁用状态，不能登录");
        }

        if(CommonConstants.USER_LOCK_LOCKED.equals(user.getLockFlag())){
            throw new UserCheckAuthenticationException("用户已处于锁定状态，不能登录");
        }


        Set<String> dbauthSet=new HashSet<>();
        Long[] roles=userInfo.getRoles();
        if(roles!=null && roles.length>0){
            //添加角色
            Arrays.stream(roles).forEach(role->dbauthSet.add(SecurityConstants.ROLE+role));
            //添加权限
            dbauthSet.addAll(Arrays.asList(userInfo.getPermissions()));
        }else{
            //如果没有角色，也需要加一个默认角色用户名保证后续不会出错
            dbauthSet.add(userInfo.getSysUser().getUsername());
        }


        Collection<? extends GrantedAuthority> authorities
                = AuthorityUtils.createAuthorityList(dbauthSet.toArray(new String[0]));
        return new ToflyUser(user.getPwderrtimes(),user.getParentCompanyId(),user.getParentCompanyName(),user.getCompanyId(),user.getCompanyName(),user.getId(),user.getDepartmentId(),user.getUserLevel(),
                user.getRealName(),user.getDepartmentName(),user.getAvatar(),
                user.getUsername(),/*SecurityConstants.BCRYPT+*/user.getPassword(),
                CommonConstants.STATUS_NORMAL.equals(user.getLockFlag()),true,
                true,true,authorities);
    }


    class UserCheckAuthenticationException extends AuthenticationException {

        public UserCheckAuthenticationException(String msg, Throwable t) {
            super(msg, t);
        }

        public UserCheckAuthenticationException(String msg) {
            super(msg);
        }
    }
}
