package top.octopusyan.config;

import kotlin.text.Charsets;
import okhttp3.*;
import okhttp3.logging.HttpLoggingInterceptor;
import okio.Buffer;
import okio.BufferedSource;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.octopusyan.http.ssl.HttpSslConfig;
import top.octopusyan.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 boolean showLog = false;
    public static final String TAG = "OkHttpLogger";
    private static final Logger log = LoggerFactory.getLogger(TAG);

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

    /**
     * 初始化okhttp client
     * @param logLevel 日志等级
     */
    public static OkHttpClient httpClient(HttpLoggingInterceptor.Level logLevel) {
        HttpLoggingInterceptor logginInterceptor = new HttpLoggingInterceptor(
                new HttpLoggingInterceptor.Logger() {
                    @Override
                    public void log(String message) {
                        try {
                            if(showLog) log.info(message);
                        } catch (Exception e) {
                            e.printStackTrace();
                            log.error(message);
                        }
                    }
                }
        );

//        setlevel用来设置日志打印的级别，共包括了四个级别：NONE,BASIC,HEADER,BODY
//        BASIC:请求/响应行
//        HEADERS:请求/响应行 + 头
//        BODY:请求/响应行 + 头 + 体
        //包含header、body数据
        logginInterceptor.setLevel(logLevel);

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

        HttpSslConfig httpSslConfig = HttpSslFactory.generateSslConfig();

        return new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)
                .addInterceptor(logginInterceptor)
                .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);
            }
            assert charset != null;
            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的字符串 并打印
            assert charset != null;
            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<>();
            }
        };
    }
}
