package cn.quantgroup.xyqb.urora;

import cn.quantgroup.xyqb.security.CustomerAuthenticationManager;
import cn.quantgroup.xyqb.security.RSADecrypt;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.List;

/**
 * Created by Administrator on 2021/7/1 0001.
 */
public class UroraAuthenticationManager extends CustomerAuthenticationManager {

    private static final Logger logger = LoggerFactory.getLogger(UroraAuthenticationManager.class);

    private RestTemplate restTemplate;
    private HttpHeaders headers;

    public RestTemplate getRestTemplate() {
        return restTemplate;
    }

    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Override
    public void init() {
        this.headers = new HttpHeaders();
        this.headers.add("Authorization", getProperty("authorization"));
        this.headers.setContentType(MediaType.APPLICATION_JSON_UTF8);

        List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
        MappingJackson2HttpMessageConverter stringHttpMessageConverter = new MappingJackson2HttpMessageConverter();
        stringHttpMessageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8, MediaType.TEXT_PLAIN));
        messageConverters.add(stringHttpMessageConverter);

    }

    @Override
    public Authentication getCredentials(String credentials) throws AuthenticationException {

        String auth = ObjectUtils.getDisplayString(credentials);
        if (StringUtils.isEmpty(credentials)) {
            throw new BadCredentialsException("Authorization credentials does not look like urora. " + credentials);
        }

        auth = new String(Base64.decodeBase64(auth));
        String[] strings = auth.split(":");
        if (strings.length != 2) {
            throw new BadCredentialsException("Authorization credentials does not look like urora. " + auth);
        }
        return new UroraAuthenticationToken(strings[0], strings[1]);
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        HttpEntity<String> httpEntity = new HttpEntity<>("{\"loginToken\":\"" + authentication.getCredentials() + "\"}", headers);
        try {
            ResponseEntity<UroraResponse> verify = restTemplate.postForEntity(getProperty("loginTokenVerify"), httpEntity, UroraResponse.class);
            if (HttpStatus.OK.equals(verify.getStatusCode())) {
                UroraResponse body = verify.getBody();
                if (!body.getCode().equals("8000") || StringUtils.isEmpty(body.getPhone())) {
                    logger.warn("Urora login token verify failed. {}", body);
                    authentication.setAuthenticated(false);
                } else {
                    String decrypt = RSADecrypt.decrypt(body.getPhone(), getProperty("privateKey"));
                    UroraAuthenticationToken token = new UroraAuthenticationToken(body.getId(), decrypt);
                    token.setAuthenticated(true);
                    return token;
                }
            }
        } catch (Exception e) {
            logger.error("Urora login token verify failed. " + e.getMessage(), e);
            authentication.setAuthenticated(false);
        }
        return authentication;
    }
}