package com.microservices.common.httpClient.config;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PreDestroy;
import java.util.concurrent.TimeUnit;

/**
 * HttpClient 配置类
 * 支持 HTTPS 和连接池管理，包含自动连接清理机制
 *
 * @author admin
 * @date 2017/2/6
 */
@Configuration
public class HttpClientConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(HttpClientConfiguration.class);

    @Value("${http.maxTotal:100}")
    private Integer maxTotal;

    @Value("${http.defaultMaxPerRoute:20}")
    private Integer defaultMaxPerRoute;

    @Value("${http.connectTimeout:10000}")
    private Integer connectTimeout;

    @Value("${http.connectionRequestTimeout:5000}")
    private Integer connectionRequestTimeout;

    @Value("${http.socketTimeout:30000}")
    private Integer socketTimeout;

    @Value("${http.staleConnectionCheckEnabled:true}")
    private boolean staleConnectionCheckEnabled;

    private PoolingHttpClientConnectionManager connectionManager;

    /**
     * 创建支持 HTTPS 的连接池管理器
     * 使用自定义的 SSL 配置来避免 "peer not authenticated" 错误
     *
     * @return PoolingHttpClientConnectionManager
     */
    @Bean(name = "httpClientConnectionManager")
    public PoolingHttpClientConnectionManager getHttpClientConnectionManager() {
        try {
            // 创建 SSLConnectionSocketFactory
            SSLConnectionSocketFactory sslSocketFactory = SSLContextFactory.createSSLConnectionSocketFactory();

            // 注册 HTTP 和 HTTPS 的 SocketFactory
            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", sslSocketFactory)
                    .build();

            // 使用自定义 Registry 创建连接池管理器
            PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(registry);

            // 设置连接池参数
            manager.setMaxTotal(maxTotal);
            manager.setDefaultMaxPerRoute(defaultMaxPerRoute);

            // 设置连接验证间隔（非常重要！防止使用已关闭的连接）
            manager.setValidateAfterInactivity(2000);

            this.connectionManager = manager;

            logger.info("HttpClient连接池初始化成功 - 最大连接数: {}, 每个路由最大连接数: {}, SSL验证: 启用",
                    maxTotal, defaultMaxPerRoute);

            return manager;
        } catch (Exception e) {
            logger.error("HttpClient连接池初始化失败", e);
            throw new RuntimeException("HttpClient连接池初始化失败", e);
        }
    }

    /**
     * 创建 HttpClientBuilder
     * 配置重试机制和连接管理策略
     *
     * @param httpClientConnectionManager 连接池管理器
     * @return HttpClientBuilder
     */
    @Bean(name = "httpClientBuilder")
    public org.apache.http.impl.client.HttpClientBuilder getHttpClientBuilder(
            @Qualifier("httpClientConnectionManager") PoolingHttpClientConnectionManager httpClientConnectionManager) {

        org.apache.http.impl.client.HttpClientBuilder builder = HttpClients.custom()
                .setConnectionManager(httpClientConnectionManager)
                // 设置连接存活时间 - 防止连接被长期占用
                .setConnectionTimeToLive(60, TimeUnit.SECONDS)
                // 添加重试机制 - 针对 IO/SSL 异常
                .setRetryHandler((exception, executionCount, context) -> {
                    if (executionCount > 2) {
                        logger.warn("HTTP请求重试次数超过限制(2次)，停止重试");
                        return false;
                    }
                    // 可重试的异常类型
                    if (exception instanceof org.apache.http.NoHttpResponseException
                            || exception instanceof javax.net.ssl.SSLHandshakeException
                            || exception instanceof java.net.SocketException
                            || exception instanceof org.apache.http.conn.HttpHostConnectException) {
                        logger.warn("HTTP请求失败，正在进行第{}次重试。异常类型: {}, 消息: {}",
                                executionCount, exception.getClass().getSimpleName(), exception.getMessage());
                        return true;
                    }
                    logger.debug("HTTP请求失败，异常类型不支持重试: {}", exception.getClass().getName());
                    return false;
                })
                // 禁用过期连接
                .evictIdleConnections(30, TimeUnit.SECONDS)
                // 空闲连接验证
                .setConnectionManagerShared(false);

        logger.info("HttpClientBuilder 配置完成 - 重试机制: 启用(最多2次), 连接存活时间: 60秒");
        return builder;
    }

    /**
     * 创建 CloseableHttpClient 实例
     *
     * @param httpClientBuilder HttpClientBuilder
     * @return CloseableHttpClient
     */
    @Bean
    public CloseableHttpClient getCloseableHttpClient(
            @Qualifier("httpClientBuilder") org.apache.http.impl.client.HttpClientBuilder httpClientBuilder) {

        CloseableHttpClient httpClient = httpClientBuilder.build();

        // 启动连接池清理后台线程
        startConnectionMonitorThread();

        logger.info("CloseableHttpClient 创建成功");
        return httpClient;
    }

    /**
     * 创建 RequestConfig.Builder
     *
     * @return RequestConfig.Builder
     */
    @Bean(name = "builder")
    public RequestConfig.Builder getBuilder() {
        RequestConfig.Builder builder = RequestConfig.custom();
        return builder.setConnectTimeout(connectTimeout)
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setSocketTimeout(socketTimeout)
                .setStaleConnectionCheckEnabled(staleConnectionCheckEnabled);
    }

    /**
     * 创建 RequestConfig
     *
     * @param builder RequestConfig.Builder
     * @return RequestConfig
     */
    @Bean
    public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder) {
        RequestConfig config = builder.build();
        logger.info("RequestConfig 配置完成 - 连接超时: {}ms, 请求超时: {}ms, Socket超时: {}ms, 陈旧连接检查: {}",
                connectTimeout, connectionRequestTimeout, socketTimeout, staleConnectionCheckEnabled);
        return config;
    }

    /**
     * 启动连接池监控和清理线程
     * 定期清理过期和空闲连接，防止使用已关闭的连接
     */
    private void startConnectionMonitorThread() {
        Thread monitorThread = new Thread(() -> {
            logger.info("HttpClient连接池监控线程启动");
            try {
                while (connectionManager != null) {
                    try {
                        // 每 10 秒清理一次
                        Thread.sleep(10000);

                        if (connectionManager != null) {
                            // 关闭过期连接
                            connectionManager.closeExpiredConnections();
                            // 关闭空闲超过 30 秒的连接
                            connectionManager.closeIdleConnections(30, TimeUnit.SECONDS);

                            if (logger.isDebugEnabled()) {
                                logger.debug("HttpClient连接池状态 - 总连接数: {}, 路由数: {}, 最大连接数: {}, 每路由最大连接数: {}",
                                        connectionManager.getTotalStats().getLeased() +
                                                connectionManager.getTotalStats().getAvailable(),
                                        connectionManager.getTotalStats().getLeased(),
                                        connectionManager.getMaxTotal(),
                                        connectionManager.getDefaultMaxPerRoute());
                            }
                        }
                    } catch (InterruptedException e) {
                        logger.warn("HttpClient连接池监控线程被中断");
                        Thread.currentThread().interrupt();
                        break;
                    } catch (Exception e) {
                        logger.error("HttpClient连接池清理过程中出现异常", e);
                    }
                }
            } finally {
                logger.info("HttpClient连接池监控线程停止");
            }
        });

        monitorThread.setDaemon(true);
        monitorThread.setName("http-connection-monitor");
        monitorThread.start();
    }

    /**
     * 应用关闭时清理资源
     */
    @PreDestroy
    public void destroy() {
        logger.info("开始清理 HttpClient 资源");
        if (connectionManager != null) {
            try {
                connectionManager.close();
                logger.info("HttpClient 连接池已关闭");
            } catch (Exception e) {
                logger.error("关闭 HttpClient 连接池时出现异常", e);
            }
        }
    }
}
