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

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qqchen.deploy.backend.workflow.dto.inputmapping.BaseNodeInputMapping;
import com.qqchen.deploy.backend.workflow.model.NodeContext;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;

import java.util.Map;

/**
 * 工作流工具类
 * <p>
 * 提供工作流相关的通用工具方法
 *
 * @author qqchen
 * @since 2025-11-07
 */
@Slf4j
public class WorkflowUtils {

    private WorkflowUtils() {
        // 工具类，禁止实例化
    }

    /**
     * 从 InputMapping 获取 continueOnFailure 配置
     * <p>
     * 用于判断节点失败后是否继续执行流程：
     * <ul>
     *   <li>true: 节点失败时标记为 FAILURE，但流程继续执行</li>
     *   <li>false: 节点失败时抛出 BpmnError，终止流程（默认）</li>
     * </ul>
     *
     * @param inputMapping 输入映射对象（必须继承自 BaseNodeInputMapping）
     * @return true: 失败后继续执行, false: 失败后终止流程（默认）
     */
    public static boolean getContinueOnFailure(Object inputMapping) {
        if (inputMapping == null) {
            return false;  // 默认阻断模式
        }

        try {
            // 所有 InputMapping 都继承自 BaseNodeInputMapping
            if (inputMapping instanceof BaseNodeInputMapping) {
                Boolean continueOnFailure = ((BaseNodeInputMapping) inputMapping).getContinueOnFailure();
                return Boolean.TRUE.equals(continueOnFailure);
            }
        } catch (Exception e) {
            log.warn("Failed to get continueOnFailure config, using default (false)", e);
        }

        return false;  // 默认阻断模式
    }

    /**
     * 从 InputMapping 获取 continueOnFailure 配置（带默认值）
     *
     * @param inputMapping  输入映射对象
     * @param defaultValue  默认值
     * @return continueOnFailure 配置值
     */
    public static boolean getContinueOnFailure(Object inputMapping, boolean defaultValue) {
        if (inputMapping == null) {
            return defaultValue;
        }

        try {
            if (inputMapping instanceof BaseNodeInputMapping) {
                Boolean continueOnFailure = ((BaseNodeInputMapping) inputMapping).getContinueOnFailure();
                if (continueOnFailure != null) {
                    return continueOnFailure;
                }
            }
        } catch (Exception e) {
            log.warn("Failed to get continueOnFailure config, using default ({})", defaultValue, e);
        }

        return defaultValue;
    }

    // ===================== 节点配置相关 =====================

    /**
     * 从配置中提取节点名称
     * <p>
     * 优先级：nodeName → nodeCode → "节点"（默认）
     *
     * @param configsMap 节点配置
     * @return 节点名称，默认返回"节点"
     */
    public static String extractNodeName(Map<String, Object> configsMap) {
        if (configsMap == null) {
            return "节点";
        }

        // 1. 优先使用 nodeName
        Object nodeName = configsMap.get("nodeName");
        if (nodeName != null && !nodeName.toString().trim().isEmpty()) {
            return nodeName.toString().trim();
        }

        // 2. 降级：使用 nodeCode
        Object nodeCode = configsMap.get("nodeCode");
        if (nodeCode != null && !nodeCode.toString().trim().isEmpty()) {
            return nodeCode.toString().trim();
        }

        // 3. 默认值
        return "节点";
    }

    // ===================== NodeContext 操作相关 =====================

    /**
     * 从 Flowable 执行上下文读取 NodeContext
     * <p>
     * 统一的 NodeContext 读取方法，供 Delegate 和 Listener 共享
     *
     * @param execution      Flowable 执行上下文
     * @param nodeId         节点ID
     * @param inputClass     输入映射类型
     * @param outputClass    输出映射类型
     * @param objectMapper   JSON 序列化工具
     * @param <I>            输入映射泛型
     * @param <O>            输出映射泛型
     * @return NodeContext 对象，解析失败返回 null
     */
    public static <I, O> NodeContext<I, O> readNodeContext(
            DelegateExecution execution,
            String nodeId,
            Class<I> inputClass,
            Class<O> outputClass,
            ObjectMapper objectMapper) {

        if (execution == null || nodeId == null || nodeId.trim().isEmpty()) {
            log.warn("Invalid parameters for readNodeContext: execution={}, nodeId={}", execution, nodeId);
            return null;
        }

        try {
            Object nodeDataObj = execution.getVariable(nodeId);
            if (!(nodeDataObj instanceof Map)) {
                log.debug("NodeContext not found or invalid type for node: {}", nodeId);
                return null;
            }

            @SuppressWarnings("unchecked")
            Map<String, Object> nodeDataMap = (Map<String, Object>) nodeDataObj;
            return NodeContext.fromMap(nodeDataMap, inputClass, outputClass, objectMapper);

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

    /**
     * 保存 NodeContext 到 Flowable 执行上下文
     * <p>
     * 统一的 NodeContext 保存方法，供 Delegate 和 Listener 共享
     *
     * @param execution    Flowable 执行上下文
     * @param nodeId       节点ID
     * @param nodeContext  NodeContext 对象
     * @param objectMapper JSON 序列化工具
     * @param <I>          输入映射泛型
     * @param <O>          输出映射泛型
     * @throws RuntimeException 保存失败时抛出
     */
    public static <I, O> void saveNodeContext(
            DelegateExecution execution,
            String nodeId,
            NodeContext<I, O> nodeContext,
            ObjectMapper objectMapper) {

        if (execution == null || nodeId == null || nodeId.trim().isEmpty() || nodeContext == null) {
            throw new IllegalArgumentException("Invalid parameters for saveNodeContext");
        }

        try {
            execution.setVariable(nodeId, nodeContext.toMap(objectMapper));
            log.debug("Saved NodeContext for node: {}", nodeId);

        } catch (Exception e) {
            log.error("Failed to save NodeContext for node: {}", nodeId, e);
            throw new RuntimeException("Failed to save NodeContext: " + nodeId, e);
        }
    }
}

