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

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.ServiceTask;
import org.flowable.engine.delegate.BpmnError;
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 static com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants.WORKFLOW_NODE_EXECUTION_STATUS_FAILURE;
import static com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants.WORKFLOW_NODE_EXECUTION_STATUS_SUCCESS;
import static com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants.WORKFLOW_PREVIOUS_NODE_EXECUTION_STATUS_VARIABLE_NAME;

import java.util.Map;
import java.util.Optional;

/**
 * 任务委派者基类
 * 负责处理panelVariables和localVariables的转换和注入
 *
 * @param <P> Panel变量类型
 * @param <L> Local变量类型
 *            <p>
 *            <p>
 *            panelVariables: 节点配置，一次配置长期有效
 *            localVariables: 运行时变量，每次执行都会变化
 */
@Slf4j
public abstract class BaseNodeDelegate<P, L> implements JavaDelegate {


    @Autowired
    private ObjectMapper objectMapper;

    // 字段注入，由Flowable自动设置
    protected Expression panelVariables;

    @Override
    public void execute(DelegateExecution execution) {
        try {
            // 在节点执行前，清除前一个节点的状态
            clearPreviousNodeStatus(execution);
            // 获取并转换Panel变量
            P panelVars = null;
            if (panelVariables != null) {
                String panelVarsJson = panelVariables.getValue(execution).toString();
                JsonNode panelVarsNode = objectMapper.readTree(panelVarsJson);
                panelVars = objectMapper.treeToValue(panelVarsNode, getPanelVariablesClass());
            }

            // 获取并转换Local变量
            L localVars = objectMapper.convertValue(execution.getVariables(), getLocalVariablesClass());
            // 执行具体的任务逻辑
            executeInternal(execution, panelVars, localVars);

            // 如果节点没有设置状态，默认设置成功状态
            String status = getExecutionStatus(execution);
            if (status == null) {
                setExecutionStatus(execution, WORKFLOW_NODE_EXECUTION_STATUS_SUCCESS);
            }

        } catch (Exception e) {
            // 设置失败状态
            setExecutionStatus(execution, WORKFLOW_NODE_EXECUTION_STATUS_FAILURE);
            log.error("Task execution failed", e);
        }
    }

    /**
     * 设置执行状态
     *
     * @param execution 执行上下文
     * @param status    状态值
     */
    protected void setExecutionStatus(DelegateExecution execution, String status) {
        execution.setVariable(WORKFLOW_PREVIOUS_NODE_EXECUTION_STATUS_VARIABLE_NAME, status);
        log.debug("Set execution status: {}", status);
    }

    /**
     * 获取Panel变量的类型
     *
     * @return Panel变量的Class对象
     */
    protected abstract Class<P> getPanelVariablesClass();

    /**
     * 获取Local变量的类型
     *
     * @return Local变量的Class对象
     */
    protected abstract Class<L> getLocalVariablesClass();

    /**
     * 执行具体的任务逻辑
     *
     * @param execution      DelegateExecution对象
     * @param panelVariables 转换后的Panel变量
     * @param localVariables 转换后的Local变量
     */
    protected abstract void executeInternal(DelegateExecution execution, P panelVariables, L localVariables);

    /**
     * 清除前一个节点的状态
     */
    private void clearPreviousNodeStatus(DelegateExecution execution) {
        // 只有在当前节点是ServiceTask时才清除状态
        execution.removeVariable(WORKFLOW_PREVIOUS_NODE_EXECUTION_STATUS_VARIABLE_NAME);
        log.debug("Cleared previous node status for node: {}", execution.getCurrentActivityId());
    }

    /**
     * 获取执行状态
     *
     * @param execution 执行上下文
     * @return 执行状态，如果不存在则返回null
     */
    protected String getExecutionStatus(DelegateExecution execution) {
        return Optional.ofNullable(execution.getVariables())
            .map(vars -> vars.get(WORKFLOW_PREVIOUS_NODE_EXECUTION_STATUS_VARIABLE_NAME))
            .map(Object::toString)
            .orElse(null);
    }
} 