package com.ruoyi.cms.util.oauth;

import com.alibaba.fastjson2.JSON;
import lombok.Data;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * 简化版 HTTP 客户端工具类（仅保留核心POST功能，保留超时配置）
 */
public class HttpUtils {
    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);

    // 保留默认超时配置
    private static final int DEFAULT_CONNECT_TIMEOUT = 10;
    private static final int DEFAULT_READ_TIMEOUT = 30;
    private static final int DEFAULT_WRITE_TIMEOUT = 30;

    // 媒体类型常量
    public static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
    public static final MediaType FORM_MEDIA_TYPE = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");

    // OkHttp 客户端（单例）
    private static final OkHttpClient OK_HTTP_CLIENT;

    static {
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .connectTimeout(DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(DEFAULT_WRITE_TIMEOUT, TimeUnit.SECONDS);

        OK_HTTP_CLIENT = builder.build();
    }

    /**
     * POST JSON请求（默认超时）
     */
    public static String doPostJson(String url, Map<String, Object> params) throws TimeoutException, IOException {
        return doPostJson(url, params, DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT, DEFAULT_WRITE_TIMEOUT);
    }

    /**
     * POST JSON请求（自定义超时）
     */
    public static String doPostJson(String url, Map<String, Object> params, int connectTimeout, int readTimeout, int writeTimeout)
            throws TimeoutException, IOException {
        String jsonParams = CollectionUtils.isEmpty(params) ? "{}" : JSON.toJSONString(params);
        return doPost(url, jsonParams, JSON_MEDIA_TYPE, null, connectTimeout, readTimeout, writeTimeout);
    }

    /**
     * POST JSON请求（默认超时，支持自定义 headers）
     */
    public static String doPostJson(String url, Map<String, Object> params, Map<String, String> headers) throws TimeoutException, IOException {
        return doPostJson(url, params, headers, DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT, DEFAULT_WRITE_TIMEOUT);
    }

    /**
     * POST JSON请求（自定义超时和 headers）
     */
    public static String doPostJson(String url, Map<String, Object> params, Map<String, String> headers,
                                    int connectTimeout, int readTimeout, int writeTimeout) throws TimeoutException, IOException {
        String jsonParams = CollectionUtils.isEmpty(params) ? "{}" : JSON.toJSONString(params);
        return doPost(url, jsonParams, JSON_MEDIA_TYPE, headers, connectTimeout, readTimeout, writeTimeout);
    }

    /**
     * POST 表单请求（默认超时）
     */
    public static String doPostForm(String url, Map<String, Object> params) throws TimeoutException, IOException {
        return doPostForm(url, params, null, DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT, DEFAULT_WRITE_TIMEOUT);
    }

    /**
     * POST 表单请求（自定义超时）
     */
    public static String doPostForm(String url, Map<String, Object> params, Map<String, String> headers,
                                    int connectTimeout, int readTimeout, int writeTimeout)
            throws TimeoutException, IOException {
        FormBody.Builder formBuilder = new FormBody.Builder();
        if (!CollectionUtils.isEmpty(params)) {
            params.forEach((key, value) -> {
                if (value != null) {
                    formBuilder.add(encodeParam(key), value.toString());
                }
            });
        }
        RequestBody requestBody = formBuilder.build();

        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .post(requestBody)
                .header("Content-Type", FORM_MEDIA_TYPE.toString());

        addHeaders(requestBuilder, headers);
        return executeRequest(requestBuilder.build(), connectTimeout, readTimeout, writeTimeout);
    }

    /**
     * 通用POST方法
     */
    private static String doPost(String url, String content, MediaType mediaType, Map<String, String> headers,
                                 int connectTimeout, int readTimeout, int writeTimeout)
            throws TimeoutException, IOException {
        if (mediaType == null) {
            mediaType = JSON_MEDIA_TYPE;
        }
        RequestBody requestBody = RequestBody.create(mediaType,content);

        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .post(requestBody)
                .header("Content-Type", mediaType.toString());

        addHeaders(requestBuilder, headers);
        return executeRequest(requestBuilder.build(), connectTimeout, readTimeout, writeTimeout);
    }

    /**
     * 执行请求核心方法
     */
    private static String executeRequest(Request request, int connectTimeout, int readTimeout, int writeTimeout)
            throws TimeoutException, IOException {
        // 保留超时配置覆盖能力
        OkHttpClient tempClient = OK_HTTP_CLIENT.newBuilder()
                .connectTimeout(connectTimeout, TimeUnit.SECONDS)
                .readTimeout(readTimeout, TimeUnit.SECONDS)
                .writeTimeout(writeTimeout, TimeUnit.SECONDS)
                .build();

        try (Response response = tempClient.newCall(request).execute()) {
            return response.body() != null ? response.body().string() : "";
        } catch (SocketTimeoutException e) {
            throw new TimeoutException(String.format("HTTP 请求超时 | URL: %s | 超时配置: 连接%d秒, 读取%d秒, 写入%d秒",
                    request.url(), connectTimeout, readTimeout, writeTimeout));
        }
    }

    /**
     * 参数编码
     */
    private static String encodeParam(String param) {
        try {
            return URLEncoder.encode(param, "UTF-8");
        } catch (Exception e) {
            log.warn("参数编码失败 | param: {}", param, e);
            return param;
        }
    }

    /**
     * 添加请求头
     */
    private static void addHeaders(Request.Builder requestBuilder, Map<String, String> headers) {
        if (!CollectionUtils.isEmpty(headers)) {
            headers.forEach(requestBuilder::header);
        }
    }

    /**************************增加获取cookie开始******************************/
    @Data
    public static class ResponseWrapper {
        private String responseBody; // 响应体字符串
        private Map<String, List<String>> headers; // 响应头（key: 头名称，value: 多个值）
    }

    // HttpUtils 中新增方法：发送 POST JSON 请求，返回响应体 + 响应头
    public static ResponseWrapper doPostJsonWithHeaders(String url, Map<String, Object> params,
                                                        int connectTimeout, int readTimeout, int writeTimeout) throws IOException {
        String jsonParams = CollectionUtils.isEmpty(params) ? "{}" : JSON.toJSONString(params);
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody requestBody = RequestBody.create(mediaType, jsonParams);

        // 构建 OkHttpClient
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(connectTimeout, TimeUnit.SECONDS)
                .readTimeout(readTimeout, TimeUnit.SECONDS)
                .writeTimeout(writeTimeout, TimeUnit.SECONDS)
                .build();

        // 构建请求
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        // 执行请求，获取响应体和响应头
        try (Response response = client.newCall(request).execute()) {
            String responseBody = response.body() != null ? response.body().string() : "";
            Map<String, List<String>> headers = new HashMap<>();
            for (String headerName : response.headers().names()) {
                headers.put(headerName, response.headers(headerName));
            }

            // 封装并返回
            ResponseWrapper wrapper = new ResponseWrapper();
            wrapper.setResponseBody(responseBody);
            wrapper.setHeaders(headers);
            return wrapper;
        }
    }

    /**************************增加获取cookie结束******************************/
}