package org.matrix.config;

import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.NoConnectionReuseStrategy;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.matrix.exception.GlobalException;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

/**
 * httpClient配置
 * @author huangxiahao
 */
@Component
public class HttpRequestConfig {

    ThreadLocal<CloseableHttpClient> threadLocal = new ThreadLocal<>();

    public CloseableHttpClient getClient(){
         CloseableHttpClient closeableHttpClient = threadLocal.get();
         if (closeableHttpClient==null){
             threadLocal.set(client());
         }
        return threadLocal.get();
    }

    public void clear(){
        threadLocal.remove();
    }

    /**
     * HttpClient的配置，所返回的CloseableHttpClient可以用来发送网络请求。
     */
    public CloseableHttpClient client()  {
        try {
            TrustStrategy acceptingTrustStrategy = (X509Certificate[] x509Certificates, String s) -> true;
            SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
                    .loadTrustMaterial(null, acceptingTrustStrategy)
                    .build();
            SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext
                    ,null, null, NoopHostnameVerifier.INSTANCE);
            SocketConfig socketConfig = SocketConfig.custom()
                    .setSoKeepAlive(false)
                    .setSoLinger(1)
                    .setSoReuseAddress(true)
                    .setSoTimeout(5000)
                    .setTcpNoDelay(true).build();
            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", csf)
                    .build();
            PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
            //最大连接数3000
            connectionManager.setMaxTotal(3000);
            //路由链接数400
            connectionManager.setDefaultMaxPerRoute(400);
            RequestConfig requestConfig = RequestConfig.custom()
                    .setMaxRedirects(1)
                    .setRedirectsEnabled(true)
                    .build();
            return   HttpClients.custom().setDefaultRequestConfig(requestConfig)
                    .setConnectionManager(connectionManager)
                    .setDefaultSocketConfig(socketConfig)
                    .setConnectionReuseStrategy(new NoConnectionReuseStrategy())
                    .evictExpiredConnections()
                    .evictIdleConnections(30, TimeUnit.SECONDS)
                    .setRetryHandler(new DefaultHttpRequestRetryHandler())
                    .disableAutomaticRetries()
                    .disableRedirectHandling()
                    .setDefaultCookieStore(cookieStore())
                    .build();
        }catch (Exception e){
            throw new GlobalException("初始化HttpClient引擎失败");
        }
    }

    /**
     * HttpClient的Cookie管理器，可在其他类中调用该Bean清空Cookie缓存。
     * 主要针对某些网站Cookie多次使用会造成Cookie失效的问题
     */
    public CookieStore cookieStore(){
        return new BasicCookieStore();
    }
}
