package com.skr.mdm.authentication.user.imei;

import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.crypto.symmetric.SM4;
import com.skr.mdm.enums.MdmEncryptEnum;
import com.skr.mdm.util.SmUtils;
import io.swagger.models.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AuthenticationServiceException;
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.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author nfq
 * @date 2020/7/15 10:10
 */
public class ImeiAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public static final String SPRING_SECURITY_FORM_IMEI_KEY = "imei";
    public static final String COMPANY_ID = "companyId";

    public static final String SECRET_KEY = "secretKey";

    private final String imeiParameter = SPRING_SECURITY_FORM_IMEI_KEY;
    private final String companyIdParameter = COMPANY_ID;

    private final String secretKeyParameter = SECRET_KEY;

    private final boolean postOnly = true;

    private SM4 sm4 = null;

    private String mdmEncrypt;

    public ImeiAuthenticationFilter() {
        super(new AntPathRequestMatcher("/imei/login", "POST"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException,
            IOException, ServletException {

        if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {
            throw new AuthenticationServiceException("Authentication method not supported:" + request.getMethod());
        }
        if (MdmEncryptEnum.SM.getMdmEncrypt().equals(mdmEncrypt)) {
            obtainSecretKey(request);
        }
        String imei = obtainImei(request);
        String companyId = obtainCompanyId(request);
        if (imei == null) {
            imei = "";
        }

        imei = imei.trim();

        ImeiAuthenticationToken imeiAuthenticationToken = new ImeiAuthenticationToken(imei, companyId);

        setDetails(request, imeiAuthenticationToken);

        return this.getAuthenticationManager().authenticate(imeiAuthenticationToken);
    }

    @Nullable
    protected String obtainImei(HttpServletRequest request) {
        if (MdmEncryptEnum.SM.getMdmEncrypt().equals(mdmEncrypt)) {
            return sm4.decryptStr(request.getParameter(imeiParameter));
        }
        return request.getParameter(imeiParameter);
    }

    @Nullable
    protected String obtainCompanyId(HttpServletRequest request) {
        if (MdmEncryptEnum.SM.getMdmEncrypt().equals(mdmEncrypt)) {
            return sm4.decryptStr(request.getParameter(companyIdParameter));
        }
        return request.getParameter(companyIdParameter);
    }

    @Nullable
    protected String obtainSecretKey(HttpServletRequest request) {
        String secretKey = request.getHeader(secretKeyParameter);
        SM2 sm2 = SmUtils.sm2Sign();
        byte[] secretKeyBytes = sm2.decrypt(secretKey, KeyType.PrivateKey);
        sm4 = SmUtil.sm4(secretKeyBytes);
        return request.getHeader(secretKeyParameter);
    }

    protected void setDetails(HttpServletRequest request, ImeiAuthenticationToken imeiAuthenticationToken) {
        imeiAuthenticationToken.setDetails(authenticationDetailsSource.buildDetails(request));
    }

    public void setMdmEncrypt(String mdmEncrypt) {
        this.mdmEncrypt = mdmEncrypt;
    }
}
