package cn.axzo.workflow.core.engine.cmd;

import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO;
import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler;
import cn.axzo.workflow.core.engine.job.AsyncRemindTaskJobHandler;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import org.apache.commons.collections.CollectionUtils;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.job.service.JobService;
import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_REMIND;
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.REMIND_TASK_TOO_MANY;
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_REMIND_ERROR_NOT_EXISTS;

/**
 * TODO
 *
 * @author wangli
 * @since 2025-06-13 14:01
 */
public class CustomRemindTaskAsyncCmd extends AbstractCommand<String> implements Serializable {
    private static final Logger logger = LoggerFactory.getLogger(CustomRemindTaskAsyncCmd.class);
    private final BpmnTaskRemindDTO dto;

    public CustomRemindTaskAsyncCmd(BpmnTaskRemindDTO dto) {
        this.dto = dto;
    }

    @Override
    public String paramToJsonString() {
        return JSON.toJSONString(dto);
    }

    @Override
    public String executeInternal(CommandContext commandContext) {
        ProcessEngineConfigurationImpl processEngineConfiguration =
                CommandContextUtil.getProcessEngineConfiguration(commandContext);
        RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
        ProcessInstance processInstance =
                runtimeService.createProcessInstanceQuery().processInstanceId(dto.getProcessInstanceId()).singleResult();
        if (Objects.isNull(processInstance)) {
            throw new WorkflowEngineException(PROCESS_INSTANCE_CANT_REMIND, dto.getProcessInstanceId());
        }

        TaskService taskService = processEngineConfiguration.getTaskService();
        TaskQuery taskQuery = taskService.createTaskQuery().processInstanceId(dto.getProcessInstanceId());
        if (StringUtils.hasLength(dto.getTaskDefinitionKey())) {
            taskQuery.taskDefinitionKey(dto.getTaskDefinitionKey());
        }
        List<Task> list = taskQuery.active().list();
        if (CollectionUtils.isEmpty(list)) {
            throw new WorkflowEngineException(TASK_REMIND_ERROR_NOT_EXISTS);
        }
        if (!StringUtils.hasText(dto.getTaskDefinitionKey())) {
            List<String> taskDefinitionKeys = list.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList());
            if (taskDefinitionKeys.isEmpty()) {
                throw new WorkflowEngineException(TASK_REMIND_ERROR_NOT_EXISTS);
            } else if (taskDefinitionKeys.size() > 1) {
                throw new WorkflowEngineException(REMIND_TASK_TOO_MANY);
            } else {
                dto.setTaskDefinitionKey(taskDefinitionKeys.get(0));
            }
        }
        return startAsync(processEngineConfiguration, list.get(0));
    }

    private String startAsync(ProcessEngineConfigurationImpl processEngineConfiguration, Task task) {
        JobService jobService = processEngineConfiguration.getJobServiceConfiguration().getJobService();

        JobEntity job = jobService.createJob();
        // 这里的 executionId 可为 null
        job.setExecutionId(task.getExecutionId());
        job.setProcessInstanceId(task.getProcessInstanceId());
        job.setProcessDefinitionId(task.getProcessDefinitionId());
        job.setElementId(task.getTaskDefinitionKey());
        job.setElementName(task.getName());
        job.setJobHandlerType(AsyncRemindTaskJobHandler.TYPE);
        job.setTenantId(task.getTenantId());

        // 携带自定义的数据
        job.setCustomValues(JSONUtil.toJsonStr(dto));

        // 创建异步任务并调度
        jobService.createAsyncJob(job, false);
        jobService.scheduleAsyncJob(job);
        return job.getId();
    }
}