package com.secspace.lib.common.net;


import android.content.Context;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Arrays;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.OkHttpClient;

/**
 * @author hyw
 * @since 2017/2/23
 */
public class OkHttpsUtils {
    private static final String TAG = "OkHttpsUtils";
    private static volatile OkHttpClient sOkHttpClient = null;

    public static OkHttpClient getOkHttpClient(Context context, int certRes) {
        synchronized (OkHttpClient.class) {
            if (sOkHttpClient == null) {
                InputStream inputStream = context.getResources().openRawResource(certRes);
                sOkHttpClient = createOkHttpClient(
                        inputStream);
            }
        }
        return sOkHttpClient;
    }

    private static class SSLParams {
        SSLSocketFactory sslSocketFactory;
        X509TrustManager trustManager;
    }

    private static OkHttpClient createOkHttpClient(InputStream... certificateInputStreams) {
        SSLParams sslParams = getSSLParams(certificateInputStreams);
        // 创建OkHttpClient设置SslSocketFactory
        return new OkHttpClient.Builder()
                .sslSocketFactory(sslParams.sslSocketFactory, sslParams.trustManager)
                .hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return hostname.equalsIgnoreCase(session.getPeerHost());
                    }
                })
                .retryOnConnectionFailure(false)
                .build();
    }

    private static SSLParams getSSLParams(InputStream... certificateInputStreams) {
        SSLParams sslParams = new SSLParams();
        try {
            // 构造CertificateFactory对象，通过它的generateCertificate(is)方法得到Certificate
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            int index = 0;
            for (InputStream inputStream : certificateInputStreams) {
                String certificateAlias = Integer.toString(index++);
                // 将得到的Certificate放入到keyStore中
                keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(inputStream));

                try {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                } catch (IOException e) {
                    Log.e(TAG, "getSSLParams: " + e);
                }
            }
            // 初始化TrustManagerFactory
            TrustManagerFactory trustManagerFactory =
                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);

            // 得到X509TrustManager
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                throw new IllegalStateException("Unexpected default trust managers:"
                        + Arrays.toString(trustManagers));
            }
            X509TrustManager trustManager = (X509TrustManager) trustManagers[0];

            // 初始化SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());

            sslParams.sslSocketFactory = sslContext.getSocketFactory();
            sslParams.trustManager = trustManager;
        } catch (CertificateException | KeyStoreException | NoSuchAlgorithmException | IOException | KeyManagementException e) {
            Log.e(TAG, "getSSLParams: " + e);
        }
        return sslParams;

    }
}
