package com.njzscloud.common.security.support;

import lombok.Getter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 待认证/已认证 令牌
 */
@Getter
public class UserAuthenticationToken extends AbstractAuthenticationToken {

    /**
     * 凭证
     */
    private final Object credentials;

    /**
     * 认证主体，未认证时为：{@link LoginForm}，认证完成时为：{@link UserDetail}
     */
    private final Object principal;

    /**
     * 创建认证对象
     *
     * @param credentials   凭证
     * @param principal     认证主体，未认证时为：{@link LoginForm}，认证完成时为：{@link UserDetail}
     * @param authorities   权限信息（角色编码）
     * @param details       登录附加信息{@link AuthenticationDetails}
     * @param authenticated 是否已完成认证
     */
    private UserAuthenticationToken(Object credentials,
                                    Object principal,
                                    Collection<? extends GrantedAuthority> authorities,
                                    AuthenticationDetails details,
                                    boolean authenticated) {
        super(authorities);
        setAuthenticated(authenticated);
        setDetails(details);
        this.credentials = credentials;
        this.principal = principal;
    }

    /**
     * 创建未认证的认证对象
     *
     * @param principal 认证主体，未认证时为：{@link LoginForm}
     * @param details   登录附加信息{@link AuthenticationDetails}
     * @return 待认证对象
     */
    public static UserAuthenticationToken create(LoginForm principal, AuthenticationDetails details) {
        return new UserAuthenticationToken(null, principal, null, details, false);
    }

    /**
     * 创建已完成认证的认证对象
     *
     * @param principal 用户信息{@link UserDetail}
     * @return 已完成认证的认证对象
     */
    public static UserAuthenticationToken create(UserDetail principal, AuthenticationDetails details) {
        Token credentials = principal.getToken();
        Set<String> roles = principal.getRoles();
        Set<SimpleGrantedAuthority> authorities = roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet());
        return new UserAuthenticationToken(credentials, principal, authorities, details, true);
    }
}
