package com.liquidnet.commons.lang.util.spring;

import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.util.concurrent.TimeUnit;

/**
 * @author AnJiabin <anjiabin@zhengzai.tv>
 * @version V1.0
 * @Description: TODO
 * @class: RestTemplateConfig
 * @Package com.liquidnet.commons.lang.util.spring
 * @Copyright: LightNet @ Copyright (c) 2021
 * @date 2021/7/31 14:57
 */
public class RestTemplateConfig {
    private static RestTemplate restTemplate;

    static {
        // 长链接保持时间长度20秒
        PoolingHttpClientConnectionManager poolConnManager =
                new PoolingHttpClientConnectionManager(20, TimeUnit.SECONDS);
        // 设置最大链接数
        poolConnManager.setMaxTotal(80 * getMaxCpuCore() * 5);
        // 单路由的并发数
        poolConnManager.setDefaultMaxPerRoute(80 * getMaxCpuCore());

        HttpClientBuilder httpClientBuilder = HttpClients.custom();
        httpClientBuilder.setConnectionManager(poolConnManager);

        // 重试次数3次，并开启
//        httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3,true));
        HttpClient httpClient = httpClientBuilder.build();
//        // 保持长链接配置，keep-alive
//        httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());

//        HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

        HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientRestfulHttpRequestFactory(httpClient);
        // 链接超时配置 5秒
        httpComponentsClientHttpRequestFactory.setConnectTimeout(5000);
        // 连接读取超时配置
//        httpComponentsClientHttpRequestFactory.setReadTimeout(10000);
        // 连接池不够用时候等待时间长度设置，分词那边 500毫秒 ，我们这边设置成1秒
        httpComponentsClientHttpRequestFactory.setConnectionRequestTimeout(5000);

        // 缓冲请求数据，POST大量数据，可以设定为true 我们这边机器比较内存较大
        httpComponentsClientHttpRequestFactory.setBufferRequestBody(true);

        restTemplate = new RestTemplate();
        restTemplate.setRequestFactory(httpComponentsClientHttpRequestFactory);
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
    }

    public static RestTemplate getRestTemplate() {
        return restTemplate;
    }

    private static int getMaxCpuCore() {
        int cpuCore = Runtime.getRuntime().availableProcessors();
        return cpuCore;
    }

    static class HttpComponentsClientRestfulHttpRequestFactory extends HttpComponentsClientHttpRequestFactory {

        public  HttpComponentsClientRestfulHttpRequestFactory(HttpClient httpClient) {
             new HttpComponentsClientHttpRequestFactory(httpClient);
        }

        @Override
        protected HttpUriRequest createHttpUriRequest(HttpMethod httpMethod, URI uri) {
            if (httpMethod == HttpMethod.GET) {
                return new HttpGetRequestWithEntity(uri);
            }
            return super.createHttpUriRequest(httpMethod, uri);
        }

        /**
         * 定义HttpGetRequestWithEntity实现HttpEntityEnclosingRequestBase抽象类，以支持GET请求携带body数据
         */

        private final class HttpGetRequestWithEntity extends HttpEntityEnclosingRequestBase {
            public HttpGetRequestWithEntity(final URI uri) {
                super.setURI(uri);
            }

            @Override
            public String getMethod() {
                return HttpMethod.GET.name();
            }
        }
    }
}
