package com.criticalblue.reactnative;

import com.facebook.react.modules.network.OkHttpClientFactory;
import com.facebook.react.modules.network.OkHttpClientProvider;
import com.facebook.react.modules.network.ReactCookieJarContainer;

import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

import okhttp3.CertificatePinner;
import okhttp3.OkHttpClient;

import android.util.Log;

public class PinnedClientFactory implements OkHttpClientFactory {
  private static final String TAG = "PinnedClientFactory";
    private CertificatePinner certificatePinner;
    private List<String> selfSignedCerts;

    public PinnedClientFactory(CertificatePinner certificatePinner, List<String> selfSignedCerts) {
        this.certificatePinner = certificatePinner;
        this.selfSignedCerts = selfSignedCerts;
    }

    /* Custom code for WFO usage: allow the HttpClient to connect to any SSL
    as the security will be ensured by cert pinning
     */
    @Override
    public OkHttpClient createNewNetworkModuleClient() {
        try {
            final TrustManager[] trustAllCerts = new TrustManager[] {new WfoX509TrustManager(selfSignedCerts)};

            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new SecureRandom());
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient.Builder client = new OkHttpClient.Builder()
                    .connectTimeout(0, TimeUnit.MILLISECONDS) //no timeout
                    .readTimeout(0, TimeUnit.MILLISECONDS) //no timeout
                    .writeTimeout(0, TimeUnit.MILLISECONDS) //no timeout
                    .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
                    .hostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {
                            return true; //trust all hosts
                        }
                    })
                    .cookieJar(new ReactCookieJarContainer());

            if (certificatePinner != null) {
                Log.i(TAG, "Setting OkHttpClient certificatePinner");
                client.addNetworkInterceptor(new LoggingInterceptor(certificatePinner));
            }

            return OkHttpClientProvider.enableTls12OnPreLollipop(client).build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}