package cn.reghao.tnb.auth.app.security.form;

import cn.reghao.tnb.auth.app.model.po.UserAccount;
import cn.reghao.tnb.common.util.ConstantId;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;

import java.util.List;

/**
 * 参考 org.springframework.security.authentication.UsernamePasswordAuthenticationToken 实现
 *
 * @author reghao
 * @date 2022-07-06 15:59:02
 */
public class AccountAuthToken extends AbstractAuthenticationToken {
    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

    // ~ Instance fields
    // ================================================================================================
    private final Integer plat;
    private final String loginId;
    private final Integer loginType;
    private final Long userId;
    private final boolean rememberMe;
    private final Object principal;
    private Object credentials;

    // ~ Constructors
    // ===================================================================================================

    /**
     * 等待认证时创建的 Authentication 对象
     *
     * This constructor can be safely used by any code that wishes to create a
     * <code>PasswordAuthToken</code>, as the {@link #isAuthenticated()}
     * will return <code>false</code>.
     *
     */
    public AccountAuthToken(Integer plat, String loginId, Integer loginType, Boolean rememberMe, Object principal, Object credentials) {
        super(null);
        super.setAuthenticated(false);
        this.plat = plat;
        this.loginId = loginId;
        this.loginType = loginType;
        this.rememberMe = rememberMe;
        this.userId = ConstantId.ANONYMOUS_USER_ID;
        this.principal = principal;
        this.credentials = credentials;
    }

    /**
     * 认证通过时创建的 Authentication 对象
     *
     * This constructor should only be used by <code>AuthenticationManager</code> or
     * <code>AuthenticationProvider</code> implementations that are satisfied with
     * producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
     * authentication token.
     *
     * @param authToken
     * @param userDetail
     */
    public AccountAuthToken(AccountAuthToken authToken, UserAccount userDetail) {
        super(userDetail.getAuthorities());
        super.setAuthenticated(true); // must use super, as we override
        super.setDetails(userDetail);
        this.plat = authToken.getPlat();
        this.loginId = authToken.getLoginId();
        this.loginType = authToken.getLoginType();
        this.rememberMe = authToken.isRememberMe();
        this.userId = userDetail.getUserId();
        this.principal = authToken.getPrincipal();
        this.credentials = authToken.getCredentials();
    }

    /**
     * 从 AccessToken 中恢复的已认证 Authentication 对象
     *
     * @param
     * @return
     * @date 2023-02-17 17:42:27
     */
    public AccountAuthToken(int plat, String loginId, int loginType, long userId, List<GrantedAuthority> authorities) {
        super(authorities);
        super.setAuthenticated(true);
        this.plat = plat;
        this.loginId = loginId;
        this.loginType = loginType;
        this.rememberMe = false;
        this.userId = userId;
        this.principal = userId;
        this.credentials = null;
    }

    // ~ Methods
    // ========================================================================================================
    public Integer getPlat() {
        return this.plat;
    }

    public String getLoginId() {
        return loginId;
    }

    public Integer getLoginType() {
        return this.loginType;
    }

    public boolean isRememberMe() {
        return rememberMe;
    }

    public Long getUserId() {
        return this.userId;
    }

    @Override
    public Object getCredentials() {
        return this.credentials;
    }

    @Override
    public Object getPrincipal() {
        return this.principal;
    }

    /*@Override
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException(
                    "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        }

        super.setAuthenticated(false);
    }*/

    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
        credentials = null;
    }
}
