package cn.iocoder.byzs.framework.web.config;

import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;

import java.util.concurrent.TimeUnit;

/**
 * WebClient 自动配置
 *
 * @author fansili
 */
@AutoConfiguration
@EnableConfigurationProperties(WebClientProperties.class)
public class WebClientAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public WebClient webClient(WebClient.Builder builder) {
        return builder.build();
    }

    @Bean
    @ConditionalOnMissingBean
    public WebClient.Builder webClientBuilder(WebClientProperties properties) {
        // 配置连接池
        ConnectionProvider connectionProvider = ConnectionProvider.builder("web-client-pool")
                .maxConnections(properties.getPool().getMaxConnections())
                .maxIdleTime(properties.getPool().getMaxIdleTime())
                .maxLifeTime(properties.getPool().getMaxLifeTime())
                .build();

        // 配置 HttpClient
        HttpClient httpClient = HttpClient.create(connectionProvider)
                // 连接超时设置
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) properties.getConnectTimeout().toMillis())
                // 读取超时设置
                .doOnConnected(conn -> conn
                        .addHandlerLast(new ReadTimeoutHandler((int) properties.getReadTimeout().getSeconds(), TimeUnit.SECONDS))
                        .addHandlerLast(new WriteTimeoutHandler((int) properties.getWriteTimeout().getSeconds(), TimeUnit.SECONDS)))
                // 增加连接复用
                .keepAlive(true);

        // 构建 WebClient.Builder
        return WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient));
    }

    @Bean
    @ConditionalOnMissingBean
    public HttpClient httpClient(WebClientProperties properties) {
        // 配置连接池
        ConnectionProvider connectionProvider = ConnectionProvider.builder("web-client-pool")
                .maxConnections(properties.getPool().getMaxConnections())
                .maxIdleTime(properties.getPool().getMaxIdleTime())
                .maxLifeTime(properties.getPool().getMaxLifeTime())
                .build();

        // 配置 HttpClient
        return HttpClient.create(connectionProvider)
                // 连接超时设置
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) properties.getConnectTimeout().toMillis())
                // 读取超时设置
                .doOnConnected(conn -> conn
                        .addHandlerLast(new ReadTimeoutHandler((int) properties.getReadTimeout().getSeconds(), TimeUnit.SECONDS))
                        .addHandlerLast(new WriteTimeoutHandler((int) properties.getWriteTimeout().getSeconds(), TimeUnit.SECONDS)));
    }

}