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

import com.ningdatech.basic.exception.BizException;
import com.ningdatech.pmapi.user.constant.LoginTypeEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
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.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author LiuXinXin
 * @Date 2020/8/3 8:46 下午
 * @Version 1.0
 **/
public class CredentialAuthFilter extends AbstractAuthenticationProcessingFilter {

    private boolean postOnly = true;

    private static final String IDENTIFIER_PARAMETER = "identifier";
    private static final String CREDENTIAL_PARAMETER = "credential";
    private static final String LOGIN_TYPE_PARAMETER = "loginType";


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

    public CredentialAuthFilter(String processingUrl) {
        super(new AntPathRequestMatcher(processingUrl, HttpMethod.POST.name()));
    }

    // ~ Methods
    // ========================================================================================================

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {
            throw new AuthenticationServiceException("请求方法错误");
        }
        String identifier = request.getParameter(IDENTIFIER_PARAMETER);
        String credential = request.getParameter(CREDENTIAL_PARAMETER);
        String loginType = request.getParameter(LOGIN_TYPE_PARAMETER);
        if (StringUtils.isBlank(loginType)) {
            throw new BadCredentialsException("登陆类型不能为空");
        }
        paramValid(identifier, credential, loginType);


        identifier = trim(identifier);
        credential = trim(credential);
        loginType = trim(loginType);
        try {
            CredentialAuthToken authRequest = new CredentialAuthToken(identifier, credential, loginType);
            // Allow subclasses to set the "details" property
            setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        } catch (AuthenticationException e) {
            throw new BadCredentialsException("账号或密码错误");
        } catch (BizException e) {
            throw new BadCredentialsException(e.getMessage());
        } catch (Exception e) {
            throw new InternalAuthenticationServiceException("授权失败：", e);
        }
    }

    protected void setDetails(HttpServletRequest request, CredentialAuthToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

    private void paramValid(String identifier, String credential, String loginType) {
        LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(loginType);
        switch (loginTypeEnum) {
            case DING_QR_LOGIN: {
                if (StringUtils.isBlank(credential)) {
                    throw new BadCredentialsException("浙政钉扫码登陆 授权码 不能为空 credential");
                }
            }
            break;
            case USERNAME_PASSWORD_LOGIN: {
                if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) {
                    throw new BadCredentialsException("账号密码登陆 账号密码不能为空 identifier credential");
                }
            }
            break;
            case PHONE_VERIFICATION_CODE_LOGIN: {
                if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) {
                    throw new BadCredentialsException("手机号验证码登陆 手机号或验证码不能为空 identifier credential");
                }
            }
            break;
        }
    }

    private String trim(String trimStr) {
        if (StringUtils.isNotBlank(trimStr)) {
            return trimStr.trim();
        }
        return null;
    }
}
