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

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qqchen.deploy.backend.framework.utils.SpelExpressionResolver;
import com.qqchen.deploy.backend.workflow.enums.NodeExecutionStatusEnum;
import com.qqchen.deploy.backend.workflow.enums.WorkflowNodeInstanceStatusEnums;
import com.qqchen.deploy.backend.workflow.dto.event.WorkflowNodeInstanceStatusChangeEvent;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import jakarta.annotation.Resource;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Component("globalNodeStartEndExecutionListener")
public class GlobalNodeStartEndExecutionListener implements ExecutionListener {

    /**
     * 不产生 outputs 的节点类型（事件/网关节点）
     * 这些节点执行后不会设置 outputs.status，直接视为成功
     */
    private static final Set<String> NODES_WITHOUT_OUTPUTS = Set.of(
        "StartEvent",           // 开始事件
        "EndEvent",             // 结束事件
        "BoundaryEvent",        // 边界事件
        "IntermediateCatchEvent", // 中间捕获事件
        "IntermediateThrowEvent", // 中间抛出事件
        "ExclusiveGateway",     // 排他网关
        "ParallelGateway",      // 并行网关
        "InclusiveGateway",     // 包容网关
        "EventBasedGateway"     // 事件网关
    );

    @Resource
    @Lazy
    private ApplicationEventPublisher eventPublisher;

    @Resource
    private ObjectMapper objectMapper;

    @Override
    public void notify(DelegateExecution execution) {
        // 获取当前节点信息
        FlowElement flowElement = execution.getCurrentFlowElement();
        String eventName = execution.getEventName();
        String processInstanceId = execution.getProcessInstanceId();
        String executionId = execution.getId();
        String nodeId = execution.getCurrentActivityId();
        String nodeName = flowElement.getName();
        String nodeType = flowElement.getClass().getSimpleName();
        log.debug("Node execution event: {}, processInstanceId: {}, nodeId: {}, nodeType: {}, nodeName:{}", eventName, processInstanceId, nodeId, nodeType, nodeName);
        LocalDateTime now = LocalDateTime.now();
        WorkflowNodeInstanceStatusEnums status = null;
        LocalDateTime startTime = null;
        LocalDateTime endTime = null;
        String variablesJson = null;
        String errorMessage = null;

        switch (eventName) {
            case ExecutionListener.EVENTNAME_START:
                status = WorkflowNodeInstanceStatusEnums.RUNNING;
                startTime = now;
                break;
            case ExecutionListener.EVENTNAME_END:
                // 从节点的 outputs.status 读取执行状态
                NodeExecutionStatusEnum nodeExecutionStatus = getNodeOutputStatus(execution, nodeId, nodeType);
                if (nodeExecutionStatus == NodeExecutionStatusEnum.FAILURE) {
                    status = WorkflowNodeInstanceStatusEnums.FAILED;
                    // ✅ 失败时提取错误信息
                    errorMessage = extractErrorMessage(execution, nodeId);
                } else {
                    status = WorkflowNodeInstanceStatusEnums.COMPLETED;
                }

                // ✅ 收集节点执行变量
                variablesJson = collectNodeVariables(execution, nodeId);

                endTime = now;
                break;
            default:
                log.warn("Unexpected event type: {}", eventName);
                return;
        }
        eventPublisher.publishEvent(WorkflowNodeInstanceStatusChangeEvent.builder()
            .processInstanceId(processInstanceId)
            .executionId(executionId)
            .nodeId(nodeId)
            .nodeName(nodeName)
            .nodeType(nodeType)
            .status(status)
            .startTime(startTime)
            .endTime(endTime)
            .variables(variablesJson)
            .errorMessage(errorMessage)
            .build());
    }

    /**
     * 从节点的 outputs.status 获取执行状态
     *
     * @param execution Flowable执行上下文
     * @param nodeId    节点ID
     * @param nodeType  节点类型（ServiceTask/StartEvent/Gateway等）
     * @return 节点执行状态枚举
     */
    private NodeExecutionStatusEnum getNodeOutputStatus(DelegateExecution execution, String nodeId, String nodeType) {
        // ✅ 第一层防护：事件/网关节点不产生 outputs，直接返回成功
        if (NODES_WITHOUT_OUTPUTS.contains(nodeType)) {
            log.debug("节点 {} 类型为 {}，不产生 outputs，直接返回 SUCCESS", nodeId, nodeType);
            return NodeExecutionStatusEnum.SUCCESS;
        }

        // ✅ 第二层：执行型节点，查找 outputs.status
        try {
            // 使用 SpelExpressionResolver 从节点变量中获取 outputs.status（支持复杂表达式）
            String expression = nodeId + ".outputs.status";
            Object statusObj = SpelExpressionResolver.evaluateExpression(execution, expression, Object.class);

            if (statusObj != null) {
                // 如果已经是枚举类型，直接返回
                if (statusObj instanceof NodeExecutionStatusEnum) {
                    return (NodeExecutionStatusEnum) statusObj;
                }
                // 如果是字符串，转换为枚举
                try {
                    return NodeExecutionStatusEnum.valueOf(statusObj.toString());
                } catch (IllegalArgumentException e) {
                    log.warn("无法将 {} 转换为 NodeExecutionStatusEnum", statusObj);
                }
            }
        } catch (Exception e) {
            log.debug("无法获取节点 {} 的 outputs.status: {}", nodeId, e.getMessage());
        }
        
        // ✅ 其他情况：默认失败（后续可优化为严格模式）
        return NodeExecutionStatusEnum.FAILURE;
    }

    /**
     * 收集节点执行变量
     *
     * @param execution Flowable执行上下文
     * @param nodeId    节点ID
     * @return JSON格式的变量字符串
     */
    private String collectNodeVariables(DelegateExecution execution, String nodeId) {
        try {
            // ✅ 直接获取所有流程变量
            Map<String, Object> allVariables = execution.getVariables();

            if (allVariables == null || allVariables.isEmpty()) {
                return null;
            }

            return objectMapper.writeValueAsString(allVariables);

        } catch (Exception e) {
            log.error("Failed to collect node variables for nodeId: {}", nodeId, e);
            return null;
        }
    }

    /**
     * 提取错误信息
     *
     * @param execution Flowable执行上下文
     * @param nodeId    节点ID
     * @return 错误信息字符串
     */
    private String extractErrorMessage(DelegateExecution execution, String nodeId) {
        try {
            Object nodeOutput = execution.getVariable(nodeId);
            if (nodeOutput instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, Object> outputMap = (Map<String, Object>) nodeOutput;
                Object message = outputMap.get("message");
                if (message != null) {
                    return message.toString();
                }
            }
        } catch (Exception e) {
            log.warn("Failed to extract error message for nodeId: {}", nodeId, e);
        }
        return null;
    }
}