package xlike.top.api.utils;

import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author muchi
 */
public class OkHttpUtils {

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

    // 设置超时时间 30秒 (默认的是10秒)
    private static final int DEFAULT_READ_TIMEOUT = 30;
    private static final int DEFAULT_CONNECT_TIMEOUT = 30;

    // 获取OkHttpClient实例(可自定义超时和代理)
    private static OkHttpClient getClient(Integer connectTimeout, Integer readTimeout, Proxy proxy) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();

        builder.connectTimeout(Objects.requireNonNullElse(connectTimeout, DEFAULT_CONNECT_TIMEOUT), TimeUnit.SECONDS);

        builder.readTimeout(Objects.requireNonNullElse(readTimeout, DEFAULT_READ_TIMEOUT), TimeUnit.SECONDS);

        if (proxy != null) {
            builder.proxy(proxy);
            logger.info("使用代理服务器 {}:{}", proxy.address().toString(), ((InetSocketAddress) proxy.address()).getPort());
        }

        return builder.build();
    }

    // 通用请求方法
    private static Response sendRequest(String url, String method, Map<String, String> headers, RequestBody body,
                                        Integer connectTimeout, Integer readTimeout, Proxy proxy) throws IOException {
        logger.info("准备发送 {} 请求到 URL: {}", method, url);

        Request.Builder requestBuilder = new Request.Builder().url(url).method(method, body);

        if (headers != null) {
            for (Map.Entry<String, String> header : headers.entrySet()) {
                requestBuilder.addHeader(header.getKey(), header.getValue());
                logger.debug("添加请求头:{} = {}", header.getKey(), header.getValue());
            }
        }

        Request request = requestBuilder.build();
        OkHttpClient client = getClient(connectTimeout, readTimeout, proxy);
        long startTimeMillis  = System.currentTimeMillis();
        LocalDateTime startTime = LocalDateTime.now();
        DateTimeFormatter beginFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        try {
            logger.info("请求开始,当前时间: {}", startTime.format(beginFormatter));
            Response response = client.newCall(request).execute();
            long endTimeMillis = System.currentTimeMillis();
            LocalDateTime endTime = LocalDateTime.now();
            DateTimeFormatter endFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            logger.info("请求结束,当前时间: {} ,耗时 {} 毫秒,返回状态码: {}", endTime.format(endFormatter), (endTimeMillis - startTimeMillis), response.code());

            return response;
        } catch (IOException e) {
            long errorTimeMillis = System.currentTimeMillis();
            logger.error("请求失败,耗时 {} 毫秒,错误信息: {}", (errorTimeMillis - startTimeMillis), e.getMessage());
            throw e;
        }
    }

    // GET请求(可自定义超时和代理)
    public static Response get(String url, Map<String, String> headers, Integer connectTimeout,
                               Integer readTimeout, Proxy proxy) throws IOException {
        return sendRequest(url, "GET", headers, null, connectTimeout, readTimeout, proxy);
    }

    // GET请求(使用默认超时和无代理)
    public static Response get(String url, Map<String, String> headers) throws IOException {
        return get(url, headers, null, null, null);
    }

    // GET请求(无自定义请求头,使用默认超时和无代理)
    public static Response get(String url) throws IOException {
        return get(url, null);
    }

    // POST请求(可自定义超时和代理)
    public static Response post(String url, Map<String, String> headers, RequestBody body, Integer connectTimeout,
                                Integer readTimeout, Proxy proxy) throws IOException {
        return sendRequest(url, "POST", headers, body, connectTimeout, readTimeout, proxy);
    }

    // POST请求(使用默认超时和无代理)
    public static Response post(String url, Map<String, String> headers, RequestBody body) throws IOException {
        return post(url, headers, body, null, null, null);
    }

    // POST请求(无自定义请求头,使用默认超时和无代理)
    public static Response post(String url, RequestBody body) throws IOException {
        return post(url, null, body);
    }

    // PUT请求(可自定义超时和代理)
    public static Response put(String url, Map<String, String> headers, RequestBody body, Integer connectTimeout,
                               Integer readTimeout, Proxy proxy) throws IOException {
        return sendRequest(url, "PUT", headers, body, connectTimeout, readTimeout, proxy);
    }

    // DELETE请求(可自定义超时和代理)
    public static Response delete(String url, Map<String, String> headers, Integer connectTimeout,
                                  Integer readTimeout, Proxy proxy) throws IOException {
        return sendRequest(url, "DELETE", headers, null, connectTimeout, readTimeout, proxy);
    }

    // 使用代理
    public static Proxy createProxy(String hostname, int port) {
        logger.info("创建代理,主机名: {},端口: {}", hostname, port);
        return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(hostname, port));
    }

    // 创建JSON请求体
    public static RequestBody createJsonRequestBody(String json) {
        logger.info("创建JSON请求体: {}", json);
        return RequestBody.create(json, MediaType.get("application/json; charset=utf-8"));
    }

    // 创建表单请求体
    public static RequestBody createFormRequestBody(Map<String, String> formData) {
        FormBody.Builder formBuilder = new FormBody.Builder();
        for (Map.Entry<String, String> entry : formData.entrySet()) {
            formBuilder.add(entry.getKey(), entry.getValue());
            logger.debug("添加表单字段:{} = {}", entry.getKey(), entry.getValue());
        }
        return formBuilder.build();
    }

    // 获取响应体字符串
    public static String getResponseBodyAsString(Response response) throws IOException {
        if (response.body() != null) {
            String responseBody = response.body().string();
            logger.debug("响应体内容: {}", responseBody);
            return responseBody;
        }
        return null;
    }

    // 关闭响应
    public static void closeResponse(Response response) {
        if (response != null && response.body() != null) {
            logger.info("关闭响应,URL: {}", response.request().url());
            response.close();
        }
    }
}