package cn.stylefeng.workflow.instance.core.actions.custom;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.stylefeng.roses.kernel.rule.util.ExceptionUtil;
import cn.stylefeng.workflow.api.entity.design.Node;
import cn.stylefeng.workflow.api.entity.instance.RuntimeNode;
import cn.stylefeng.workflow.api.enums.*;
import cn.stylefeng.workflow.api.pojo.InstanceContext;
import cn.stylefeng.workflow.api.pojo.config.node.activity.NodeActivity;
import cn.stylefeng.workflow.design.api.NodeActivityServiceApi;
import cn.stylefeng.workflow.instance.api.node.NodeAction;
import cn.stylefeng.workflow.instance.api.pojo.NodeActionResult;
import cn.stylefeng.workflow.instance.modular.manage.service.RuntimeNodeService;
import cn.stylefeng.workflow.log.api.WorkflowLogApi;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Slf4j
public class CustomActiviyNodeAction extends NodeAction {

    @Resource
    private NodeActivityServiceApi nodeActivityServiceApi;

    @Resource
    private RuntimeNodeService runtimeNodeService;

    @Resource
    private WorkflowLogApi workflowLogApi;

    @Override
    public NodeTypeEnum getNodeType() {
        return NodeTypeEnum.CUSTOM_ACTIVITY;
    }

    @Override
    public NodeActionResult doAction(Node nodeInfo, InstanceContext instanceContext) {

        RuntimeNode runtimeNode = super.createRuntimeNode(nodeInfo, instanceContext);

        NodeActivity nodeActivity = nodeActivityServiceApi.getNodeActivity(nodeInfo.getNodeId());
        log.info("开始执行自定义任务的节点，自定义任务节点的数据如下：{}", nodeActivity);

        if (ActivityTypeEnum.RPC.getKey().equals(nodeActivity.getActivityType())) {

            runtimeNode = super.finishAndSaveRuntimeNode(runtimeNode);

            List<Node> nextNodeList = super.calcNextNodeList(nodeInfo, instanceContext);
            return new NodeActionResult(runtimeNode, nextNodeList, instanceContext.getInstanceVariable());
        }

        else if (ActivityTypeEnum.HTTP.getKey().equals(nodeActivity.getActivityType())) {
            invokeHttpMethod(nodeInfo, runtimeNode, instanceContext, nodeActivity);
        }

        return afterInvoke(nodeInfo, instanceContext, runtimeNode, nodeActivity);
    }

    private NodeActionResult afterInvoke(Node nodeInfo, InstanceContext instanceContext, RuntimeNode runtimeNode,
                                         NodeActivity nodeActivity) {

        Integer requestAfterType = nodeActivity.getRequestAfterType();

        if (ActivityRequestAfterTypeEnum.CONTINUE.getCode().equals(requestAfterType)) {
            runtimeNode.setNodeStatus(NodeStatusEnum.FINISH.getStatus());
            this.runtimeNodeService.save(runtimeNode);

            List<Node> nextNodeList = super.calcNextNodeList(nodeInfo, instanceContext);
            return new NodeActionResult(runtimeNode, nextNodeList, instanceContext.getInstanceVariable());
        }

        else {

            runtimeNode.setNodeStatus(NodeStatusEnum.RUNNING.getStatus());
            this.runtimeNodeService.save(runtimeNode);

            return new NodeActionResult(runtimeNode, null, instanceContext.getInstanceVariable());
        }
    }

    private void invokeHttpMethod(Node nodeInfo, RuntimeNode runtimeNode, InstanceContext instanceContext, NodeActivity nodeActivity) {

        Integer syncType = nodeActivity.getSyncType();

        if (ActivitySyncTypeEnum.SYNC.getCode().equals(syncType)) {

            doHttpMethodExecute(nodeInfo, runtimeNode, instanceContext, nodeActivity);
        }

        else {

            Thread thread = new Thread(() -> {
                doHttpMethodExecute(nodeInfo, runtimeNode, instanceContext, nodeActivity);
            });
            thread.start();
        }
    }

    private void doHttpMethodExecute(Node nodeInfo, RuntimeNode runtimeNode, InstanceContext instanceContext, NodeActivity nodeActivity) {

        if ("get".equalsIgnoreCase(nodeActivity.getHttpMethod())) {
            workflowLogApi.logSuccess(instanceContext, nodeInfo.getNodeId(),
                    "开始执行HTTP Get请求，业务端URL为：" + nodeActivity.getHttpUrl());
            HttpRequest httpRequestGet = HttpUtil.createGet(nodeActivity.getHttpUrl());
            if (ObjectUtil.isNotEmpty(nodeActivity.getRequestParams())) {
                String requestParams = nodeActivity.getRequestParams();
                JSONObject jsonObject = JSON.parseObject(requestParams);

                jsonObject.put("runtimeNodeId", runtimeNode.getRuNodeId());

                httpRequestGet.form(jsonObject);

                workflowLogApi.logSuccess(instanceContext, nodeInfo.getNodeId(),
                        "构造http请求的参数信息如下：" + jsonObject.toJSONString());
            }
            doHttpExecute(nodeInfo, instanceContext, httpRequestGet);
        }

        else if ("post".equalsIgnoreCase(nodeActivity.getHttpMethod())) {

            workflowLogApi.logSuccess(instanceContext, nodeInfo.getNodeId(),
                    "开始执行HTTP Post请求，业务端URL为：" + nodeActivity.getHttpUrl());

            HttpRequest httpRequestPost = HttpUtil.createPost(nodeActivity.getHttpUrl());

            JSONObject commonParams = new JSONObject();
            commonParams.put("workflowContext",
                    WorkflowContextFactory.createWorkflowRequestContext(runtimeNode, instanceContext.getInstanceVariable()));

            if (ObjectUtil.isNotEmpty(nodeActivity.getRequestParams())) {
                String requestParams = nodeActivity.getRequestParams();
                JSONObject specialParams = JSON.parseObject(requestParams);
                commonParams.putAll(specialParams);
            }

            workflowLogApi.logSuccess(instanceContext, nodeInfo.getNodeId(),
                    "构造http请求的参数Json信息如下：\n" + JSON.toJSONString(commonParams, SerializerFeature.PrettyFormat));

            httpRequestPost.body(commonParams.toJSONString());
            doHttpExecute(nodeInfo, instanceContext, httpRequestPost);
        }
    }

    private void doHttpExecute(Node nodeInfo, InstanceContext instanceContext, HttpRequest httpRequest) {
        HttpResponse execute = null;
        try {
            execute = httpRequest.execute();
        } catch (Exception e) {
            log.error("自定义节点执行HTTP调用失败，异常信息为：", e);
            workflowLogApi.logSuccess(instanceContext, nodeInfo.getNodeId(),
                    "自定义节点执行HTTP调用失败，异常信息为：" + ExceptionUtil.getFirstStackTraceByPackageName(e, "cn.stylefeng"));
        }

        String jsonResult = execute.body();
        JSONObject resultObject = JSON.parseObject(jsonResult);

        String resultTip = resultObject.getString("data");

        workflowLogApi.logSuccess(instanceContext, nodeInfo.getNodeId(), "HTTP调用成功，业务端返回结果为：\n" + resultTip);
    }

}
