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

import com.fasterxml.jackson.databind.JsonNode;
import com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants;
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraphEdge;
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraph;
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraphNode;
import com.qqchen.deploy.backend.workflow.enums.GatewayTypeEnums;
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
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.Component;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * BPMN 模型转换工具
 *
 * @author cascade
 * @date 2024-12-11
 */
@Slf4j
@Component
public class BpmnConverter {

    /**
     * 将工作流定义图转换为Flowable XML
     *
     * @param graph      工作流定义图
     * @param processKey 流程定义的唯一标识
     * @return Flowable XML字符串
     * @throws RuntimeException 当转换失败时抛出
     */
    public String convertToXml(WorkflowDefinitionGraph graph, String processKey) {
        try {
            log.debug("开始转换工作流定义为XML, processKey: {}", processKey);

            // 步骤1：创建和初始化BPMN模型
            BpmnModel bpmnModel = new BpmnModel();
            Process process = createAndInitializeBpmnModel(processKey, bpmnModel);

            // 步骤2：转换所有节点
            Map<String, String> idMapping = convertNodes(graph.getNodes(), process);

            // 步骤3：转换连线
            convertEdgesToSequenceFlows(graph.getEdges(), idMapping, process);

            // 步骤4：自动布局
            new BpmnAutoLayout(bpmnModel).execute();

            // 转换为XML
            BpmnXMLConverter converter = new BpmnXMLConverter();
            byte[] bytes = converter.convertToXML(bpmnModel);
            String xml = new String(bytes, StandardCharsets.UTF_8);

            log.debug("工作流定义转换完成");
            return xml;

        } catch (Exception e) {
            log.error("转换工作流��义为XML失败", e);
            throw new RuntimeException("转换工作流定义为XML失败: " + e.getMessage(), e);
        }
    }

    /**
     * 创建并初始化BPMN模型
     *
     * @param processKey 流程定义的唯一标识
     * @param bpmnModel BPMN模型对象
     * @return 初始化后的Process对象
     */
    private Process createAndInitializeBpmnModel(String processKey, BpmnModel bpmnModel) {
        // 步骤1.1：设置BPMN模型的基本属性
        bpmnModel.setTargetNamespace("http://www.flowable.org/test");
        bpmnModel.addError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, WorkFlowConstants.WORKFLOW_EXEC_ERROR);

        // 步骤1.2：创建并配置Process对象
        Process process = new Process();
        // 确保processKey符合NCName规则
        String validProcessKey = processKey.replaceAll("[^a-zA-Z0-9-_.]", "_");
        process.setId(validProcessKey);
        process.setName(processKey); // 保持原始processKey作为显示名称
        process.setExecutable(true);

        // 步骤1.3：将Process添加到BPMN模型中
        bpmnModel.addProcess(process);

        return process;
    }

    /**
     * 转换工作流节点为BPMN节点
     *
     * @param nodes 工作流定义节点列表
     * @param process 流程定义对象
     * @return 节点ID映射关系
     */
    private Map<String, String> convertNodes(List<WorkflowDefinitionGraphNode> nodes, Process process) {
        // 步骤2.1：创建节点ID映射
        Map<String, String> idMapping = new HashMap<>();

        // 步骤2.2：遍历并转换每个节点
        for (WorkflowDefinitionGraphNode node : nodes) {
            log.debug("转换节点: {}, 类型: {}", node.getNodeName(), node.getNodeCode());
            convertSingleNode(node, process, idMapping);
        }

        return idMapping;
    }

    /**
     * 转换单个工作流节点为BPMN节点
     *
     * @param node 工作流节点定义
     * @param process 流程定义对象
     * @param idMapping 节点ID映射关系
     */
    private void convertSingleNode(WorkflowDefinitionGraphNode node, Process process, Map<String, String> idMapping) {
        try {
            // 步骤2.3：获取节点对应的BPMN元素类型
            @SuppressWarnings("unchecked")
            Class<? extends FlowElement> instanceClass = (Class<? extends FlowElement>) NodeTypeEnums.valueOf(node.getNodeCode())
                .getBpmnType()
                .getInstance();

            // 步骤2.4：创建节点实例并设置基本属性
            FlowElement element = instanceClass.getDeclaredConstructor().newInstance();
            String validId = sanitizeId(node.getId());
            idMapping.put(node.getId(), validId);

            // 如果是网关节点，需要特殊处理
            if (element instanceof Gateway) {
                element = createGatewayElement(node, validId);
            } else {
                element.setId(validId);
                element.setName(node.getNodeName());
            }

            // 步骤2.5：配置节点的特定属性
            configureFlowElement(element, node, process);

            // 步骤2.6：将节点添加到流程中
            process.addFlowElement(element);
        } catch (Exception e) {
            log.error("节点转换失败: {}", node.getNodeName(), e);
            throw new RuntimeException("节点转换失败: " + e.getMessage(), e);
        }
    }

    private String sanitizeId(String id) {
        return "NODE_" + id.replaceAll("[^a-zA-Z0-9-_.]", "_");
    }

    /**
     * 配置流程节点的特定属性
     *
     * @param element 流程节点元素
     * @param node    工作流节点定义
     * @param process 当前流程
     */
    private void configureFlowElement(FlowElement element, WorkflowDefinitionGraphNode node, Process process) {
        // 步骤1：配置执行监听器
        Map<String, List<ExtensionElement>> extensionElements = configureExecutionListeners(element);

        // 步骤2：根据节点类型进行特定配置
        if (element instanceof ServiceTask) {
            configureServiceTask((ServiceTask) element, node, process, extensionElements);
        } else {
            element.setExtensionElements(extensionElements);
        }
    }

    /**
     * 配置节点的执行监听器
     *
     * @param element 流程节点元素
     * @return 配置好的扩展元素Map
     */
    private Map<String, List<ExtensionElement>> configureExecutionListeners(FlowElement element) {
        Map<String, List<ExtensionElement>> extensionElements = new HashMap<>();
        List<ExtensionElement> executionListeners = new ArrayList<>();

        if (element instanceof Gateway) {
            // 网关节点只添加 start 监听器
            executionListeners.add(createExecutionListener("start", "${gatewayExecutionListener}"));
        } else {
            // 其他节点添加 start 和 end 监听器
            executionListeners.add(createExecutionListener("start", "${globalNodeExecutionListener}"));
            executionListeners.add(createExecutionListener("end", "${globalNodeExecutionListener}"));
        }

        extensionElements.put("executionListener", executionListeners);
        return extensionElements;
    }

    /**
     * 创��基本的扩展元素（包含执行监听器）
     *
     * @return 包含基本扩展元素的Map
     */
    private Map<String, List<ExtensionElement>> createBaseExtensionElements() {
        Map<String, List<ExtensionElement>> extensionElements = new HashMap<>();
        List<ExtensionElement> executionListeners = new ArrayList<>();

        // 添加开始事件监听器
        ExtensionElement startListener = createExecutionListener("start", "${globalNodeExecutionListener}");
        executionListeners.add(startListener);

        // 添加结束事件监听器
        ExtensionElement endListener = createExecutionListener("end", "${globalNodeExecutionListener}");
        executionListeners.add(endListener);

        extensionElements.put("executionListener", executionListeners);
        return extensionElements;
    }

    /**
     * 配置服务任务节点
     *
     * @param serviceTask 服务任务节点
     * @param node 工作流节点定义
     * @param process 当前流程
     * @param extensionElements 扩展元素
     */
    private void configureServiceTask(ServiceTask serviceTask, WorkflowDefinitionGraphNode node, Process process, Map<String, List<ExtensionElement>> extensionElements) {
        if (node.getPanelVariables() != null && node.getPanelVariables().has("delegate")) {
            String delegate = node.getPanelVariables().get("delegate").asText();
            serviceTask.setImplementationType("delegateExpression");
            serviceTask.setImplementation(delegate);
        }

        addExecutionVariables(extensionElements, node);
        addRetryStrategy(extensionElements);
        serviceTask.setExtensionElements(extensionElements);
        addErrorBoundaryEventHandler(process, serviceTask);
    }

    /**
     * 创建扩展属性
     *
     * @param name 属性名
     * @param value 属性值
     * @return 扩展属性
     */
    private ExtensionAttribute createAttribute(String name, String value) {
        ExtensionAttribute attribute = new ExtensionAttribute();
        attribute.setName(name);
        attribute.setValue(value);
        return attribute;
    }

    /**
     * 添加执行实例级变量
     *
     * @param extensionElements 扩展元素
     * @param node 工作流节点定义
     */
    private void addExecutionVariables(Map<String, List<ExtensionElement>> extensionElements, WorkflowDefinitionGraphNode node) {
        // 添加panelVariables变量
        if (node.getPanelVariables() != null) {
            ExtensionElement fieldElement = new ExtensionElement();
            fieldElement.setName("field");
            fieldElement.setNamespace("http://flowable.org/bpmn");
            fieldElement.setNamespacePrefix("flowable");

            // 创建field的子元素string
            ExtensionElement stringElement = new ExtensionElement();
            stringElement.setName("string");
            stringElement.setNamespace("http://flowable.org/bpmn");
            stringElement.setNamespacePrefix("flowable");
            // 直接设置JSON内容，不使用CDATA
            stringElement.setElementText(node.getPanelVariables().toString());

            // 设置field的name属性
            Map<String, List<ExtensionAttribute>> fieldAttributes = new HashMap<>();
            fieldAttributes.put("name", Collections.singletonList(createAttribute("name", "panelVariables")));
            fieldElement.setAttributes(fieldAttributes);

            // 添加string子元素到field
            fieldElement.addChildElement(stringElement);

            // 添加field到extensionElements
            extensionElements.computeIfAbsent("field", k -> new ArrayList<>()).add(fieldElement);
        }

        // 添加localVariables变量
//        if (node.getLocalVariables() != null) {
//            ExtensionElement fieldElement = new ExtensionElement();
//            fieldElement.setName("field");
//            fieldElement.setNamespace("http://flowable.org/bpmn");
//            fieldElement.setNamespacePrefix("flowable");
//
//            // 创建field的子元素string
//            ExtensionElement stringElement = new ExtensionElement();
//            stringElement.setName("string");
//            stringElement.setNamespace("http://flowable.org/bpmn");
//            stringElement.setNamespacePrefix("flowable");
//            // 直接设置JSON内容，不使用CDATA
//            stringElement.setElementText(node.getLocalVariables().toString());
//
//            // 设置field的name属性
//            Map<String, List<ExtensionAttribute>> fieldAttributes = new HashMap<>();
//            fieldAttributes.put("name", Collections.singletonList(createAttribute("name", "localVariables")));
//            fieldElement.setAttributes(fieldAttributes);
//
//            // 添加string子元素到field
//            fieldElement.addChildElement(stringElement);
//
//            // 添加field到extensionElements
//            extensionElements.computeIfAbsent("field", k -> new ArrayList<>()).add(fieldElement);
//        }
    }

    /**
     * 添加重试策略配置
     *
     * @param extensionElements 扩展元素
     */
    private void addRetryStrategy(Map<String, List<ExtensionElement>> extensionElements) {
        ExtensionElement retryConfig = new ExtensionElement();
        retryConfig.setName("failedJobRetryTimeCycle");
        retryConfig.setNamespace("http://flowable.org/bpmn");
        retryConfig.setNamespacePrefix("flowable");
        retryConfig.setElementText("R0/PT1H");  // 设置为0次重试

        List<ExtensionElement> retryElements = new ArrayList<>();
        retryElements.add(retryConfig);
        extensionElements.put("failedJobRetryTimeCycle", retryElements);
    }

    /**
     * 创建执行监听器扩展元素
     *
     * @param event 事件类型（start/end）
     * @param delegateExpression 委托表达式
     * @return 配置好的监听器扩展元素
     */
    private ExtensionElement createExecutionListener(String event, String delegateExpression) {
        ExtensionElement listener = new ExtensionElement();
        listener.setName("executionListener");
        listener.setNamespace("http://flowable.org/bpmn");
        listener.setNamespacePrefix("flowable");

        // 设置事件属性
        ExtensionAttribute eventAttr = new ExtensionAttribute();
        eventAttr.setName("event");
        eventAttr.setValue(event);

        // 设置委托表达式属性
        ExtensionAttribute delegateAttr = new ExtensionAttribute();
        delegateAttr.setName("delegateExpression");
        delegateAttr.setValue(delegateExpression);

        // 添加属性到监听器
        Map<String, List<ExtensionAttribute>> attributes = new HashMap<>();
        attributes.put("event", Collections.singletonList(eventAttr));
        attributes.put("delegateExpression", Collections.singletonList(delegateAttr));
        listener.setAttributes(attributes);

        return listener;
    }

    /**
     * 为活动节点添加错误边界事件和错误结束事件
     * 当节点执行失败时，会触发错误边界事件，并流转到错误结束事件
     *
     * @param process     BPMN流程定义
     * @param activity    需要添加错误处理的活动节点
     */
    private void addErrorBoundaryEventHandler(Process process, Activity activity) {
        BoundaryEvent boundaryEvent = createErrorBoundaryEvent(activity);
        EndEvent errorEndEvent = createErrorEndEvent(activity);
        SequenceFlow errorFlow = createErrorSequenceFlow(boundaryEvent, errorEndEvent);

        process.addFlowElement(boundaryEvent);
        process.addFlowElement(errorEndEvent);
        process.addFlowElement(errorFlow);
    }

    /**
     * 创建错误边界事件
     *
     * @param activity 关联的活动节点
     * @return 配置好的错误边界事件
     */
    private BoundaryEvent createErrorBoundaryEvent(Activity activity) {
        BoundaryEvent boundaryEvent = new BoundaryEvent();
        boundaryEvent.setId(WorkFlowConstants.BOUNDARY_EVENT_ERROR_PREFIX + activity.getId());
        boundaryEvent.setName("边界事件异常");
        boundaryEvent.setAttachedToRef(activity);
        boundaryEvent.setAttachedToRefId(activity.getId());
        boundaryEvent.setCancelActivity(true);  // 确保取消原有活动

        // 配置错误事件定义
        ErrorEventDefinition errorEventDefinition = new ErrorEventDefinition();
        errorEventDefinition.setErrorCode(WorkFlowConstants.WORKFLOW_EXEC_ERROR);
        boundaryEvent.addEventDefinition(errorEventDefinition);

        return boundaryEvent;
    }

    /**
     * 创建错误结束事件
     *
     * @param activity 关联的活动节点
     * @return 配置好的错误结束事件
     */
    private EndEvent createErrorEndEvent(Activity activity) {
        EndEvent errorEndEvent = new EndEvent();
        errorEndEvent.setId(WorkFlowConstants.END_EVENT_ERROR_PREFIX + activity.getId());
        errorEndEvent.setName("结束事件异常");
        // 添加终止定义
        TerminateEventDefinition terminateEventDefinition = new TerminateEventDefinition();
        errorEndEvent.addEventDefinition(terminateEventDefinition);

//        ErrorEventDefinition errorEventDefinition = new ErrorEventDefinition();
//        errorEventDefinition.setErrorCode(WorkFlowConstants.WORKFLOW_EXEC_ERROR);
//        errorEndEvent.addEventDefinition(errorEventDefinition);

        return errorEndEvent;
    }

    /**
     * 创建错误处理流程的连线
     *
     * @param boundaryEvent 错误边界事件
     * @param errorEndEvent 错误结束事件
     * @return 配置好的连线
     */
    private SequenceFlow createErrorSequenceFlow(BoundaryEvent boundaryEvent, EndEvent errorEndEvent) {
        SequenceFlow errorFlow = new SequenceFlow();
        errorFlow.setId(WorkFlowConstants.SEQUENCE_FLOW_ERROR_PREFIX + boundaryEvent.getAttachedToRefId());
        errorFlow.setName("连接线异常");
        errorFlow.setSourceRef(boundaryEvent.getId());
        errorFlow.setTargetRef(errorEndEvent.getId());

        return errorFlow;
    }

    /**
     * 创建网关节点
     *
     * @param node 工作流节点定义
     * @param validId 有效的节点ID
     * @return 创建的网关节点
     */
    private Gateway createGatewayElement(WorkflowDefinitionGraphNode node, String validId) {
        if (node.getPanelVariables() == null) {
            throw new IllegalArgumentException("Gateway node must have panel variables");
        }

        String gatewayTypeCode = node.getPanelVariables().get("gatewayType").asText();
        GatewayTypeEnums gatewayType = GatewayTypeEnums.fromCode(gatewayTypeCode);

        Gateway gateway;
        switch (gatewayType) {
            case EXCLUSIVE_GATEWAY:
                gateway = new ExclusiveGateway();
                break;
            case PARALLEL_GATEWAY:
                gateway = new ParallelGateway();
                break;
            case INCLUSIVE_GATEWAY:
                gateway = new InclusiveGateway();
                break;
            default:
                throw new IllegalArgumentException("Unsupported gateway type: " + gatewayType);
        }

        gateway.setId(validId);
        gateway.setName(node.getNodeName());

        return gateway;
    }

    /**
     * 转换连线为顺序流
     *
     * @param edges 工作流定义边集合
     * @param idMapping 节点ID映射
     * @param process 流程定义
     */
    private void convertEdgesToSequenceFlows(List<WorkflowDefinitionGraphEdge> edges, Map<String, String> idMapping, Process process) {
        for (WorkflowDefinitionGraphEdge edge : edges) {
            log.debug("转换连线: from {} to {}", edge.getFrom(), edge.getTo());

            SequenceFlow flow = new SequenceFlow();
            String flowId = "FLOW_" + edge.getId().replaceAll("[^a-zA-Z0-9-_.]", "_");
            flow.setId(flowId);
            flow.setName(edge.getName());
            flow.setSourceRef(idMapping.get(edge.getFrom()));
            flow.setTargetRef(idMapping.get(edge.getTo()));

            // 处理条件
            if (edge.getConfig() != null && edge.getConfig().getCondition() != null) {
                if ("EXPRESSION".equals(edge.getConfig().getCondition().getType())) {
                    String expression = edge.getConfig().getCondition().getExpression();
                    flow.setConditionExpression(expression);
                }
            }

//            // 添加 take 事件监听器
//            Map<String, List<ExtensionElement>> extensionElements = new HashMap<>();
//            List<ExtensionElement> executionListeners = new ArrayList<>();
//            executionListeners.add(createExecutionListener("take", "${sequenceFlowTakeListener}"));
//            extensionElements.put("executionListener", executionListeners);
//            flow.setExtensionElements(extensionElements);

            process.addFlowElement(flow);
        }
    }
}
