package com.zsElectric.boot.config;

import lombok.extern.slf4j.Slf4j;
import okhttp3.ConnectionPool;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.time.Duration;
import java.util.concurrent.TimeUnit;

@Slf4j
@Configuration
public class OkHttpConfig {
    
    @Value("${okhttp.connect-timeout:30}")
    private Duration connectTimeout;
    
    @Value("${okhttp.read-timeout:120}")
    private Duration readTimeout;
    
    @Value("${okhttp.write-timeout:60}")
    private Duration writeTimeout;
    
    @Value("${okhttp.retry-on-connection-failure:true}")
    private boolean retryOnConnectionFailure;
    
    @Value("${okhttp.connection-pool.max-idle-connections:200}")
    private int maxIdleConnections;
    
    @Value("${okhttp.connection-pool.keep-alive-duration:300}")
    private Duration keepAliveDuration;
    
    @Value("${okhttp.max-retry-count:3}")
    private int maxRetryCount;

    @Bean
    public ConnectionPool connectionPool() {
        return new ConnectionPool(maxIdleConnections, keepAliveDuration.toMillis(), TimeUnit.MILLISECONDS);
    }

    @Bean
    public OkHttpClient okHttpClient(ConnectionPool connectionPool) {
        return new OkHttpClient.Builder()
                .connectTimeout(connectTimeout)
                .readTimeout(readTimeout)
                .writeTimeout(writeTimeout)
                .retryOnConnectionFailure(retryOnConnectionFailure)
                .connectionPool(connectionPool)
                .addInterceptor(retryInterceptor())
                .build();
    }
    
    /**
     * 重试拦截器
     */
    private Interceptor retryInterceptor() {
        return chain -> {
            Request request = chain.request();
            Response response = null;
            IOException lastException = null;
            
            for (int i = 0; i <= maxRetryCount; i++) {
                try {
                    if (i > 0) {
                        log.warn("第 {} 次重试请求: {}", i, request.url());
                        // 重试前等待一段时间，使用指数退避策略
                        Thread.sleep((long) Math.pow(2, i - 1) * 1000);
                    }
                    response = chain.proceed(request);
                    // 如果响应成功，直接返回
                    if (response.isSuccessful()) {
                        if (i > 0) {
                            log.info("第 {} 次重试成功: {}", i, request.url());
                        }
                        return response;
                    }
                    // 如果是客户端错误（4xx），不重试
                    if (response.code() >= 400 && response.code() < 500) {
                        log.warn("客户端错误，不重试: {}, 状态码: {}", request.url(), response.code());
                        return response;
                    }
                } catch (SocketTimeoutException e) {
                    lastException = e;
                    log.error("请求超时: {}, 第 {} 次尝试", request.url(), i + 1, e);
                    if (response != null) {
                        response.close();
                    }
                } catch (IOException e) {
                    lastException = e;
                    log.error("请求失败: {}, 第 {} 次尝试", request.url(), i + 1, e);
                    if (response != null) {
                        response.close();
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new IOException("重试被中断", e);
                }
            }
            
            // 所有重试都失败了
            if (lastException != null) {
                log.error("所有重试都失败了: {}, 总共尝试 {} 次", request.url(), maxRetryCount + 1);
                throw lastException;
            }
            
            return response;
        };
    }
}