package tech.easyflow.ai.plugin.workflow.snapshot;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.easyagents.flow.core.chain.ChainDefinition;
import com.easyagents.flow.core.chain.Node;
import com.easyagents.flow.core.node.EndNode;
import org.springframework.stereotype.Service;
import tech.easyflow.ai.easyagentsflow.support.PublishedWorkflowDefinitionIds;
import tech.easyflow.ai.easyagentsflow.service.WorkflowDatacenterContentService;
import tech.easyflow.ai.easyagents.tool.WorkflowTool;
import tech.easyflow.ai.entity.Plugin;
import tech.easyflow.ai.entity.PluginItem;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.service.WorkflowService;
import com.easyagents.flow.core.parser.ChainParser;
import tech.easyflow.common.web.exceptions.BusinessException;

import java.util.List;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 工作流插件快照解析服务。
 */
@Service
public class WorkflowPluginSnapshotResolver {

    private final WorkflowService workflowService;
    private final ChainParser chainParser;
    private final WorkflowDatacenterContentService workflowDatacenterContentService;

    public WorkflowPluginSnapshotResolver(WorkflowService workflowService,
                                          ChainParser chainParser,
                                          WorkflowDatacenterContentService workflowDatacenterContentService) {
        this.workflowService = workflowService;
        this.chainParser = chainParser;
        this.workflowDatacenterContentService = workflowDatacenterContentService;
    }

    /**
     * 使用已发布视图刷新工作流插件工具定义。
     *
     * @param plugin     插件
     * @param pluginItem 插件工具
     * @param workflowId 工作流 ID
     */
    public void syncPluginItemFromPublishedWorkflow(Plugin plugin, PluginItem pluginItem, java.math.BigInteger workflowId) {
        Workflow workflow = workflowService.getPublishedById(workflowId);
        if (workflow == null) {
            throw new BusinessException("工作流不存在");
        }
        assertSupportedForWorkflowPlugin(workflow);
        ChainDefinition definition = parseDefinition(workflow);
        pluginItem.setPluginId(plugin.getId());
        pluginItem.setName(plugin.getName());
        pluginItem.setEnglishName(workflow.getEnglishName());
        pluginItem.setDescription(resolveDescription(plugin, workflow));
        pluginItem.setBasePath(null);
        pluginItem.setRequestMethod("WORKFLOW");
        JSONArray inputDefinitions = resolveInputDefinitions(definition);
        JSONArray outputDefinitions = resolveOutputDefinitions(definition);
        pluginItem.setInputData(JSON.toJSONString(inputDefinitions));
        pluginItem.setOutputData(JSON.toJSONString(outputDefinitions));
        pluginItem.setSchemaHash(resolveSchemaHash(inputDefinitions, outputDefinitions));
        pluginItem.setServiceStatus(1);
        pluginItem.setStatus(1);
    }

    /**
     * 构建工作流插件运行工具。
     *
     * @param workflow 工作流已发布视图
     * @return 工作流工具
     */
    public WorkflowTool buildWorkflowTool(Workflow workflow) {
        return new WorkflowTool(
                workflow,
                false,
                PublishedWorkflowDefinitionIds.published(String.valueOf(workflow.getId()))
        );
    }

    /**
     * 解析输入参数定义。
     *
     * @param definition 流程定义
     * @return 输入参数数组
     */
    public JSONArray resolveInputDefinitions(ChainDefinition definition) {
        JSONArray inputs = JSON.parseArray(JSON.toJSONString(definition.getStartParameters()));
        markWorkflowPluginInput(inputs);
        return inputs == null ? new JSONArray() : inputs;
    }

    /**
     * 解析输出参数定义。
     *
     * @param definition 流程定义
     * @return 输出参数数组
     */
    public JSONArray resolveOutputDefinitions(ChainDefinition definition) {
        JSONArray outputs = new JSONArray();
        List<Node> nodes = definition.getNodes();
        if (nodes == null) {
            return outputs;
        }
        for (Node node : nodes) {
            if (node instanceof EndNode endNode) {
                outputs = JSON.parseArray(JSON.toJSONString(endNode.getOutputDefs()));
            }
        }
        return outputs == null ? new JSONArray() : outputs;
    }

    /**
     * 解析工作流插件契约哈希。
     *
     * @param workflow 工作流
     * @return 哈希值
     */
    public String resolveSchemaHash(Workflow workflow) {
        ChainDefinition definition = parseDefinition(workflow);
        return resolveSchemaHash(resolveInputDefinitions(definition), resolveOutputDefinitions(definition));
    }

    /**
     * 解析工作流插件契约哈希。
     *
     * @param inputDefinitions 输入定义
     * @param outputDefinitions 输出定义
     * @return 哈希值
     */
    public String resolveSchemaHash(JSONArray inputDefinitions, JSONArray outputDefinitions) {
        JSONObject payload = new JSONObject();
        payload.put("inputs", inputDefinitions == null ? new JSONArray() : inputDefinitions);
        payload.put("outputs", outputDefinitions == null ? new JSONArray() : outputDefinitions);
        return sha256Hex(JSON.toJSONString(payload));
    }

    /**
     * 校验工作流是否支持被封装为工作流插件。
     *
     * @param workflow 工作流
     */
    public void assertSupportedForWorkflowPlugin(Workflow workflow) {
        ChainDefinition definition = parseDefinition(workflow);
        int endNodeCount = countEndNodes(definition);
        // 一期先收敛为“单结束节点才能封装为插件”，后续若要支持多结束节点，
        // 需要先补齐统一输出契约、父流程节点 schema 同步和结果展示策略。
        if (endNodeCount != 1) {
            throw new BusinessException("工作流插件仅支持单一结束节点，当前工作流不可封装为插件");
        }
    }

    /**
     * 判断工作流是否为单结束节点结构。
     *
     * @param workflow 工作流
     * @return 单结束节点返回 true
     */
    public boolean isSupportedForWorkflowPlugin(Workflow workflow) {
        ChainDefinition definition = parseDefinition(workflow);
        return countEndNodes(definition) == 1;
    }

    /**
     * 解析已发布工作流定义。
     *
     * @param workflow 工作流已发布视图
     * @return 流程定义
     */
    public ChainDefinition parseDefinition(Workflow workflow) {
        String preparedContent = workflowDatacenterContentService.prepareContent(workflow.getContent());
        return chainParser.parse(preparedContent);
    }

    private String resolveDescription(Plugin plugin, Workflow workflow) {
        if (plugin.getDescription() != null && !plugin.getDescription().isBlank()) {
            return plugin.getDescription();
        }
        return workflow.getDescription();
    }

    private void markWorkflowPluginInput(JSONArray parameters) {
        if (parameters == null) {
            return;
        }
        for (Object parameter : parameters) {
            if (!(parameter instanceof com.alibaba.fastjson2.JSONObject obj)) {
                continue;
            }
            obj.put("refType", "ref");
            JSONArray children = obj.getJSONArray("children");
            if (children != null) {
                markWorkflowPluginInput(children);
            }
        }
    }

    private int countEndNodes(ChainDefinition definition) {
        List<Node> nodes = definition == null ? null : definition.getNodes();
        if (nodes == null || nodes.isEmpty()) {
            return 0;
        }
        int count = 0;
        for (Node node : nodes) {
            if (node instanceof EndNode) {
                count++;
            }
        }
        return count;
    }

    private String sha256Hex(String source) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] bytes = digest.digest(source.getBytes(StandardCharsets.UTF_8));
            StringBuilder builder = new StringBuilder(bytes.length * 2);
            for (byte current : bytes) {
                builder.append(Character.forDigit((current >> 4) & 0xF, 16));
                builder.append(Character.forDigit(current & 0xF, 16));
            }
            return builder.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("SHA-256 algorithm unavailable", e);
        }
    }
}
