package top.octopusyan.http;

import kotlin.text.Charsets;
import okhttp3.*;
import okio.Buffer;
import okio.BufferedSource;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.octopusyan.manager.http.ssl.HttpSslConfig;
import top.octopusyan.manager.http.ssl.HttpSslFactory;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author : octopus yan
 * @email : octopus_yan@foxmail.com
 * @description :  okhttp 设置
 * @create : 2022-4-2 15:27
 */
public class OkHttpClientConfig {
    public static final String TAG = "OkHttpClientConfig";
    private static final Logger log = LoggerFactory.getLogger(TAG);


    public static final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();

    public static OkHttpClient httpClient() {
        Interceptor tokenInterceptor = new Interceptor() {//全局拦截器，往请求头部添加 token 字段，实现全局添加 token
            @Override
            public Response intercept(Chain chain) throws IOException {// 打印请求报文
                // 获取请求
                Request request = chain.request();
                // 取出请求参数
                String reqBody = getRequestBody(request);

                // 打印请求报文
                log.info("【" + TAG + "】 " + String.format("发送新请求\n-\tmethod：%s\n-\turl：%s\n-\theaders: %s\n-\tbody：%s",
                        request.method(), request.url(), request.headers(), reqBody));
                // 执行请求，获取响应报文
                Response response = chain.proceed(request);
                // 获取响应内容 TODO 读取结果乱码
                String respBody = getResponseBody(response);
                // 打印响应报文
//                log.info("【" + TAG + "】 " + String.format("收到响应 %s %s\n-\t请求url：%s\n-\t请求body：%s\n-\t响应body：%s",
//                        response.code(), response.message(), response.request().url(), reqBody, respBody));
                log.info("【" + TAG + "】 " + String.format("收到响应 %s %s\n-\t请求url：%s\n-\t请求body：%s",
                        response.code(), response.message(), response.request().url(), reqBody));

                return response;
            }
        };

        Dispatcher dispatcher = new Dispatcher();
        dispatcher.setMaxRequests(16);
        dispatcher.setMaxRequestsPerHost(4);

        HttpSslConfig httpSslConfig = HttpSslFactory.generateSslConfig();

        return new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)
                .addNetworkInterceptor(tokenInterceptor)
                .dispatcher(dispatcher)
                .cookieJar(cookieJar())
                .connectionPool(new ConnectionPool(16, 5, TimeUnit.MINUTES))
                .connectTimeout(10L, TimeUnit.SECONDS)
                .readTimeout(30L, TimeUnit.SECONDS)
                .writeTimeout(0L, TimeUnit.SECONDS)
                .pingInterval(60L, TimeUnit.SECONDS)
                .sslSocketFactory(httpSslConfig.getSslSocketFactory(), httpSslConfig.getTrustManager())
                .hostnameVerifier(HttpSslFactory.generateUnSafeHostnameVerifier())
                .build();
    }

    /**
     * 获取请求体
     */
    private static String getRequestBody(Request request) throws IOException {
        RequestBody requestBody = request.body();
        String reqBody = null;
        if (requestBody != null) {
            Buffer buffer = new Buffer();
            requestBody.writeTo(buffer);

            Charset charset = StandardCharsets.UTF_8;
            MediaType contentType = requestBody.contentType();
            if (contentType != null) {
                charset = contentType.charset(StandardCharsets.UTF_8);
            }
            reqBody = buffer.readString(charset);
        }

        return reqBody;
    }

    /**
     * 获取返回体
     */
    private static String getResponseBody(Response response) throws IOException {
        ResponseBody responseBody = response.body();
        String respBody = null;
        if (responseBody != null) {
            BufferedSource source = responseBody.source();
            source.request(Long.MAX_VALUE); // Buffer the entire body.
            Buffer buffer = source.getBuffer();

            Charset charset = Charsets.UTF_8;
            MediaType contentType = responseBody.contentType();
            if (contentType != null)
                charset = contentType.charset(charset);

            //获取Response的body的字符串 并打印
            respBody = buffer.clone().readString(charset);
        }

        return respBody;
    }

    private static CookieJar cookieJar() {
        return new CookieJar() {
            @Override
            public void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) {
                cookieStore.put(httpUrl.host(), list);
            }

            @NotNull
            @Override
            public List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) {
                List<Cookie> cookies = cookieStore.get(httpUrl.host());
                return cookies != null ? cookies : new ArrayList<Cookie>();
            }
        };
    }
}
