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

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qqchen.deploy.backend.framework.utils.JsonUtils;
import com.qqchen.deploy.backend.framework.utils.SpelExpressionResolver;
import com.qqchen.deploy.backend.workflow.dto.outputs.BaseNodeOutputs;
import com.qqchen.deploy.backend.workflow.enums.LogLevel;
import com.qqchen.deploy.backend.workflow.enums.LogSource;
import com.qqchen.deploy.backend.workflow.enums.NodeExecutionStatusEnum;
import com.qqchen.deploy.backend.workflow.model.NodeContext;
import com.qqchen.deploy.backend.workflow.service.IWorkflowNodeLogService;
import com.qqchen.deploy.backend.workflow.utils.WorkflowUtils;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.flowable.common.engine.api.delegate.Expression;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;


/**
 * 任务委派者基类
 * <p>
 * 负责处理节点配置、输入映射和输出结果的统一处理
 *
 * @param <I> 输入映射类型 (InputMapping)
 * @param <O> 输出类型 (Outputs)
 * @author qqchen
 */
@Slf4j

public abstract class BaseNodeDelegate<I, O> implements JavaDelegate {

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired(required = false)
    private IWorkflowNodeLogService workflowNodeLogService;

    // Flowable自动注入的字段
    protected Expression nodeId;

    protected Expression configs;

    protected Expression inputMapping;

    protected Expression outputs;

    // 缓存泛型类型
    private Class<I> inputMappingClass;

    private Class<O> outputsClass;

    // 当前执行上下文（用于日志记录）
    private String currentProcessInstanceId;

    private String currentNodeId;

    // 预初始化的输出对象（子类可以直接访问和修改）
    protected O output;

    // 当前输入映射对象（用于读取 continueOnFailure 等配置）
    protected I currentInputMapping;

    @Override
    public void execute(DelegateExecution execution) {

        NodeContext<I, O> nodeContext = new NodeContext<>();
        Map<String, Object> configsMap = null;
        I inputMappingObj = null;

        try {
            // 1. 获取节点ID和流程实例ID（用于日志记录）
            this.currentNodeId = getFieldValue(nodeId, execution);
            this.currentProcessInstanceId = execution.getProcessInstanceId();
            log.info("Executing node: {}", currentNodeId);

            // 2. 解析配置（通用Map）
            configsMap = parseJsonField(configs, execution);

            // 3. 自动创建并初始化输出对象为 SUCCESS 状态
            this.output = createSuccessOutputs(configsMap);

            // 4. 解析并转换InputMapping（强类型）
            inputMappingObj = parseAndConvertInputMapping(execution);
            this.currentInputMapping = inputMappingObj;  // 保存引用，供子类使用

            // 5. 执行具体的业务逻辑（子类直接修改 this.output）
            executeInternal(execution, configsMap, inputMappingObj);

            // 6. 使用 NodeContext 保存节点数据
            nodeContext.setConfigs(configsMap);
            nodeContext.setInputMapping(inputMappingObj);
            nodeContext.setOutputs(this.output);

            execution.setVariable(currentNodeId, nodeContext.toMap(objectMapper));
            log.info("Stored NodeContext for: {}", currentNodeId);

        } catch (Exception e) {
            // 业务异常：根据 continueOnFailure 配置决定行为
            log.error("Business exception in node: {}", currentNodeId, e);

            boolean continueOnFailure = WorkflowUtils.getContinueOnFailure(currentInputMapping);
            if (continueOnFailure) {
                // 非阻断模式：标记失败但流程继续
                log.error("Node failed (continue mode enabled by config): {}", e.getMessage());
                markFailure(e);
                // 保存失败状态的 NodeContext
                nodeContext.setConfigs(configsMap);
                nodeContext.setInputMapping(inputMappingObj);
                nodeContext.setOutputs(this.output);
                execution.setVariable(currentNodeId, nodeContext.toMap(objectMapper));
            } else {
                //阻断模式：终止流程（默认行为）
                log.error("Node failed (terminate mode, default): {}", e.getMessage());
                terminateWorkflow(e);  // 抛出 BpmnError，触发流程终止
            }
        }
    }

    /**
     * 执行具体的业务逻辑（子类实现）
     * <p>
     * 子类可以直接修改 {@code this.output} 对象来设置输出结果。
     * 输出对象已预初始化为 SUCCESS 状态，失败时调用 {@code markFailure()} 或 {@code terminateWorkflow()}。
     *
     * @param execution    Flowable执行上下文
     * @param configs      节点配置
     * @param inputMapping 输入映射（强类型）
     */
    protected abstract void executeInternal(
        DelegateExecution execution,
        Map<String, Object> configs,
        I inputMapping
    );

    /**
     * 通过反射获取InputMapping的类型
     */
    @SuppressWarnings("unchecked")
    protected Class<I> getInputMappingClass() {
        if (inputMappingClass == null) {
            Type genericSuperclass = getClass().getGenericSuperclass();
            if (genericSuperclass instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                // 第一个泛型参数是 I (InputMapping)
                inputMappingClass = (Class<I>) actualTypeArguments[0];
            }
        }
        return inputMappingClass;
    }

    /**
     * 通过反射获取Outputs的类型（预留，未来可能需要）
     */
    @SuppressWarnings("unchecked")
    protected Class<O> getOutputsClass() {
        if (outputsClass == null) {
            Type genericSuperclass = getClass().getGenericSuperclass();
            if (genericSuperclass instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                // 第二个泛型参数是 O (Outputs)
                outputsClass = (Class<O>) actualTypeArguments[1];
            }
        }
        return outputsClass;
    }

    /**
     * 解析并转换InputMapping
     */
    protected I parseAndConvertInputMapping(DelegateExecution execution) {
        try {
            String inputMappingJson = getFieldValue(inputMapping, execution);
            Class<I> inputClass = getInputMappingClass();

            if (inputMappingJson == null || inputMappingJson.isEmpty()) {
                return inputClass.getDeclaredConstructor().newInstance();
            }

            // 先解析为Map
            Map<String, Object> inputMap = objectMapper.readValue(
                inputMappingJson,
                new TypeReference<Map<String, Object>>() {
                }
            );

            // 处理表达式
            Map<String, Object> resolvedMap = resolveExpressions(inputMap, execution);

            // 转换为强类型对象
            return JsonUtils.convert(resolvedMap, inputClass);

        } catch (Exception e) {
            log.error("Failed to parse input mapping", e);
            throw new RuntimeException("Failed to parse input mapping", e);
        }
    }

    /**
     * 解析Map中的表达式
     * 自动处理纯表达式、模板字符串、纯文本三种情况
     * 
     * 重要：如果表达式解析失败（变量不存在），**不会设置该字段**，让JSON反序列化使用类型默认值
     */
    protected Map<String, Object> resolveExpressions(Map<String, Object> inputMap, DelegateExecution execution) {
        Map<String, Object> resolvedMap = new HashMap<>();

        log.debug("开始解析 inputMap: {}", inputMap);

        for (Map.Entry<String, Object> entry : inputMap.entrySet()) {
            Object value = entry.getValue();

            if (value instanceof String) {
                String strValue = (String) value;
                try {
                    // ✅ 使用 SpelExpressionResolver 统一解析方法，支持复杂表达式
                    String resolvedValue = SpelExpressionResolver.resolve(execution, strValue);
                    
                    // ⚠️ 关键修复：如果解析后仍然是未解析的占位符（如${targetRepository.systemId}），说明变量不存在
                    // 这种情况**不设置该字段**，让JSON反序列化时使用类型默认值（null或0等）
                    // 让具体的节点去校验参数是否有效，并抛出更友好的业务异常
                    if (isUnresolvedPlaceholder(resolvedValue)) {
                        log.warn("表达式未解析成功（变量不存在）: {} = {}，跳过该字段", entry.getKey(), strValue);
                        // 不设置该字段到resolvedMap中
                    } else {
                        log.debug("解析字段: {} = {} -> {}", entry.getKey(), strValue, resolvedValue);
                        resolvedMap.put(entry.getKey(), resolvedValue);
                    }
                } catch (Exception e) {
                    log.warn("解析失败: {}，跳过该字段", strValue, e);
                    // 不设置该字段到resolvedMap中
                }
            } else {
                resolvedMap.put(entry.getKey(), value);
            }
        }

        log.debug("解析后 resolvedMap: {}", resolvedMap);
        return resolvedMap;
    }
    
    /**
     * 判断是否为未解析的占位符
     * 例如：${targetRepository.systemId}、${some.variable}
     */
    private boolean isUnresolvedPlaceholder(String value) {
        if (value == null || value.isEmpty()) {
            return false;
        }
        // 检查是否以 ${ 开头且以 } 结尾，说明SpEL解析失败，保留了原样
        return value.startsWith("${") && value.endsWith("}");
    }

    protected String getFieldValue(Expression expression, DelegateExecution execution) {
        if (expression == null) return null;
        Object value = expression.getValue(execution);
        return value != null ? value.toString() : null;
    }

    protected Map<String, Object> parseJsonField(Expression expression, DelegateExecution execution) {
        String jsonStr = getFieldValue(expression, execution);
        if (jsonStr == null || jsonStr.isEmpty()) {
            return new HashMap<>();
        }
        try {
            return objectMapper.readValue(jsonStr, new TypeReference<>() {
            });
        } catch (Exception e) {
            log.error("Failed to parse JSON field: {}", jsonStr, e);
            return new HashMap<>();
        }
    }

    // ===================== 便利方法：流程控制 =====================

    /**
     * 终止流程（致命错误）- 使用自定义错误码
     * <p>
     * 适用场景：需要指定特定错误码用于边界事件捕获
     *
     * @param errorCode    错误码（如 WORKFLOW_EXEC_ERROR）
     * @param errorMessage 错误描述
     */
    protected void terminateWorkflow(String errorCode, String errorMessage) {
        log.error("🛑 Terminating workflow: errorCode={}, message={}", errorCode, errorMessage);

        // 自动记录错误日志到 Redis Stream
        logError(errorMessage);

        throw new org.flowable.engine.delegate.BpmnError(errorCode, errorMessage);
    }

    /**
     * 终止流程（致命错误）- 使用默认错误码
     * <p>
     * 适用场景：构建失败、审批拒绝、系统级异常等
     *
     * @param errorMessage 错误描述
     */
    protected void terminateWorkflow(String errorMessage) {
        terminateWorkflow("workflow_exec_error", errorMessage);
    }

    /**
     * 终止流程（致命错误）- 使用异常对象
     * <p>
     * 适用场景：捕获异常后直接终止流程
     *
     * @param exception 异常对象
     */
    protected void terminateWorkflow(Exception exception) {
        String errorMessage = exception.getMessage() != null
            ? exception.getMessage()
            : exception.getClass().getSimpleName();
        terminateWorkflow(errorMessage);
    }

    /**
     * 标记当前节点为失败状态（非致命错误，流程继续）
     * <p>
     * 直接修改 {@code this.output} 对象的状态为 FAILURE，并自动记录 WARN 日志到 Redis Stream。
     * <p>
     * 适用场景：通知发送失败、可选步骤失败、日志记录失败等
     *
     * @param errorMessage 错误描述
     */
    protected void markFailure(String errorMessage) {
        log.warn("⚠️ Node failed but workflow continues: {}", errorMessage);

        // 自动记录警告日志到 Redis Stream
        logWarn(errorMessage);

        // 设置失败状态
        if (output instanceof BaseNodeOutputs) {
            ((BaseNodeOutputs) output).setStatus(NodeExecutionStatusEnum.FAILURE);
            ((BaseNodeOutputs) output).setMessage(errorMessage);
        }
    }

    /**
     * 标记当前节点为失败状态（非致命错误，流程继续）- 使用异常对象
     * <p>
     * 适用场景：捕获异常后继续流程，但标记为失败
     *
     * @param exception 异常对象
     */
    protected void markFailure(Exception exception) {
        String errorMessage = exception.getMessage() != null
            ? exception.getMessage()
            : exception.getClass().getSimpleName();
        markFailure(errorMessage);
    }


    /**
     * 创建失败状态的输出对象（非致命错误，流程继续）
     * <p>
     * ⚠️ 已废弃：请使用 {@link #markFailure(String)} 代替
     * <p>
     * 适用场景：通知发送失败、可选步骤失败、日志记录失败等
     *
     * @param errorMessage 错误描述
     * @return 失败状态的输出对象（类型为当前节点的输出类型 O）
     * @deprecated 使用 {@link #markFailure(String)} 代替
     */
    @Deprecated
    protected O createFailureOutputs(String errorMessage) {
        log.warn("⚠️ Node failed but workflow continues: {}", errorMessage);

        // 自动记录警告日志到 Redis Stream
        logWarn(errorMessage);

        try {
            // 通过反射创建正确类型的输出对象
            Class<O> outputClass = getOutputsClass();
            O outputs = outputClass.getDeclaredConstructor().newInstance();

            // 设置失败状态（假设所有输出都继承自 BaseNodeOutputs）
            if (outputs instanceof BaseNodeOutputs) {
                ((BaseNodeOutputs) outputs).setStatus(NodeExecutionStatusEnum.FAILURE);
                ((BaseNodeOutputs) outputs).setMessage(errorMessage);
            }

            return outputs;

        } catch (Exception e) {
            // 降级方案：如果反射失败，返回 BaseNodeOutputs
            log.error("Failed to create failure outputs, using fallback BaseNodeOutputs", e);
            BaseNodeOutputs fallback = new BaseNodeOutputs();
            fallback.setStatus(NodeExecutionStatusEnum.FAILURE);
            fallback.setMessage(errorMessage);
            return (O) fallback;
        }
    }

    /**
     * 创建失败状态的输出对象（非致命错误，流程继续）- 使用异常对象
     * <p>
     * ⚠️ 已废弃：请使用 {@link #markFailure(Exception)} 代替
     * <p>
     * 适用场景：捕获异常后继续流程，但标记为失败
     *
     * @param exception 异常对象
     * @return 失败状态的输出对象
     * @deprecated 使用 {@link #markFailure(Exception)} 代替
     */
    @Deprecated
    protected O createFailureOutputs(Exception exception) {
        String errorMessage = exception.getMessage() != null
            ? exception.getMessage()
            : exception.getClass().getSimpleName();
        return createFailureOutputs(errorMessage);
    }

    /**
     * 创建成功状态的输出对象（便利方法）
     * <p>
     * 自动设置状态为 SUCCESS，并根据节点名称生成默认消息："{节点名称}执行成功"
     *
     * @param configsMap 节点配置（用于提取节点名称）
     * @return 成功状态的输出对象（类型为当前节点的输出类型 O）
     */
    protected O createSuccessOutputs(Map<String, Object> configsMap) {
        try {
            Class<O> outputClass = getOutputsClass();
            O outputs = outputClass.getDeclaredConstructor().newInstance();

            if (outputs instanceof BaseNodeOutputs) {
                ((BaseNodeOutputs) outputs).setStatus(NodeExecutionStatusEnum.SUCCESS);

                // ✅ 自动生成默认成功消息
                String nodeName = WorkflowUtils.extractNodeName(configsMap);
                ((BaseNodeOutputs) outputs).setMessage(nodeName + "执行成功");
            }

            return outputs;

        } catch (Exception e) {
            log.error("Failed to create success outputs, using fallback BaseNodeOutputs", e);
            BaseNodeOutputs fallback = new BaseNodeOutputs();
            fallback.setStatus(NodeExecutionStatusEnum.SUCCESS);
            fallback.setMessage("节点执行成功");
            return (O) fallback;
        }
    }


    // ===================== 日志记录辅助方法 =====================

    /**
     * 记录错误日志到 Redis Stream
     *
     * @param message 错误信息
     */
    protected void logError(String message) {
        if (workflowNodeLogService != null && currentProcessInstanceId != null && currentNodeId != null) {
            try {
                workflowNodeLogService.log(
                    currentProcessInstanceId,
                    currentNodeId,
                    LogSource.FLOWABLE,
                    LogLevel.ERROR,
                    message
                );
            } catch (Exception e) {
                // 日志记录失败不影响主流程
                log.error("Failed to log to Redis Stream: {}", message, e);
            }
        }
    }

    /**
     * 记录警告日志到 Redis Stream
     *
     * @param message 警告信息
     */
    protected void logWarn(String message) {
        if (workflowNodeLogService != null && currentProcessInstanceId != null && currentNodeId != null) {
            try {
                workflowNodeLogService.log(
                    currentProcessInstanceId,
                    currentNodeId,
                    LogSource.FLOWABLE,
                    LogLevel.WARN,
                    message
                );
            } catch (Exception e) {
                log.warn("Failed to log to Redis Stream: {}", message, e);
            }
        }
    }

    /**
     * 记录信息日志到 Redis Stream
     *
     * @param message 信息内容
     */
    protected void logInfo(String message) {
        if (workflowNodeLogService != null && currentProcessInstanceId != null && currentNodeId != null) {
            try {
                workflowNodeLogService.log(
                    currentProcessInstanceId,
                    currentNodeId,
                    LogSource.FLOWABLE,
                    LogLevel.INFO,
                    message
                );
            } catch (Exception e) {
                log.debug("Failed to log to Redis Stream: {}", message, e);
            }
        }
    }

} 