package cn.hztech.sdk.client;

import cn.hztech.sdk.crypto.envelope.GmPacket;
import cn.hztech.sdk.crypto.envelope.GmPacketBuilder;
import cn.hztech.sdk.crypto.envelope.GmPacketParser;
import cn.hztech.sdk.exception.ApiException;
import cn.hztech.sdk.model.response.ApiResponse;
import cn.hztech.sdk.util.JsonUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;

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

/**
 * SDK HTTP客户端
 *
 * 功能：
 * - 封装HTTP请求
 * - 自动处理报文加解密
 * - 统一异常处理
 * - 支持泛型响应
 */
@Slf4j
public class SdkHttpClient {

    private final String gatewayUrl;
    private final GmPacketBuilder packetBuilder;
    private final GmPacketParser packetParser;
    private final OkHttpClient httpClient;
    private final ObjectMapper objectMapper;

    public SdkHttpClient(String gatewayUrl, Integer connectTimeout,
                        Integer readTimeout, Integer writeTimeout,
                        GmPacketBuilder packetBuilder, GmPacketParser packetParser,
                        boolean enableLog, boolean enableRetry, int maxRetries, long retryInterval) {
        this.gatewayUrl = gatewayUrl;
        this.packetBuilder = packetBuilder;
        this.packetParser = packetParser;
        this.objectMapper = JsonUtil.getObjectMapper();

        OkHttpClient.Builder builder = new OkHttpClient.Builder()
            .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
            .readTimeout(readTimeout, TimeUnit.MILLISECONDS)
            .writeTimeout(writeTimeout, TimeUnit.MILLISECONDS)
            .addInterceptor(new LoggingInterceptor(enableLog));

        if (enableRetry) {
            builder.addInterceptor(new RetryInterceptor(enableRetry, maxRetries, retryInterval));
        }

        this.httpClient = builder.build();

        log.info("SDK HTTP客户端初始化完成, 网关URL: {}", gatewayUrl);
    }

    /**
     * 发送POST请求
     *
     * @param apiPath API路径
     * @param requestData 请求数据
     * @param responseType 响应类型
     * @return 响应数据
     */
    public <T> T post(String apiPath, Object requestData, Class<T> responseType) {
        try {
            // 1. 序列化请求数据（如果已经是String则直接使用）
            String requestJson = (requestData instanceof String)
                ? (String) requestData
                : objectMapper.writeValueAsString(requestData);
            log.debug("请求数据: {}", requestJson);

            // 2. 构建加密报文
            GmPacket packet = packetBuilder.build(requestJson);
            String packetJson = objectMapper.writeValueAsString(packet);
            log.debug("加密报文: {}", packetJson);

            // 3. 发送HTTP请求
            String fullUrl = gatewayUrl + apiPath;
            Request request = new Request.Builder()
                .url(fullUrl)
                .post(RequestBody.create(packetJson, MediaType.parse("application/json")))
                .build();

            log.info("发送请求: POST {}", apiPath);

            try (Response response = httpClient.newCall(request).execute()) {
                if (!response.isSuccessful()) {
                    throw new ApiException(response.code(), "HTTP请求失败: " + response.code());
                }

                String responseBody = response.body() != null ? response.body().string() : "";
                log.debug("响应数据: {}", responseBody);

                // 4. 解析加密报文响应
                GmPacket responsePacket = objectMapper.readValue(responseBody, GmPacket.class);

                // 5. 解密响应报文
                String decryptedData = packetParser.parse(responsePacket);
                log.debug("解密后的响应数据: {}", decryptedData);

                // 6. 解析ApiResponse
                ApiResponse apiResponse = objectMapper.readValue(decryptedData, ApiResponse.class);

                if (apiResponse.getCode() != 200) {
                    throw new ApiException(
                        String.format("API调用失败: code=%d, message=%s",
                        apiResponse.getCode(), apiResponse.getMessage())
                    );
                }

                // 7. 返回业务数据
                if (apiResponse.getData() != null) {
                    // 如果返回类型是String，直接返回JSON字符串
                    if (responseType == String.class) {
                        return (T) objectMapper.writeValueAsString(apiResponse.getData());
                    }
                    // 否则转换为指定类型
                    return objectMapper.convertValue(apiResponse.getData(), responseType);
                }

                return null;
            }

        } catch (ApiException e) {
            throw e;
        } catch (Exception e) {
            log.error("请求失败", e);
            throw new ApiException("请求失败: " + e.getMessage(), e);
        }
    }

    /**
     * 发送POST请求（支持泛型）
     *
     * @param apiPath API路径
     * @param requestData 请求数据
     * @param responseTypeRef 响应类型引用（支持泛型）
     * @return 响应数据
     */
    public <T> T post(String apiPath, Object requestData, TypeReference<T> responseTypeRef) {
        try {
            // 1. 序列化请求数据（如果已经是String则直接使用）
            String requestJson = (requestData instanceof String)
                ? (String) requestData
                : objectMapper.writeValueAsString(requestData);
            log.debug("请求数据: {}", requestJson);

            // 2. 构建加密报文
            GmPacket packet = packetBuilder.build(requestJson);
            String packetJson = objectMapper.writeValueAsString(packet);
            log.debug("加密报文: {}", packetJson);

            // 3. 发送HTTP请求
            String fullUrl = gatewayUrl + apiPath;
            Request request = new Request.Builder()
                .url(fullUrl)
                .post(RequestBody.create(packetJson, MediaType.parse("application/json")))
                .build();

            log.info("发送请求: POST {}", apiPath);

            try (Response response = httpClient.newCall(request).execute()) {
                if (!response.isSuccessful()) {
                    throw new ApiException(response.code(), "HTTP请求失败: " + response.code());
                }

                String responseBody = response.body() != null ? response.body().string() : "";
                log.debug("响应数据: {}", responseBody);

                // 4. 解析加密报文响应
                GmPacket responsePacket = objectMapper.readValue(responseBody, GmPacket.class);

                // 5. 解密响应报文
                String decryptedData = packetParser.parse(responsePacket);
                log.debug("解密后的响应数据: {}", decryptedData);

                // 6. 解析ApiResponse
                ApiResponse apiResponse = objectMapper.readValue(decryptedData, ApiResponse.class);

                if (apiResponse.getCode() != 200) {
                    throw new ApiException(
                        String.format("API调用失败: code=%d, message=%s",
                        apiResponse.getCode(), apiResponse.getMessage())
                    );
                }

                // 7. 返回业务数据（使用TypeReference保留泛型信息）
                if (apiResponse.getData() != null) {
                    // 如果返回类型是String，直接返回JSON字符串
                    if (String.class.equals(responseTypeRef.getType().getClass())) {
                        return (T) objectMapper.writeValueAsString(apiResponse.getData());
                    }
                    // 使用TypeReference转换，保留泛型信息
                    return objectMapper.convertValue(apiResponse.getData(), responseTypeRef);
                }

                return null;
            }

        } catch (ApiException e) {
            throw e;
        } catch (Exception e) {
            log.error("请求失败", e);
            throw new ApiException("请求失败: " + e.getMessage(), e);
        }
    }
}
