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

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.task.Task;
import cn.hutool.extra.spring.SpringUtil;
import cn.stylefeng.roses.kernel.timer.api.exception.TimerException;
import cn.stylefeng.roses.kernel.timer.api.exception.enums.TimerExceptionEnum;
import cn.stylefeng.workflow.api.entity.design.Definition;
import cn.stylefeng.workflow.api.entity.instance.RuntimeNode;
import cn.stylefeng.workflow.api.pojo.InstanceContext;
import cn.stylefeng.workflow.api.pojo.config.model.FlowGlobalConfig;
import cn.stylefeng.workflow.api.pojo.config.model.ModelTimer;
import cn.stylefeng.workflow.api.timer.BaseWorkflowTimerAction;
import cn.stylefeng.workflow.instance.modular.manage.pojo.request.RuntimeTimerRequest;
import cn.stylefeng.workflow.instance.modular.manage.service.RuntimeTimerService;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Slf4j
public class WorkflowTimerExec {

    @Resource
    private RuntimeTimerService runtimeTimerService;

    public void startTimerOnInstanceStart(Definition definition, InstanceContext instanceContext) {
        if (definition == null) {
            return;
        }
        if (definition.getXSixGraphJson() == null) {
            return;
        }
        if (definition.getXSixGraphJson().getFlowGlobalConfig() == null) {
            return;
        }
        FlowGlobalConfig flowGlobalConfig = definition.getXSixGraphJson().getFlowGlobalConfig();
        List<ModelTimer> modelTimerList = flowGlobalConfig.getModelTimerList();
        if (ObjectUtil.isNotEmpty(modelTimerList)) {
            for (ModelTimer modelTimer : modelTimerList) {
                this.startTimer(
                        true,
                        null,
                        modelTimer.getTimerActionClass(),
                        modelTimer.getTimerName(),
                        modelTimer.getTimerCron(),
                        null,
                        instanceContext);
            }
        }
    }

    public void startTimer(Boolean createRuntimeTimer,
                           Long nodeTimerId,
                           String timerClass,
                           String timerName,
                           String timerCron,
                           RuntimeNode runtimeNode,
                           InstanceContext instanceContext) {

        if (StrUtil.isBlank(timerCron)) {
            throw new TimerException(TimerExceptionEnum.PARAM_HAS_NULL, "cron");
        }

        if (StrUtil.isBlank(timerClass)) {
            throw new TimerException(TimerExceptionEnum.PARAM_HAS_NULL, "className");
        }

        try {
            Class.forName(timerClass);
        } catch (ClassNotFoundException e) {
            throw new TimerException(TimerExceptionEnum.CLASS_NOT_FOUND, timerClass);
        }

        Task task = () -> {
            try {
                BaseWorkflowTimerAction timerAction = (BaseWorkflowTimerAction) SpringUtil.getBean(Class.forName(timerClass));
                timerAction.action(runtimeNode, instanceContext);
            } catch (Exception e) {
                log.error("流程的定时任务执行异常：{}", e.getMessage());
            }
        };

        CronUtil.schedule(IdWorker.getIdStr(), timerCron, task);

        if (createRuntimeTimer) {
            RuntimeTimerRequest runtimeTimerRequest = new RuntimeTimerRequest();
            runtimeTimerRequest.setInstanceId(instanceContext.getRuntimeInstance().getInstanceId());
            runtimeTimerRequest.setNodeTimerId(nodeTimerId);
            runtimeTimerRequest.setParamRuntimeNodeJson(runtimeNode);
            runtimeTimerRequest.setParamInstanceContextJson(instanceContext);

            runtimeTimerRequest.setTimerName(timerName);
            runtimeTimerRequest.setTimerActionClass(timerClass);
            runtimeTimerRequest.setTimerCron(timerCron);

            runtimeTimerService.add(runtimeTimerRequest);
        }
    }

}
