package cn.stylefeng.workflow.instance.core.nodeexe;

import cn.hutool.extra.spring.SpringUtil;
import cn.stylefeng.roses.kernel.rule.util.ExceptionUtil;
import cn.stylefeng.workflow.api.entity.design.Node;
import cn.stylefeng.workflow.api.enums.FlowLogLevelEnum;
import cn.stylefeng.workflow.api.enums.NodeEventTypeEnum;
import cn.stylefeng.workflow.api.enums.NodeTypeEnum;
import cn.stylefeng.workflow.api.pojo.InstanceContext;
import cn.stylefeng.workflow.event.api.EventPublishApi;
import cn.stylefeng.workflow.instance.api.node.NodeAction;
import cn.stylefeng.workflow.instance.api.pojo.NodeActionResult;
import cn.stylefeng.workflow.log.api.WorkflowLogApi;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
@Slf4j
public class NodeExecutor {

    @Resource
    private WorkflowLogApi workflowLogApi;

    @Resource
    private EventPublishApi eventPublishApi;

    public NodeActionResult executeNodeAction(Node nodeInfo, InstanceContext instanceContext) {

        Integer nodeType = nodeInfo.getNodeType();
        NodeTypeEnum nodeTypeEnum = NodeTypeEnum.START.parseToEnum(String.valueOf(nodeType));
        if (nodeTypeEnum == null) {
            workflowLogApi.logFail(instanceContext, nodeInfo.getNodeId(), "未找到节点执行器，节点的枚举值不对");
            return new NodeActionResult(instanceContext.getInstanceVariable());
        }

        NodeAction nodeAction = null;
        Map<String, NodeAction> nodeActionMap = SpringUtil.getBeansOfType(NodeAction.class);
        for (NodeAction item : nodeActionMap.values()) {
            if (nodeTypeEnum.equals(item.getNodeType())) {
                nodeAction = item;
            }
        }

        if (nodeAction == null) {
            workflowLogApi.logFail(instanceContext, nodeInfo.getNodeId(), "未找到节点执行器，节点的动作类未找到");
            return new NodeActionResult(instanceContext.getInstanceVariable());
        }

        eventPublishApi.publishNodeEvent(NodeEventTypeEnum.EXE_BEFORE, nodeInfo.getNodeId(), instanceContext);

        long nodeStartTime = System.currentTimeMillis();

        try {

            NodeActionResult nodeActionResult = nodeAction.doAction(nodeInfo, instanceContext);

            long nodeEndTime = System.currentTimeMillis();

            workflowLogApi.createNodeLog(instanceContext, nodeInfo.getNodeId(), FlowLogLevelEnum.INFO, nodeStartTime, nodeEndTime,
                    "节点执行成功", true);

            instanceContext.setInstanceVariable(nodeActionResult.getNewInstanceVariable());

            eventPublishApi.publishNodeEvent(NodeEventTypeEnum.EXE_SUCCESS, nodeInfo.getNodeId(), instanceContext);

            return nodeActionResult;

        } catch (Exception e) {
            log.error("执行节点过程中，出现错误", e);

            long nodeEndTime = System.currentTimeMillis();

            eventPublishApi.publishNodeEvent(NodeEventTypeEnum.EXE_ERROR, nodeInfo.getNodeId(), instanceContext);

            String message = "【执行失败，出现异常】" + ExceptionUtil.getFirstStackTraceByPackageName(e, "cn.stylefeng");
            workflowLogApi.createNodeLog(instanceContext, nodeInfo.getNodeId(), FlowLogLevelEnum.ERROR, nodeStartTime, nodeEndTime,
                    message, true);

            return new NodeActionResult(instanceContext.getInstanceVariable());
        }
    }

}
