package com.cmvr.llm.service;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.cmvr.common.exception.GlobalException;
import com.cmvr.common.utils.http.CallAPIUtil;
import com.cmvr.llm.config.APIProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

/**
 * 商道大模型工作流调用服务
 * 流程：
 * 1. 调用工作流启动接口，获取 runId
 * 2. 根据 runId 轮询查询接口
 * 3. 解析结果
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WorkflowInvokeService {

    private final APIProperties apiProperties;

    /**
     * 用户ID可以作为全局常量
     */
    private static final String USER_ID = "18888888888";

    /**
     * 默认最大重试次数
     */
    private static final int DEFAULT_MAX_RETRY = 40;

    /**
     * 默认轮询间隔（毫秒）
     */
    private static final int DEFAULT_INTERVAL_MS = 1000;

    /**
     * 一站式执行工作流（带自定义重试参数）
     *
     * @param appId       智能体应用ID
     * @param appKey      智能体应用秘钥
     * @param inputParams 输入参数（业务参数，例如图片、描述等）
     * @param maxRetry    最大重试次数
     * @param intervalMs  每次轮询间隔（毫秒）
     * @return 最终结果 message
     */
    public JSONObject executeWorkflow(String appId, String appKey,
                                  Map<String, String> inputParams,
                                  int maxRetry, long intervalMs) {
        // 1. 启动工作流，获取 runId
        String runId = startWorkflow(appId, appKey, inputParams);

        // 2. 轮询获取结果
        String responseBody = pollResult(runId, appId, appKey, maxRetry, intervalMs);

        // 3. 解析
        return parseResponse(responseBody);
    }

    /**
     * 一站式执行工作流（使用默认重试参数）
     *
     * @param appId       智能体应用ID
     * @param appKey      智能体应用秘钥
     * @param inputParams 输入参数（业务参数，例如图片、描述等）
     * @return 最终结果 message
     */
    public JSONObject executeWorkflow(String appId, String appKey, Map<String, String> inputParams) {
        return executeWorkflow(appId, appKey, inputParams, DEFAULT_MAX_RETRY, DEFAULT_INTERVAL_MS);
    }

    // ------------------- 核心流程 -------------------

    /**
     * 启动工作流，返回 runId
     *
     * @param appId       智能体应用ID
     * @param appKey      智能体应用秘钥
     * @param inputParams 输入参数
     * @return 工作流运行ID-runId
     */
    private String startWorkflow(String appId, String appKey, Map<String, String> inputParams) {
        Map<String, String> headers = buildHeaders(appKey);
        Map<String, String> body = buildRequestBody(appKey, appId, inputParams);

        String responseBody = CallAPIUtil.doPostJson(apiProperties.getWorkFlowUrl(), headers, body);
        JSONObject jsonObject = JSON.parseObject(responseBody);

        String runId = jsonObject.getString("runId");
        if (StrUtil.isEmpty(runId)) {
            throw new GlobalException("未返回 runId，响应：{}", responseBody);
        }
        return runId;
    }

    /**
     * 轮询查询接口，直到获取到 end 节点
     *
     * @param runId      工作流运行ID
     * @param appId      智能体应用ID
     * @param appKey     智能体应用秘钥
     * @param maxRetry   最大重试次数
     * @param intervalMs 轮询间隔（毫秒）
     * @return 最终响应 JSON 字符串
     */
    private String pollResult(String runId, String appId, String appKey, int maxRetry, long intervalMs) {
        Map<String, String> headers = buildHeaders(appKey);
        Map<String, String> body = buildBaseBody(appKey, appId);
        body.put("RunID", runId);

        int failCount = 0;
        while (true) {
            String responseBody = CallAPIUtil.doPostJson(apiProperties.getQueryResultUrl(), headers, body);
            JSONObject root = JSON.parseObject(responseBody);
            String status = root.getString("status");

            if ("success".equalsIgnoreCase(status)) {
                // 校验并返回最终结果
                parseResponse(responseBody);
                return responseBody;
            } else if ("processing".equalsIgnoreCase(status)) {
                // 继续轮询
                failCount++;
                if (failCount > maxRetry) {
                    throw new GlobalException("轮询超时，达到最大重试次数，最后响应：{}", responseBody);
                }
                try {
                    Thread.sleep(intervalMs);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new GlobalException("轮询被中断");
                }
            } else {
                // 其他状态直接抛异常，不再重试
                throw new GlobalException("工作流执行失败，status={}，响应：{}", status, responseBody);
            }
        }
    }

    // ------------------- 结果解析 -------------------

    /**
     * 从响应 JSON 中找到 nodeType=end 且 status=success 的节点
     */
    private JSONObject findEndNode(String responseBody) {
        JSONObject root = JSON.parseObject(responseBody);
        JSONObject nodes = root.getJSONObject("nodes");
        if (nodes == null) {
            throw new GlobalException("响应中 nodes 为空：{}", responseBody);
        }

        for (Map.Entry<String, Object> entry : nodes.entrySet()) {
            JSONObject node = (JSONObject) entry.getValue();
            if ("end".equalsIgnoreCase(node.getString("nodeType"))
                    && "success".equalsIgnoreCase(node.getString("status"))) {
                return node;
            }
        }
        throw new GlobalException("未找到 nodeType=end 且 status=success 的节点：{}", nodes);
    }

    /**
     * 解析 end 节点的 output 内容
     *
     * @param endNode end 节点
     * @return output JSON
     */
    private JSONObject parseOutput(JSONObject endNode) {
        String outputStr = endNode.getString("output");
        if (StrUtil.isEmpty(outputStr)) {
            throw new GlobalException("end 节点 output 为空：{}", endNode);
        }
        try {
            return JSON.parseObject(outputStr);
        } catch (Exception e) {
            throw new GlobalException("output 解析失败：{}", outputStr);
        }
    }

    /**
     * 接卸
     *
     * @param responseBody 响应 JSON 字符串
     * @return message
     */
    private JSONObject parseResponse(String responseBody) {
        JSONObject endNode = findEndNode(responseBody);
        JSONObject output = parseOutput(endNode);

        JSONObject nestedOutput = output.getJSONObject("output");
        if (ObjUtil.isEmpty(nestedOutput)) {
            throw new GlobalException("end node output 为空!");
        }
        return nestedOutput;
    }

    // ------------------- 请求体拼装 -------------------

    /**
     * 构造请求头
     *
     * @param appKey 应用秘钥
     * @return headers
     */
    private Map<String, String> buildHeaders(String appKey) {
        Map<String, String> headers = new HashMap<>();
        headers.put("Apikey", appKey);
        return headers;
    }

    /**
     * 构造启动工作流的请求体
     *
     * @param appKey      应用秘钥
     * @param appId       应用ID
     * @param inputParams 输入参数
     * @return body
     */
    private Map<String, String> buildRequestBody(String appKey, String appId, Map<String, String> inputParams) {
        Map<String, String> body = buildBaseBody(appKey, appId);
        body.put("InputData", JSON.toJSONString(inputParams));
        return body;
    }

    /**
     * 构造通用请求体
     *
     * @param appKey 应用秘钥
     * @param appId  应用ID
     * @return body
     */
    private Map<String, String> buildBaseBody(String appKey, String appId) {
        Map<String, String> body = new HashMap<>();
        body.put("AppKey", appKey);
        body.put("AppID", appId);
        body.put("UserID", USER_ID);
        return body;
    }
}
