package com.qqchen.deploy.backend.workflow.delegate;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qqchen.deploy.backend.framework.utils.JsonUtils;
import com.qqchen.deploy.backend.workflow.dto.inputmapping.HttpRequestInputMapping;
import com.qqchen.deploy.backend.workflow.dto.outputs.HttpRequestOutputs;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * HTTP请求节点委托
 *
 * @author qqchen
 * @since 2025-11-20
 */
@Slf4j
@Component("httpRequestDelegate")
public class HttpRequestNodeDelegate extends BaseNodeDelegate<HttpRequestInputMapping, HttpRequestOutputs> {

    @Resource
    private ObjectMapper objectMapper;

    @Override
    protected void executeInternal(DelegateExecution execution, Map<String, Object> configs, HttpRequestInputMapping input) {
        long startTime = System.currentTimeMillis();

        try {

            // 1. 创建专属的RestTemplate，使用节点配置的超时时间
            RestTemplate restTemplate = createRestTemplate(input.getTimeout());

            // 2. 构建请求
            HttpHeaders headers = buildHeaders(input.getHeadersAsMap());
            HttpEntity<?> entity = new HttpEntity<>(input.getBody(), headers);

            // 3. 构建完整URL（带查询参数）
            String fullUrl = buildUrl(input.getUrl(), input.getQueryParamsAsMap());

            if (input.getBody() != null) {
                logInfo(String.format("请求体: %s", JsonUtils.toJson(input.getBody())));
            }

            // 4. 发送HTTP请求
            ResponseEntity<String> response = restTemplate.exchange(
                fullUrl,
                input.getMethod(),
                entity,
                String.class
            );

            // 4. 解析响应
            long responseTime = System.currentTimeMillis() - startTime;
            parseResponse(response, responseTime, input.getResponseBodyType());

            logInfo(String.format("HTTP请求成功: 状态码=%d, 耗时=%dms, 响应大小=%d bytes", output.getStatusCode(), output.getResponseTime(), output.getResponseSize()));

        } catch (HttpClientErrorException | HttpServerErrorException e) {
            // HTTP错误（4xx, 5xx）
            handleHttpError(e, System.currentTimeMillis() - startTime);
        } catch (Exception e) {
            // 其他错误（网络超时、连接失败等）
            handleGeneralError(e);
        }
    }

    /**
     * 解析响应
     */
    private void parseResponse(ResponseEntity<String> response, long responseTime,
                               HttpRequestInputMapping.ResponseBodyType type) {
        output.setStatusCode(response.getStatusCode().value());
        output.setResponseTime(responseTime);
        output.setIsSuccess(response.getStatusCode().is2xxSuccessful());

        // 解析响应头
        Map<String, String> headerMap = new HashMap<>();
        response.getHeaders().forEach((k, v) ->
            headerMap.put(k, String.join(", ", v))
        );
        output.setResponseHeaders(headerMap);

        // 解析响应体
        String body = response.getBody();
        if (body != null) {
            output.setResponseSize((long) body.length());

            switch (type) {
                case JSON -> {
                    try {
                        // 尝试解析为JSON对象或数组
                        Object jsonBody = parseJsonBody(body);
                        output.setResponseBody(jsonBody);
                        logInfo(String.format("响应体(JSON): %s", body.length() > 500 ? body.substring(0, 500) + "..." : body));
                    } catch (Exception e) {
                        log.warn("JSON解析失败，返回原始文本: {}", e.getMessage());
                        output.setResponseBody(body);
                    }
                }
                case TEXT -> {
                    output.setResponseBody(body);
                    logInfo(String.format("响应体(TEXT): %s", body.length() > 200 ?
                        body.substring(0, 200) + "..." : body));
                }
                case XML -> output.setResponseBody(body); // 简化实现，直接返回文本
                case BINARY -> output.setResponseBody(body.getBytes());
            }
        }
    }

    /**
     * 解析JSON响应体
     */
    private Object parseJsonBody(String body) throws Exception {
        // 尝试解析为Map或List
        if (body.trim().startsWith("{")) {
            return objectMapper.readValue(body, Map.class);
        } else if (body.trim().startsWith("[")) {
            return objectMapper.readValue(body, List.class);
        } else {
            return body;
        }
    }

    /**
     * 处理HTTP错误（4xx, 5xx）
     * <p>
     * 业务失败：设置完整的 output 信息后抛出异常，由 BaseNodeDelegate 根据 continueOnFailure 决定是否继续
     */
    private void handleHttpError(Exception e, long responseTime) {
        HttpStatusCode statusCode = null;
        String responseBody = null;

        if (e instanceof HttpClientErrorException) {
            HttpClientErrorException clientError = (HttpClientErrorException) e;
            statusCode = clientError.getStatusCode();
            responseBody = clientError.getResponseBodyAsString();
        } else if (e instanceof HttpServerErrorException) {
            HttpServerErrorException serverError = (HttpServerErrorException) e;
            statusCode = serverError.getStatusCode();
            responseBody = serverError.getResponseBodyAsString();
        }

        // 设置详细的 output 信息
        output.setStatusCode(statusCode != null ? statusCode.value() : 0);
        output.setResponseTime(responseTime);
        output.setIsSuccess(false);
        output.setErrorMessage(e.getMessage());

        // ⚠️ 注意：HTTP 错误响应通常是 HTML 错误页面（不是 JSON），设置为 null 避免模板解析错误
        // 如果需要访问原始错误响应，可以从 errorMessage 中获取
        output.setResponseBody(null);

        if (responseBody != null && !responseBody.isEmpty()) {
            output.setResponseSize((long) responseBody.length());
        }

        String errorMsg = String.format("HTTP请求失败: 状态码=%d, 错误=%s",
            output.getStatusCode(), e.getMessage());

        logInfo(errorMsg);

        // 抛出异常，由 BaseNodeDelegate 根据 continueOnFailure 决定：
        // - continueOnFailure=true: 调用 markFailure(e)，设置 output.status=FAILURE，保存 output，继续执行
        // - continueOnFailure=false: 调用 terminateWorkflow(e)，抛出 BpmnError，终止工作流
        throw new RuntimeException(errorMsg, e);
    }

    /**
     * 处理一般错误（网络超时、连接失败等）
     * <p>
     * 技术异常：设置基本的 output 信息后抛出异常，由 BaseNodeDelegate 根据 continueOnFailure 决定是否继续
     */
    private void handleGeneralError(Exception e) {
        // 设置基本的 output 信息（即使是网络异常也要设置，方便模板访问）
        output.setIsSuccess(false);
        output.setStatusCode(0);  // 0 表示未获取到 HTTP 状态码
        output.setErrorMessage(e.getMessage());
        output.setResponseBody(null);

        String errorMsg = String.format("HTTP请求异常: %s - %s",
            e.getClass().getSimpleName(), e.getMessage());

        logInfo(errorMsg);

        // 抛出异常，由 BaseNodeDelegate 根据 continueOnFailure 决定：
        // - continueOnFailure=true: 调用 markFailure(e)，设置 output.status=FAILURE，保存 output，继续执行
        // - continueOnFailure=false: 调用 terminateWorkflow(e)，抛出 BpmnError，终止工作流
        throw new RuntimeException(errorMsg, e);
    }

    /**
     * 创建RestTemplate（使用节点配置的超时时间）
     */
    private RestTemplate createRestTemplate(Integer timeout) {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();

        // 使用节点配置的超时时间
        int timeoutMs = (timeout != null && timeout > 0) ? timeout : 30000;

        // 连接超时：建立TCP连接的超时时间
        factory.setConnectTimeout(timeoutMs);

        // 读取超时：等待服务器响应的超时时间
        factory.setReadTimeout(timeoutMs);

        RestTemplate restTemplate = new RestTemplate(factory);
        return restTemplate;
    }

    /**
     * 构建请求头
     */
    private HttpHeaders buildHeaders(Map<String, String> headersMap) {
        HttpHeaders headers = new HttpHeaders();

        // 默认设置 Content-Type 为 JSON（如果有body且未指定）
        if (currentInputMapping.getBody() != null &&
            (headersMap == null || !headersMap.containsKey("Content-Type"))) {
            headers.setContentType(MediaType.APPLICATION_JSON);
        }

        if (headersMap != null) {
            headersMap.forEach(headers::set);
        }

        return headers;
    }

    /**
     * 构建完整URL（带查询参数）
     */
    private String buildUrl(String baseUrl, Map<String, String> queryParams) {
        if (queryParams == null || queryParams.isEmpty()) {
            return baseUrl;
        }

        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl);
        queryParams.forEach(builder::queryParam);
        return builder.toUriString();
    }
}
