package com.flowable.devops.workflow.converter;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.BpmnAutoLayout;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 工作流转换器：JSON ↔ BPMN XML
 * 
 * 核心职责：
 * 1. 将前端的JSON工作流定义转换为Flowable的BPMN XML
 * 2. 支持各种节点类型的转换
 * 3. 处理条件分支和连线
 */
@Slf4j
@Service
public class WorkflowConverter {
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * JSON → BPMN XML
     * 
     * @param workflowJson JSON格式的工作流定义
     * @return BPMN 2.0 XML字符串
     */
    public String convertToBpmn(JsonNode workflowJson) {
        log.info("开始转换工作流JSON到BPMN: {}", workflowJson.get("name").asText());
        
        try {
            // 1. 创建BPMN模型
            BpmnModel bpmnModel = new BpmnModel();
            
            // 2. 创建流程
            Process process = createProcess(workflowJson);
            
            // 3. 添加开始事件
            StartEvent startEvent = createStartEvent();
            process.addFlowElement(startEvent);
            
            // 4. 转换节点
            Map<String, FlowElement> elementMap = new HashMap<>();
            elementMap.put("start", startEvent);
            
            JsonNode nodes = workflowJson.get("nodes");
            if (nodes != null && nodes.isArray()) {
                for (JsonNode node : nodes) {
                    FlowElement element = convertNode(node);
                    process.addFlowElement(element);
                    elementMap.put(node.get("id").asText(), element);
                }
            }
            
            // 5. 添加结束事件
            EndEvent endEvent = createEndEvent();
            process.addFlowElement(endEvent);
            elementMap.put("end", endEvent);
            
            // 6. 转换连线
            convertEdges(workflowJson, process, elementMap);
            
            // 7. 添加流程到模型
            bpmnModel.addProcess(process);
            
            // 8. 自动布局
            new BpmnAutoLayout(bpmnModel).execute();
            
            // 9. 转换为XML
            String bpmnXml = convertBpmnModelToXml(bpmnModel);
            
            log.info("工作流JSON转换BPMN完成: {} 个节点, {} KB", 
                    elementMap.size(), bpmnXml.length() / 1024);
            
            return bpmnXml;
            
        } catch (Exception e) {
            log.error("转换工作流JSON到BPMN失败", e);
            throw new WorkflowConversionException("Failed to convert workflow JSON to BPMN", e);
        }
    }
    
    /**
     * 创建流程
     */
    private Process createProcess(JsonNode workflowJson) {
        Process process = new Process();
        process.setId(workflowJson.get("id").asText());
        process.setName(workflowJson.get("name").asText());
        process.setExecutable(true);
        
        return process;
    }
    
    /**
     * 创建开始事件
     */
    private StartEvent createStartEvent() {
        StartEvent startEvent = new StartEvent();
        startEvent.setId("start");
        startEvent.setName("开始");
        return startEvent;
    }
    
    /**
     * 创建结束事件
     */
    private EndEvent createEndEvent() {
        EndEvent endEvent = new EndEvent();
        endEvent.setId("end");
        endEvent.setName("结束");
        return endEvent;
    }
    
    /**
     * 转换单个节点
     */
    private FlowElement convertNode(JsonNode nodeJson) {
        String nodeType = nodeJson.get("type").asText();
        String nodeId = nodeJson.get("id").asText();
        String nodeName = nodeJson.get("name").asText();
        
        log.debug("转换节点: {} ({})", nodeName, nodeType);
        
        // 根据节点类型创建不同的BPMN元素
        switch (nodeType) {
            case "approval":
            case "user_task":
                return createUserTask(nodeJson);
            
            case "exclusive_gateway":
                return createExclusiveGateway(nodeJson);
                
            case "parallel_gateway":
                return createParallelGateway(nodeJson);
                
            default:
                // 默认创建Service Task
                return createServiceTask(nodeJson);
        }
    }
    
    /**
     * 创建Service Task（普通节点）
     */
    private ServiceTask createServiceTask(JsonNode nodeJson) {
        ServiceTask task = new ServiceTask();
        task.setId(nodeJson.get("id").asText());
        task.setName(nodeJson.get("name").asText());
        
        // 使用通用执行器 - 关键配置！
        task.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
        task.setImplementation("${genericNodeExecutor}");
        
        // 通过Field Extension传递节点配置
        List<FieldExtension> fields = new ArrayList<>();
        
        // 节点类型
        FieldExtension typeField = new FieldExtension();
        typeField.setFieldName("nodeType");
        typeField.setStringValue(nodeJson.get("type").asText());
        fields.add(typeField);
        
        // 节点配置（JSON）
        try {
            JsonNode config = nodeJson.get("config");
            if (config != null) {
                String configJson = objectMapper.writeValueAsString(config);
                FieldExtension configField = new FieldExtension();
                configField.setFieldName("nodeConfig");
                configField.setStringValue(configJson);
                fields.add(configField);
            }
        } catch (Exception e) {
            log.warn("序列化节点配置失败: {}", nodeJson.get("id").asText(), e);
        }
        
        task.setFieldExtensions(fields);
        
        return task;
    }
    
    /**
     * 创建User Task（审批节点）
     */
    private UserTask createUserTask(JsonNode nodeJson) {
        UserTask task = new UserTask();
        task.setId(nodeJson.get("id").asText());
        task.setName(nodeJson.get("name").asText());
        
        JsonNode config = nodeJson.get("config");
        if (config != null) {
            // 审批人（支持表达式）
            JsonNode assigneeNode = config.get("assignee");
            if (assigneeNode != null) {
                task.setAssignee(assigneeNode.asText());
            }
            
            // 候选组
            JsonNode candidateGroupsNode = config.get("candidateGroups");
            if (candidateGroupsNode != null && candidateGroupsNode.isArray()) {
                List<String> candidateGroups = new ArrayList<>();
                candidateGroupsNode.forEach(group -> candidateGroups.add(group.asText()));
                task.setCandidateGroups(candidateGroups);
            }
            
            // 表单字段
            JsonNode formFieldsNode = config.get("formFields");
            if (formFieldsNode != null && formFieldsNode.isArray()) {
                List<FormProperty> formProperties = new ArrayList<>();
                formFieldsNode.forEach(field -> {
                    FormProperty prop = new FormProperty();
                    prop.setId(field.get("id").asText());
                    prop.setName(field.get("label").asText());
                    prop.setType(field.get("type").asText());
                    prop.setRequired(field.has("required") ? field.get("required").asBoolean() : false);
                    formProperties.add(prop);
                });
                task.setFormProperties(formProperties);
            }
        }
        
        return task;
    }
    
    /**
     * 创建排他网关（条件分支）
     */
    private ExclusiveGateway createExclusiveGateway(JsonNode nodeJson) {
        ExclusiveGateway gateway = new ExclusiveGateway();
        gateway.setId(nodeJson.get("id").asText());
        gateway.setName(nodeJson.get("name").asText());
        return gateway;
    }
    
    /**
     * 创建并行网关
     */
    private ParallelGateway createParallelGateway(JsonNode nodeJson) {
        ParallelGateway gateway = new ParallelGateway();
        gateway.setId(nodeJson.get("id").asText());
        gateway.setName(nodeJson.get("name").asText());
        return gateway;
    }
    
    /**
     * 转换连线
     */
    private void convertEdges(JsonNode workflowJson, Process process, Map<String, FlowElement> elementMap) {
        JsonNode edges = workflowJson.get("edges");
        if (edges == null || !edges.isArray()) {
            log.warn("工作流没有定义edges");
            return;
        }
        
        // 找到入度为0的节点（起始节点）
        Set<String> targetNodes = new HashSet<>();
        edges.forEach(edge -> targetNodes.add(edge.get("target").asText()));
        
        Set<String> sourceNodes = new HashSet<>();
        edges.forEach(edge -> sourceNodes.add(edge.get("source").asText()));
        
        // 连接 start → 第一个节点
        Set<String> firstNodes = new HashSet<>(sourceNodes);
        firstNodes.removeAll(targetNodes);
        
        for (String firstNodeId : firstNodes) {
            if (elementMap.containsKey(firstNodeId)) {
                addSequenceFlow(process, "start", firstNodeId, null);
                log.debug("连接: start → {}", firstNodeId);
            }
        }
        
        // 转换所有边
        edges.forEach(edge -> {
            String source = edge.get("source").asText();
            String target = edge.get("target").asText();
            String condition = edge.has("condition") ? edge.get("condition").asText() : null;
            
            if (elementMap.containsKey(source) && elementMap.containsKey(target)) {
                addSequenceFlow(process, source, target, condition);
                log.debug("连接: {} → {} {}", source, target, 
                         condition != null ? "[" + condition + "]" : "");
            } else {
                log.warn("跳过无效连线: {} → {} (节点不存在)", source, target);
            }
        });
        
        // 连接 最后的节点 → end
        Set<String> lastNodes = new HashSet<>(targetNodes);
        lastNodes.removeAll(sourceNodes);
        
        for (String lastNodeId : lastNodes) {
            if (elementMap.containsKey(lastNodeId)) {
                addSequenceFlow(process, lastNodeId, "end", null);
                log.debug("连接: {} → end", lastNodeId);
            }
        }
    }
    
    /**
     * 添加序列流
     */
    private SequenceFlow addSequenceFlow(Process process, String sourceId, String targetId, String condition) {
        SequenceFlow flow = new SequenceFlow();
        flow.setId("flow_" + sourceId + "_to_" + targetId);
        flow.setSourceRef(sourceId);
        flow.setTargetRef(targetId);
        
        // 设置条件表达式
        if (condition != null && !condition.trim().isEmpty()) {
            flow.setConditionExpression(condition);
        }
        
        process.addFlowElement(flow);
        return flow;
    }
    
    /**
     * 验证工作流JSON
     */
    public void validateWorkflowJson(JsonNode workflowJson) {
        if (workflowJson == null) {
            throw new WorkflowValidationException("工作流JSON不能为null");
        }
        
        List<String> errors = new ArrayList<>();
        
        // 检查必需字段
        if (!workflowJson.has("id") || workflowJson.get("id").asText().trim().isEmpty()) {
            errors.add("工作流ID不能为空");
        }
        
        if (!workflowJson.has("name") || workflowJson.get("name").asText().trim().isEmpty()) {
            errors.add("工作流名称不能为空");
        }
        
        if (!workflowJson.has("nodes") || !workflowJson.get("nodes").isArray()) {
            errors.add("工作流必须包含节点数组");
        }
        
        // 检查节点
        JsonNode nodes = workflowJson.get("nodes");
        if (nodes != null && nodes.isArray()) {
            Set<String> nodeIds = new HashSet<>();
            for (JsonNode node : nodes) {
                if (!node.has("id") || node.get("id").asText().trim().isEmpty()) {
                    errors.add("节点ID不能为空");
                }
                
                String nodeId = node.get("id").asText();
                if (nodeIds.contains(nodeId)) {
                    errors.add("节点ID重复: " + nodeId);
                }
                nodeIds.add(nodeId);
                
                if (!node.has("type")) {
                    errors.add("节点类型不能为空: " + nodeId);
                }
                
                if (!node.has("name")) {
                    errors.add("节点名称不能为空: " + nodeId);
                }
            }
        }
        
        // 检查连线
        JsonNode edges = workflowJson.get("edges");
        if (edges != null && edges.isArray()) {
            Set<String> nodeIds = new HashSet<>();
            JsonNode nodesArray = workflowJson.get("nodes");
            if (nodesArray != null) {
                nodesArray.forEach(node -> nodeIds.add(node.get("id").asText()));
            }
            
            for (JsonNode edge : edges) {
                if (!edge.has("source") || !edge.has("target")) {
                    errors.add("连线必须包含source和target");
                    continue;
                }
                
                String source = edge.get("source").asText();
                String target = edge.get("target").asText();
                
                if (!nodeIds.contains(source)) {
                    errors.add("连线源节点不存在: " + source);
                }
                
                if (!nodeIds.contains(target)) {
                    errors.add("连线目标节点不存在: " + target);
                }
            }
        }
        
        if (!errors.isEmpty()) {
            throw new WorkflowValidationException("工作流JSON验证失败: " + String.join("; ", errors));
        }
    }
    
    /**
     * BPMN Model → XML
     */
    private String convertBpmnModelToXml(BpmnModel bpmnModel) {
        BpmnXMLConverter converter = new BpmnXMLConverter();
        byte[] xmlBytes = converter.convertToXML(bpmnModel);
        return new String(xmlBytes, StandardCharsets.UTF_8);
    }
    
    /**
     * 拓扑排序验证（检测环）
     */
    public void validateWorkflowTopology(JsonNode workflowJson) {
        JsonNode nodes = workflowJson.get("nodes");
        JsonNode edges = workflowJson.get("edges");
        
        if (nodes == null || edges == null) {
            return;
        }
        
        // 构建图
        Map<String, Set<String>> adjacencyList = new HashMap<>();
        Map<String, Integer> inDegree = new HashMap<>();
        
        // 初始化
        for (JsonNode node : nodes) {
            String nodeId = node.get("id").asText();
            adjacencyList.put(nodeId, new HashSet<>());
            inDegree.put(nodeId, 0);
        }
        
        // 构建邻接表和入度统计
        for (JsonNode edge : edges) {
            String source = edge.get("source").asText();
            String target = edge.get("target").asText();
            
            adjacencyList.get(source).add(target);
            inDegree.put(target, inDegree.get(target) + 1);
        }
        
        // Kahn算法检测环
        Queue<String> queue = new LinkedList<>();
        for (Map.Entry<String, Integer> entry : inDegree.entrySet()) {
            if (entry.getValue() == 0) {
                queue.offer(entry.getKey());
            }
        }
        
        int processedCount = 0;
        while (!queue.isEmpty()) {
            String current = queue.poll();
            processedCount++;
            
            for (String neighbor : adjacencyList.get(current)) {
                inDegree.put(neighbor, inDegree.get(neighbor) - 1);
                if (inDegree.get(neighbor) == 0) {
                    queue.offer(neighbor);
                }
            }
        }
        
        if (processedCount != inDegree.size()) {
            throw new WorkflowValidationException("工作流存在环形依赖，无法执行");
        }
    }
}