package com.ningdatech.pmapi.user.security.auth.credential;

import com.ningdatech.basic.model.GenericResult;
import com.ningdatech.pmapi.user.constant.LoginTypeEnum;
import com.ningdatech.pmapi.user.security.auth.constants.UserDeatilsServiceConstant;
import com.ningdatech.zwdd.client.ZwddAuthClient;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.Objects;

/**
 * @Author LiuXinXin
 * @Date 2020/8/3 8:55 下午
 * @Version 1.0
 **/
public class CredentialAuthProvider implements AuthenticationProvider {

    private UserDetailsService userDetailsService;

    private PasswordEncoder passwordEncoder;

    private ZwddAuthClient zwddAuthClient;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        if (!(authentication instanceof CredentialAuthToken)) {
            throw new RuntimeException("CustomAuthProvider 只支持 CustomAuthToken");
        }
        CredentialAuthToken authenticationToken = (CredentialAuthToken) authentication;
        String principal = (String) authenticationToken.getPrincipal();

        UserDetails user = null;
        LoginTypeEnum loginTypeEnum = authenticationToken.getLoginTypeEnum();
        switch (loginTypeEnum) {
            case DING_QR_LOGIN: {
                String code = (String) authenticationToken.getCredentials();
                GenericResult<String> accountResult = zwddAuthClient.getAccountId(code);
                if (!accountResult.isSuccess()) {
                    throw new BadCredentialsException("login fail! 浙政钉校验失败");
                }
                String accountId = accountResult.getData();
                if (Objects.isNull(accountId)) {
                    throw new BadCredentialsException("login fail! 浙政钉校验失败");
                }
                user = userDetailsService.loadUserByUsername(accountId + UserDeatilsServiceConstant.USER_DETAILS_SERVICE_SEPARATOR + loginTypeEnum.name());
            }
            break;
            case PHONE_VERIFICATION_CODE_LOGIN: {
                // TODO 校验短信验证码
                user = userDetailsService.loadUserByUsername(principal + UserDeatilsServiceConstant.USER_DETAILS_SERVICE_SEPARATOR + loginTypeEnum.name());
            }
            break;
            case USERNAME_PASSWORD_LOGIN: {
                user = userDetailsService.loadUserByUsername(principal + UserDeatilsServiceConstant.USER_DETAILS_SERVICE_SEPARATOR + loginTypeEnum.name());
                // TODO 校验测试环境关闭登陆校验

                //                if (user == null) {
//                    throw new InternalAuthenticationServiceException("can not get user info!");
//                }
//                // 账号密码登陆 更改
//                additionalAuthenticationChecks(user, authenticationToken);
            }
            break;
        }
        // 将用户定义的user放入token中，这样可以在session中查询到所有自定义的用户信息
        return new CredentialAuthToken(user, user.getPassword(), user.getAuthorities());
    }

    protected void additionalAuthenticationChecks(UserDetails userDetails, CredentialAuthToken authentication)
            throws AuthenticationException {
        if (authentication.getCredentials() == null) {
            throw new BadCredentialsException("login fail! password is null");
        }
        String presentedPassword = authentication.getCredentials().toString();
        if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
            throw new BadCredentialsException("login fail! password is error");
        }
    }


    @Override
    public boolean supports(Class<?> authentication) {
        return CredentialAuthToken.class.isAssignableFrom(authentication);
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    public void setZwddAuthClient(ZwddAuthClient zwddAuthClient) {
        this.zwddAuthClient = zwddAuthClient;
    }

}
