package com.xvji.service.task;

import com.alibaba.fastjson2.JSONObject;
import com.xvji.domain.Component;
import com.xvji.mapper.ComponentMapper;
import com.xvji.utils.FormDataHttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

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

/**
 * 任务组件执行器：负责调用任务关联的所有组件接口
 */
@org.springframework.stereotype.Component
public class TaskComponentExecutor {

    private ThreadLocal<String> analysisReportResult = new ThreadLocal<>();

    private static final Logger log = LoggerFactory.getLogger(TaskComponentExecutor.class);

    @Autowired
    private ComponentMapper componentMapper;

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 执行指定任务的所有组件接口
     * @param taskId 任务ID 训练任务或预测任务的ID
     * @param taskType 任务类型0=训练任务，1=预测任务
     */
    public void executeComponents(Long taskId, Integer taskType) {
        // 查询关联组件
        List<Component> components = componentMapper.selectByTaskIdAndType(taskId, taskType);
        if (components.isEmpty()) {
            log.warn("任务ID:{} 没有关联的组件，无需执行", taskId);
            return;
        }

        // 记录任务开始时间 计算总耗时
        long taskStartTime = System.currentTimeMillis();

        // 循环调用组件 失败立即终止并抛异常
        for (Component component : components) {
            // 跳过未启用的组件
            if (!component.getIsEnable()) {
                log.info("组件[{}]未启用，跳过执行", component.getComponentType());
                continue;
            }

            String componentName = component.getComponentType();
            String interfaceUrl = component.getInterfaceUrl();
            Map<String, Object> params = component.getParamsMap();
            long componentStartTime = System.currentTimeMillis();

            log.info("开始调用组件[{}]，接口地址：{}，参数：{}",
                    componentName, interfaceUrl, params);
            String compType1 = component.getComponentType();
            if (compType1 != null && compType1.contains("分析报告")) {
                String db = (String) params.get("mongodb_database");
                String table = (String) params.get("mongodb_read_table");
                log.info("=== 分析报告组件调用前检查 ===\n数据源：db={}, table={}\n参数列表：{}",
                        db, table, params);
            }
            try {
                // 调用组件接口
                ResponseEntity<String> response = FormDataHttpUtil.postFormData(interfaceUrl, params);
                long costTime = System.currentTimeMillis() - componentStartTime;
                String responseBody = response.getBody();

                // 解析响应体判断业务是否成功
                boolean isBusinessSuccess = true;
                if (responseBody != null && !responseBody.isEmpty()) {
                    try {
                        JSONObject resultJson = JSONObject.parseObject(responseBody);
                        // 处理success为布尔值或数字的情况
                        if (resultJson.containsKey("success")) {
                            Object successObj = resultJson.get("success");
                            if (successObj instanceof Boolean) {
                                isBusinessSuccess = (Boolean) successObj;
                            } else if (successObj instanceof Number) {
                                isBusinessSuccess = ((Number) successObj).intValue() == 1;
                            } else {
                                isBusinessSuccess = "1".equals(successObj.toString()) ||
                                        "true".equalsIgnoreCase(successObj.toString());
                            }
                        }
                    } catch (Exception e) {
                        log.warn("解析组件[{}]响应体失败，无法判断业务状态", componentName, e);
                    }
                }

                // 处理HTTP响应和业务响应
                if (!response.getStatusCode().is2xxSuccessful() || !isBusinessSuccess) {
                    // 提取错误信息
                    String errorDetail = extractErrorMessage(responseBody);
                    String errorMsg = String.format(
                            "组件[%s]执行失败（耗时：%dms），HTTP状态码：%d，业务状态：%s，错误信息：%s",
                            componentName,
                            costTime,
                            response.getStatusCodeValue(),
                            isBusinessSuccess ? "成功" : "失败",
                            errorDetail
                    );
                    log.error(errorMsg);
                    throw new RuntimeException(errorMsg); // 抛异常终止任务
                }

                log.info("组件[{}]业务执行成功（耗时：{}ms），返回结果：{}",
                        componentName,
                        costTime,
                        responseBody);

                // 分析报告组件：只提取file_path
                String compType = component.getComponentType();
                log.info("当前组件类型：{}，原始值：{}", compType, compType);
                if (compType != null && compType.contains("分析报告")) {
                    JSONObject resultJson = JSONObject.parseObject(responseBody);
                    String reportFilePath = resultJson.getString("file_path");
                    analysisReportResult.set(reportFilePath);
                    String db = (String) params.get("mongodb_database");
                    String table = (String) params.get("mongodb_read_table");
                    log.info("=== 分析报告组件日志 ===\n数据源：db={}, table={}\n提取的file_path：{}",
                            db, table, reportFilePath);
                }

            } catch (Exception e) {
                long costTime = System.currentTimeMillis() - componentStartTime;
                String rootErrorMsg = getRootErrorMessage(e);
                String errorMsg = String.format(
                        "组件[%s]调用异常（耗时：%dms）：%s",
                        componentName,
                        costTime,
                        rootErrorMsg
                );
                log.error(errorMsg, e);
                throw new RuntimeException(errorMsg, e); // 向外层抛出异常
            }
        }

        log.info("任务ID:{} 所有组件执行完成，总耗时：{}ms",
                taskId, System.currentTimeMillis() - taskStartTime);
    }

    /**
     * 提取错误信息
     */
    /*private String extractErrorMessage(String responseBody) {
        if (responseBody == null || responseBody.trim().isEmpty()) {
            return "无错误信息";
        }

        System.out.println("=== 数据获取组件完整错误响应 ===");
        System.out.println(responseBody);
        System.out.println("===============================");

        // 1. 优先用fastjson解析
        try {
            JSONObject resultJson = JSONObject.parseObject(responseBody);
            if (resultJson.containsKey("msg")) {
                String msg = resultJson.getString("msg");
                // 处理msg中的转义字符
                if (msg != null) {
                    msg = msg.replace("\\n", "\n").replace("\\t", "  ");
                    // 限制长度
                    int maxLength = Math.min(msg.length(), 1000);
                    return msg.substring(0, maxLength) + (msg.length() > 1000 ? "\n...（日志过长，已截断）" : "");
                }
            }
        } catch (Exception e) {
            log.debug("响应体不是标准JSON，尝试字符串提取，错误：{}", e.getMessage());
        }

        // 2. JSON解析失败，用原始字符串匹配
        // 不压缩字符串（保留\n、空格），直接匹配msg字段
        String lowerBody = responseBody.toLowerCase();
        int msgStart = lowerBody.indexOf("\"msg\":\"");
        if (msgStart == -1) {
            msgStart = lowerBody.indexOf("'msg':'"); // 匹配 'msg':'xxx' 格式
        }
        if (msgStart == -1) {
            msgStart = lowerBody.indexOf("msg\":\""); // 匹配 msg:"xxx" 格式（无引号）
        }

        if (msgStart != -1) {
            // 计算msg内容的起始位置（跳过"msg":"）
            int contentStart = msgStart + (lowerBody.startsWith("\"msg\":\"", msgStart) ? 6 :
                    lowerBody.startsWith("'msg':'", msgStart) ? 6 : 5);
            // 找msg内容的结束位置（匹配对应的引号）
            char quoteChar = responseBody.charAt(msgStart + 1); // 取msg字段的引号类型（"或'）
            int contentEnd = responseBody.indexOf(quoteChar, contentStart);
            if (contentEnd == -1) {
                contentEnd = responseBody.indexOf("}", contentStart); // 无引号则找JSON结束符
            }
            if (contentEnd == -1) {
                contentEnd = responseBody.indexOf(",", contentStart); // 找逗号
            }

            if (contentEnd > contentStart) {
                String msg = responseBody.substring(contentStart, contentEnd);
                // 处理转义字符
                msg = msg.replace("\\n", "\n").replace("\\t", "  ");
                int maxLength = Math.min(msg.length(), 1000);
                return msg.substring(0, maxLength) + (msg.length() > 1000 ? "\n...（日志过长，已截断）" : "");
            }
        }

        // 3. 最终 fallback：返回原始响应的前1000个字符
        int maxLength = Math.min(responseBody.length(), 1000);
        String fallback = responseBody.substring(0, maxLength);
        fallback = fallback.replace("\\n", "\n").replace("\\t", "  ");

        String finalResult = fallback + (responseBody.length() > 1000 ? "\n...（日志过长，已截断）" : "");
        log.debug("extractErrorMessage 处理后：长度={}，内容前200字符：{}",
                finalResult.length(),
                finalResult.substring(0, Math.min(finalResult.length(), 200)));

        return fallback + (responseBody.length() > 1000 ? "\n...（日志过长，已截断）" : "");
    }*/

    private String extractErrorMessage(String responseBody) {
    if (responseBody == null || responseBody.trim().isEmpty()) {
        return "无错误信息";
    }

    // 优先解析JSON 无论是否有msg字段，都返回完整内容
    try {
        JSONObject resultJson = JSONObject.parseObject(responseBody);
        // 若有msg字段，返回完整msg；若无，返回完整JSON
        if (resultJson.containsKey("msg")) {
            String msg = resultJson.getString("msg");
            return msg != null ? msg.replace("\\n", "\n").replace("\\t", "  ") : responseBody;
        } else {
            // 无msg字段，返回完整JSON
            return responseBody.replace("\\n", "\n").replace("\\t", "  ");
        }
    } catch (Exception e) {
        log.debug("响应体不是标准JSON，返回完整原始内容");
    }

    //JSON解析失败，返回完整原始响应
    return responseBody.replace("\\n", "\n").replace("\\t", "  ");
}


    /**
     * 提取错误信息
     */
    private String getRootErrorMessage(Throwable e) {
        Throwable root = e;
        // 找到最底层的异常
        while (root.getCause() != null && root.getCause() != root) {
            root = root.getCause();
        }
        // 返回原始错误信息
        return root.getMessage() != null ? root.getMessage() : e.getMessage();
    }

    // 提供方法获取分析报告结果
    public String getAnalysisReportResult() {
        return analysisReportResult.get();
    }

    // 任务执行完成后清理ThreadLocal 避免内存泄漏
    public void clearAnalysisReportResult() {
        analysisReportResult.remove();
    }
}