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

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.NodeTypeEnums;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.BpmnAutoLayout;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BoundaryEvent;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.ErrorEventDefinition;
import org.flowable.bpmn.model.ExtensionAttribute;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.SequenceFlow;
import org.flowable.bpmn.model.ServiceTask;
import org.flowable.bpmn.model.StartEvent;
import org.flowable.bpmn.model.TerminateEventDefinition;
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 BpmnConverter1 {

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

            // 创建BPMN模型
            BpmnModel bpmnModel = new BpmnModel();
            bpmnModel.setTargetNamespace("http://www.flowable.org/test");
            bpmnModel.addError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, WorkFlowConstants.WORKFLOW_EXEC_ERROR);

            Process process = new Process();
            // 确保processKey符合NCName规则
            String validProcessKey = processKey.replaceAll("[^a-zA-Z0-9-_.]", "_");
            process.setId(validProcessKey);
            process.setName(processKey); // 保持原始processKey作为显示名称
            process.setExecutable(true);
            bpmnModel.addProcess(process);

            // 创建节点ID到规范化ID的映射
            Map<String, String> idMapping = new HashMap<>();

            // 转换节点
            for (WorkflowDefinitionGraphNode node : graph.getNodes()) {
                log.debug("转换节点: {}, 类型: {}", node.getNodeName(), node.getNodeCode());

                // 通过NodeTypeEnums获取对应的BpmnTypeEnums中定义的实例类型
                @SuppressWarnings("unchecked")
                Class<? extends FlowElement> instanceClass = (Class<? extends FlowElement>) NodeTypeEnums.valueOf(node.getNodeCode())
                    .getBpmnType()
                    .getInstance();

                // 创建节点实例
                FlowElement element = instanceClass.getDeclaredConstructor().newInstance();
                String validId = sanitizeId(node.getId());
                idMapping.put(node.getId(), validId);
                element.setId(validId);
                element.setName(node.getNodeName());

                // 设置节点特定属性
                configureFlowElement(element, node, process);

                process.addFlowElement(element);
            }

            // 转换连线
            for (WorkflowDefinitionGraphEdge edge : graph.getEdges()) {
                log.debug("转换连线: from {} to {}", edge.getFrom(), edge.getTo());

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

            // 自动布局
            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);
        }
    }

    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) {
        // 为所有节点添加执行监听器
        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);

        // 根据节点类型进行特定配置
        if (element instanceof ServiceTask) {
            ServiceTask serviceTask = (ServiceTask) element;
            // 设置委托表达式
//            String delegate = (String) node.getLocalVariables().get("delegate");
//            serviceTask.setImplementationType("delegateExpression");
//            serviceTask.setImplementation(delegate);

            // 配置重试策略
            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);

            // 添加字段注入
//            List<FieldExtension> fieldExtensions = new ArrayList<>();
//            node.getLocalVariables().forEach((key, value) -> {
//                if (value != null && !"delegate".equals(key)) {
//                    FieldExtension fieldExtension = new FieldExtension();
//                    fieldExtension.setFieldName(key);
//                    fieldExtension.setStringValue(String.valueOf(value));
//                    fieldExtensions.add(fieldExtension);
//                }
//            });

            // 设置到服务任务
//            serviceTask.setFieldExtensions(fieldExtensions);
            serviceTask.setExtensionElements(extensionElements);

            // 添加错误边界事件
            addErrorBoundaryEventHandler(process, serviceTask);
        } else if (element instanceof StartEvent || element instanceof EndEvent) {
            // 为开始节点和结束节点设置监听器
            element.setExtensionElements(extensionElements);
        }
    }

    /**
     * 创建执行监听器扩展元素
     *
     * @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 serviceTask 需要添加错误处理的服务任务
     */
    private void addErrorBoundaryEventHandler(Process process, ServiceTask serviceTask) {
        BoundaryEvent boundaryEvent = createErrorBoundaryEvent(serviceTask);
        EndEvent errorEndEvent = createErrorEndEvent(serviceTask);
        SequenceFlow errorFlow = createErrorSequenceFlow(boundaryEvent, errorEndEvent);

        // 将错误处理相关的元素添加到流程中
        process.addFlowElement(boundaryEvent);
        process.addFlowElement(errorEndEvent);
        process.addFlowElement(errorFlow);
    }

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

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

        return boundaryEvent;
    }

    /**
     * 创建错误结束事件
     *
     * @param serviceTask 关联的服务任务
     * @return 配置好的错误结束事件
     */
    private EndEvent createErrorEndEvent(ServiceTask serviceTask) {
        EndEvent errorEndEvent = new EndEvent();
        errorEndEvent.setId(WorkFlowConstants.END_EVENT_ERROR_PREFIX + serviceTask.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;
    }
}
