package com.qdb.sdk.util;

import com.qdb.sdk.QdbConfig;
import com.qdb.sdk.QdbException;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;

import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

/**
 * HTTP 工具类
 * <p>
 * 基于 OkHttp 实现 HTTP 请求，提供 POST 请求（JSON 方式）的封装。
 * 企得宝ERP API 调用方式：
 * <ul>
 *   <li>公共参数拼接到 URL Query String</li>
 *   <li>业务参数以 JSON 格式放入 Request Body</li>
 *   <li>签名由公共参数计算得出</li>
 * </ul>
 * </p>
 *
 * @author qdb-sdk
 * @version 1.0.0
 */
@Slf4j
public class HttpUtil {

    private final OkHttpClient client;
    private static final MediaType JSON_TYPE = MediaType.parse("application/json; charset=utf-8");

    /**
     * 构造方法
     *
     * @param config SDK 配置
     */
    public HttpUtil(QdbConfig config) {
        this.client = new OkHttpClient.Builder()
                .connectTimeout(config.getConnectTimeout(), TimeUnit.SECONDS)
                .readTimeout(config.getReadTimeout(), TimeUnit.SECONDS)
                .writeTimeout(config.getWriteTimeout(), TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .build();
    }

    /**
     * 执行 API POST 请求
     * <p>
     * 请求方式：
     * <ol>
     *   <li>生成公共参数（包含 sign 签名）</li>
     *   <li>将公共参数拼接到 URL Query String</li>
     *   <li>业务参数以 JSON 格式放入 Request Body</li>
     *   <li>发送 POST 请求</li>
     * </ol>
     * </p>
     *
     * @param config        SDK 配置
     * @param method        API 方法名
     * @param businessJson  业务参数 JSON 字符串
     * @return 响应 JSON 字符串
     * @throws QdbException 请求失败时抛出
     */
    public String post(QdbConfig config, String method, String businessJson) throws QdbException {
        try {
            // 构建公共参数
            Map<String, String> publicParams = buildPublicParams(config, method);

            // 计算签名
            String sign = SignUtil.generateSign(publicParams, config.getClientSecret());
            publicParams.put("sign", sign);

            // 拼接完整 URL：baseUrl + query string
            String url = buildUrl(config.getApiUrl(), publicParams);

            log.debug("QDB API 请求 URL: {}", url);
            log.debug("QDB API Method: {}", method);
            log.debug("QDB API 业务参数: {}", businessJson);

            // 创建请求体（JSON 格式）
            RequestBody body = RequestBody.create(businessJson, JSON_TYPE);

            // 创建请求
            Request request = new Request.Builder()
                    .url(url)
                    .header("Content-Type", "application/json")
                    .post(body)
                    .build();

            // 执行请求
            try (Response response = client.newCall(request).execute()) {
                log.debug("QDB API 响应状态码: {}", response.code());

                if (!response.isSuccessful()) {
                    throw new QdbException("HTTP 请求失败，状态码: " + response.code());
                }

                ResponseBody responseBody = response.body();
                String responseStr = responseBody != null ? responseBody.string() : "";
                log.debug("QDB API 响应体: {}", responseStr);
                return responseStr;
            }

        } catch (IOException e) {
            log.error("QDB API 网络请求异常", e);
            throw new QdbException("网络请求异常: " + e.getMessage(), e);
        }
    }

    /**
     * 构建公共参数
     *
     * @param config SDK 配置
     * @param method API 方法名
     * @return 公共参数 Map
     */
    private Map<String, String> buildPublicParams(QdbConfig config, String method) {
        Map<String, String> params = new TreeMap<>();
        params.put("client_id", config.getClientId());
        params.put("format", config.getFormat());
        params.put("method", method);
        params.put("partner_id", config.getPartnerId());
        params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        params.put("v", config.getVersion());
        return params;
    }

    /**
     * 拼接 URL 和查询参数
     *
     * @param baseUrl API 基础 URL
     * @param params  查询参数
     * @return 完整 URL
     */
    private String buildUrl(String baseUrl, Map<String, String> params) {
        StringBuilder url = new StringBuilder(baseUrl);
        url.append("?");
        boolean first = true;
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (!first) {
                url.append("&");
            }
            url.append(entry.getKey()).append("=").append(entry.getValue());
            first = false;
        }
        return url.toString();
    }

    /**
     * 关闭 HTTP 客户端，释放资源
     */
    public void close() {
        if (client != null) {
            client.dispatcher().executorService().shutdown();
            client.connectionPool().evictAll();
        }
    }
}
