package cn.anicert.secure.access.utils;


import cn.hutool.log.StaticLog;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.TrustAllStrategy;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.config.Registry;
import org.apache.hc.core5.http.config.RegistryBuilder;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.apache.hc.core5.util.Timeout;

import javax.net.ssl.SSLContext;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

public class HttpUtil {
    private final PoolingHttpClientConnectionManager connPoolMng;
    private final RequestConfig requestConfig;
    private final SSLContext sslContext;
    private volatile static HttpUtil httpUtilInstance;

    /**
     * 私有构造方法
     * 单例中连接池初始化一次
     */
    private HttpUtil() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        //初始化http连接池
        sslContext = SSLContextBuilder.create()
                .loadTrustMaterial(new TrustAllStrategy())
                .build();
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https",new SSLConnectionSocketFactory(sslContext))
                .build();
        connPoolMng = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        connPoolMng.setMaxTotal(ConfigUtil.getConfig().getPoolMaxConn());
        connPoolMng.setDefaultMaxPerRoute(ConfigUtil.getConfig().getPoolMaxConn());
        //初始化请求超时控制参数
        requestConfig = RequestConfig.custom()
                //从线程池中获取线程超时时间
                .setConnectionRequestTimeout(Timeout.ofMilliseconds(ConfigUtil.getConfig().getConnectionRequestTimeout()))
                //设置数据读取超时时间
                .setResponseTimeout(Timeout.ofMilliseconds(ConfigUtil.getConfig().getResponseTimeout()))
                .build();
    }

    /**
     * 单例模式
     * 使用双检锁机制，线程安全且在多线程情况下能保持高性能
     *
     * @return HttpUtil
     */
    public static HttpUtil getInstance() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        if (httpUtilInstance == null) {
            synchronized (HttpUtil.class) {
                if (httpUtilInstance == null) {
                    httpUtilInstance = new HttpUtil();
                }
            }
        }
        return httpUtilInstance;
    }

    /**
     * 获取client客户端
     *
     * @return
     */
    public CloseableHttpClient getClient() {
        return HttpClients.custom()
                .setConnectionManager(connPoolMng)
                .setDefaultRequestConfig(requestConfig)
                .build();
    }

    /**
     * post请求
     *
     * @param postUrl
     * @param jsonStr
     * @return String
     * @throws Exception
     */
    public String postRequest(String postUrl, String jsonStr) throws Exception {
        String result;
        HttpPost post = new HttpPost(postUrl);
        StringEntity reqEntity = new StringEntity(jsonStr, ContentType.APPLICATION_JSON);
        post.setEntity(reqEntity);
        result = getClient().execute(post, response -> {
            StaticLog.debug("[安全接入平台]--请求地址--{}--响应状态--{}", postUrl, response.getCode());
            return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
        });
        return result;
    }
}
