package cn.axzo.workflow.core.service.impl;

import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.service.BpmnProcessJobService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.flowable.engine.ManagementService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.job.api.Job;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;

import static cn.axzo.workflow.common.code.AsyncJobRespCode.JOB_NOT_EXISTS_JOB_ID;
import static cn.axzo.workflow.common.code.AsyncJobRespCode.JOB_NOT_EXISTS_PROC_INST_ID;

@Service
@Slf4j
public class BpmnProcessJobServiceImp implements BpmnProcessJobService {

    @Resource
    private ManagementService managementService;

    @Resource
    private ProcessEngineConfigurationImpl processEngineConfiguration;

    @Override
    public void executeDeadLetterJobActionByJobId(String jobId) {
        Job deadLetterJob = getDeadLetterJobById(jobId);
        managementService.moveDeadLetterJobToExecutableJob(deadLetterJob.getId(), processEngineConfiguration.getAsyncExecutorNumberOfRetries());
    }

    @Override
    public void executeDeadLetterJobActionByProcInstId(String processInstanceId) {
        List<Job> jobs = getDeadLetterProcInstId(processInstanceId);
        for (Job deadLetterJob : jobs) {
            managementService.moveDeadLetterJobToExecutableJob(deadLetterJob.getId(), processEngineConfiguration.getAsyncExecutorNumberOfRetries());
        }
    }

    @Override
    public String getDeadLetterJobExceptionStacktrace(String processInstId) {
        List<Job> jobs = managementService.createDeadLetterJobQuery().processInstanceId(processInstId).list();
        if (CollectionUtils.isEmpty(jobs)) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        jobs.forEach(job -> {
            String deadLetterJobExceptionStacktrace = managementService.getDeadLetterJobExceptionStacktrace(job.getId());
            if (StringUtils.hasText(deadLetterJobExceptionStacktrace)) {
                builder.append(deadLetterJobExceptionStacktrace);
                builder.append("\n");
            }
        });
        return builder.toString();
    }

    @Override
    public String getDeadLetterJobExceptionStacktraceByJobId(String jobId) {
        if (!StringUtils.hasText(jobId)) {
            return "";
        }
        return managementService.getDeadLetterJobExceptionStacktrace(jobId);
    }

    protected Job getDeadLetterJobById(String jobId) {
        Job job = managementService.createDeadLetterJobQuery().jobId(jobId).singleResult();
        if (job == null) {
            throw new WorkflowEngineException(JOB_NOT_EXISTS_JOB_ID, jobId);
        }
        return job;
    }

    protected List<Job> getDeadLetterProcInstId(String procInstId) {
        List<Job> jobs = managementService.createDeadLetterJobQuery().processInstanceId(procInstId).list();
        if (CollectionUtils.isEmpty(jobs)) {
            throw new WorkflowEngineException(JOB_NOT_EXISTS_PROC_INST_ID, procInstId);
        }
        return jobs;
    }

}
