
package org.jeecg.modules.workFlow.flowlong.engine;

import org.jeecg.modules.workFlow.flowlong.engine.assist.Assert;
import org.jeecg.modules.workFlow.flowlong.engine.assist.ObjectUtils;
import org.jeecg.modules.workFlow.flowlong.engine.core.Execution;
import org.jeecg.modules.workFlow.flowlong.engine.core.FlowCreator;
import org.jeecg.modules.workFlow.flowlong.engine.core.enums.*;
import org.jeecg.modules.workFlow.flowlong.engine.entity.FlwTask;
import org.jeecg.modules.workFlow.flowlong.engine.entity.FlwTaskActor;
import org.jeecg.modules.workFlow.flowlong.engine.model.NodeAssignee;
import org.jeecg.modules.workFlow.flowlong.engine.model.NodeModel;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

/**
 * 任务业务类接口
 *

 */
public interface TaskService {

    /**
     * 根据任务ID，创建人ID完成任务
     * <p>
     * 该方法仅仅结束活动任务，并不能驱动流程继续执行
     * </p>
     *
     * @param taskId      任务ID
     * @param flowCreator 任务完成者
     * @param args        任务参数
     * @return Task 任务对象
     */
    default FlwTask complete(Long taskId, FlowCreator flowCreator, Map<String, Object> args) {
        return this.executeTask(taskId, flowCreator, args, TaskState.complete, TaskEventType.complete);
    }

    default FlwTask complete(Long taskId, FlowCreator flowCreator) {
        return this.complete(taskId, flowCreator, null);
    }

    /**
     * 根据任务ID，创建人ID完成任务
     *
     * @param taskId      任务ID
     * @param flowCreator 任务完成者
     * @param args        任务参数
     * @param taskState   任务状态
     * @param eventType   任务执行事件类型
     * @return Task 任务对象
     */
    FlwTask executeTask(Long taskId, FlowCreator flowCreator, Map<String, Object> args, TaskState taskState, TaskEventType eventType);

    /**
     * 强制完成所有任务
     *
     * @param instanceId    流程实例ID
     * @param flowCreator   处理人员
     * @param instanceState 流程实例最终状态
     * @param eventType     监听事件类型
     * @return true 成功 false 失败
     */
    boolean forceCompleteAllTask(Long instanceId, FlowCreator flowCreator, InstanceState instanceState, TaskEventType eventType);

    /**
     * 强制完成某个任务
     *
     * @param flwTask     审批任务
     * @param flowCreator 处理人员
     * @param taskState   流任务状态
     * @param eventType   监听事件类型
     * @return true 成功 false 失败
     */
    boolean forceCompleteTask(FlwTask flwTask, FlowCreator flowCreator, TaskState taskState, TaskEventType eventType);

    /**
     * 执行节点跳转任务
     *
     * @param taskId            任务ID
     * @param flowCreator       任务创建者
     * @param args              任务参数
     * @param nodeKey           跳转至目标节点key
     * @param executionFunction 执行函数
     * @param taskTye           任务类型，仅支持 jump rejectJump routeJump
     * @return 当前 flowCreator 所在的任务
     */
    Optional<FlwTask> executeJumpTask(Long taskId, String nodeKey, FlowCreator flowCreator, Map<String, Object> args, Function<FlwTask, Execution> executionFunction, TaskType taskTye);

    default boolean executeJumpTask(Long taskId, String nodeKey, FlowCreator flowCreator, Map<String, Object> args, Function<FlwTask, Execution> executionFunction) {
        return executeJumpTask(taskId, nodeKey, flowCreator, args, executionFunction, TaskType.jump).isPresent();
    }

    default boolean executeJumpTask(Long taskId, String nodeKey, FlowCreator flowCreator, Function<FlwTask, Execution> executionFunction) {
        return executeJumpTask(taskId, nodeKey, flowCreator, null, executionFunction);
    }

    /**
     * 执行触发器任务
     *
     * @param execution {@link Execution}
     * @param flwTask   触发器任务
     * @return true 成功 false 失败
     */
    boolean executeTaskTrigger(Execution execution, FlwTask flwTask);

    /**
     * 完成指定实例ID活动任务
     *
     * @param instanceId  实例ID
     * @param flowCreator 处理人员
     * @return true 成功 false 失败
     */
    boolean completeActiveTasksByInstanceId(Long instanceId, FlowCreator flowCreator);

    /**
     * 更新任务对象
     *
     * @param flwTask     任务对象
     * @param flowCreator 处理人员
     */
    void updateTaskById(FlwTask flwTask, FlowCreator flowCreator);

    /**
     * 查看任务设置为已阅状态
     *
     * @param taskId    任务ID
     * @param taskActor 任务参与者
     * @return true 成功 false 失败
     */
    boolean viewTask(Long taskId, FlwTaskActor taskActor);

    /**
     * 角色根据 任务ID 认领任务，删除其它任务参与者
     *
     * @param taskId      任务ID
     * @param flowCreator 任务认领者
     * @return Task 任务对象
     */
    FlwTask claimRole(Long taskId, FlowCreator flowCreator);

    /**
     * 部门根据 任务ID 认领任务，删除其它任务参与者
     *
     * @param taskId      任务ID
     * @param flowCreator 任务认领者
     * @return Task 任务对象
     */
    FlwTask claimDepartment(Long taskId, FlowCreator flowCreator);

    /**
     * 根据 任务ID 指定代理人
     *
     * @param taskId            任务ID
     * @param flowCreator       任务参与者
     * @param agentFlowCreators 指定代理人列表
     * @param args              任务参数
     * @return true 成功 false 失败
     */
    default boolean agentTask(Long taskId, FlowCreator flowCreator, List<FlowCreator> agentFlowCreators, Map<String, Object> args) {
        return this.assigneeTask(taskId, TaskType.agent, flowCreator, agentFlowCreators, args, null);
    }

    default boolean agentTask(Long taskId, FlowCreator flowCreator, List<FlowCreator> agentFlowCreators) {
        return this.agentTask(taskId, flowCreator, agentFlowCreators, null);
    }

    /**
     * 根据 任务ID 转办任务
     *
     * @param taskId              任务ID
     * @param flowCreator         任务参与者
     * @param assigneeFlowCreator 指定办理人
     * @param args                任务参数
     * @return true 成功 false 失败
     */
    default boolean transferTask(Long taskId, FlowCreator flowCreator, FlowCreator assigneeFlowCreator, Map<String, Object> args) {
        return this.assigneeTask(taskId, TaskType.transfer, flowCreator, Collections.singletonList(assigneeFlowCreator), args, null);
    }

    default boolean transferTask(Long taskId, FlowCreator flowCreator, FlowCreator assigneeFlowCreator) {
        return this.transferTask(taskId, flowCreator, assigneeFlowCreator, null);
    }

    /**
     * 参与者的所有任务【离职转办】给指定办理人
     * <p>
     * 用于任务参与者离职
     * </p>
     *
     * @param flowCreator         任务参与者
     * @param assigneeFlowCreator 指定办理人
     * @return true 成功 false 失败
     */
    boolean transferTask(FlowCreator flowCreator, FlowCreator assigneeFlowCreator);

    /**
     * 根据 任务ID 委派任务、代理人办理完任务该任务重新归还给原处理人
     *
     * @param taskId              任务ID
     * @param flowCreator         任务参与者
     * @param assigneeFlowCreator 指定办理人
     * @param args                任务参数
     * @return true 成功 false 失败
     */
    default boolean delegateTask(Long taskId, FlowCreator flowCreator, FlowCreator assigneeFlowCreator, Map<String, Object> args) {
        return this.assigneeTask(taskId, TaskType.delegate, flowCreator, Collections.singletonList(assigneeFlowCreator), args, null);
    }

    default boolean delegateTask(Long taskId, FlowCreator flowCreator, FlowCreator assigneeFlowCreator) {
        return this.delegateTask(taskId, flowCreator, assigneeFlowCreator, null);
    }

    /**
     * 根据 任务ID 分配任务给指定办理人、重置任务类型
     *
     * @param taskId               任务ID
     * @param taskType             任务类型
     * @param flowCreator          任务参与者
     * @param assigneeFlowCreators 指定办理人列表
     * @param args                 任务参数
     * @param check                校验函数，可以根据 dbFlwTask.getAssignorId() 是否存在判断为重发分配
     * @return true 成功 false 失败
     */
    boolean assigneeTask(Long taskId, TaskType taskType, FlowCreator flowCreator, List<FlowCreator> assigneeFlowCreators, Map<String, Object> args, Function<FlwTask, Boolean> check);

    default boolean assigneeTask(Long taskId, TaskType taskType, FlowCreator flowCreator, List<FlowCreator> assigneeFlowCreators) {

        // 校验存在重复分配抛出异常
        return this.assigneeTask(taskId, taskType, flowCreator, assigneeFlowCreators, null, t -> {
            if (ObjectUtils.isNotEmpty(t.getAssignorId())) {
                Assert.illegal("Do not allow duplicate assign , taskId = " + taskId);
            }
            return true;
        });
    }

    /**
     * 根据 任务ID 解决委派任务
     *
     * @param taskId      任务ID
     * @param flowCreator 任务参与者
     * @return true 成功 false 失败
     */
    boolean resolveTask(Long taskId, FlowCreator flowCreator);

    /**
     * 拿回任务、在当前办理人尚未处理文件前，允许上一节点提交人员执行拿回
     *
     * @param taskId      任务ID（当前节点的父任务ID属于历史任务）
     * @param flowCreator 任务创建者
     * @return 拿回任务
     */
    Optional<FlwTask> reclaimTask(Long taskId, FlowCreator flowCreator);

    /**
     * 唤醒撤回或拒绝终止历史任务（只有实例发起人可操作）
     *
     * @param instanceId  历史实例ID
     * @param flowCreator 任务唤醒者
     * @return true 成功 false 失败
     */
    boolean resume(Long instanceId, FlowCreator flowCreator);

    /**
     * 根据任务ID、创建人撤回任务（该任务后续任务未执行前有效）
     *
     * @param taskId      待撤回历史任务ID
     * @param flowCreator 任务创建者
     * @return Task 任务对象
     */
    Optional<FlwTask> withdrawTask(Long taskId, FlowCreator flowCreator);

    /**
     * 根据当前任务对象驳回至上一步处理
     *
     * @param currentFlwTask 当前任务对象
     * @param flowCreator    任务创建者
     * @param args           任务参数
     * @return Task 任务对象
     */
    Optional<FlwTask> rejectTask(FlwTask currentFlwTask, FlowCreator flowCreator, Map<String, Object> args);

    default Optional<FlwTask> rejectTask(FlwTask currentFlwTask, FlowCreator flowCreator) {
        return rejectTask(currentFlwTask, flowCreator, null);
    }

    /**
     * 根据 taskId、createBy 判断创建人createBy是否允许执行任务
     *
     * @param flwTask 任务对象
     * @param userId  用户ID
     * @return 被允许参与者 {@link FlwTaskActor}
     */
    FlwTaskActor isAllowed(FlwTask flwTask, String userId);

    /**
     * 根据任务模型、执行对象创建新的任务
     *
     * @param taskModel    任务模型
     * @param execution    执行对象
     * @param taskFunction 任务处理函数，如果自定义 CreateTaskHandler 可用于控制任务创建属性设置
     * @return 创建任务集合
     */
    List<FlwTask> createTask(NodeModel taskModel, Execution execution, Function<FlwTask, FlwTask> taskFunction);

    default List<FlwTask> createTask(NodeModel taskModel, Execution execution) {
        return createTask(taskModel, execution, null);
    }

    /**
     * 根据已有任务、参与者创建新的任务
     * <p>
     * 适用于动态转派，动态协办等处理且流程图中不体现节点情况
     * </p>
     *
     * @param taskId            主办任务ID
     * @param taskActors        参与者集合
     * @param taskType          任务类型
     * @param performType       参与类型
     * @param flowCreator       任务创建者
     * @param executionFunction 执行函数
     * @return 创建任务集合
     */
    List<FlwTask> createNewTask(Long taskId, TaskType taskType, PerformType performType, List<FlwTaskActor> taskActors, FlowCreator flowCreator, Function<FlwTask, Execution> executionFunction);

    /**
     * 创建抄送任务
     * <p>默认不校验是否重复抄送</p>
     *
     * @param taskModel   任务模型
     * @param flwTask     当前任务
     * @param ccUserList  抄送任务分配到任务的人或角色列表
     * @param flowCreator 任务创建者
     */
    boolean createCcTask(NodeModel taskModel, FlwTask flwTask, List<NodeAssignee> ccUserList, FlowCreator flowCreator);

    /**
     * 获取超时或者提醒的任务
     *
     * @return 任务列表
     */
    List<FlwTask> getTimeoutOrRemindTasks();

    /**
     * 根据任务ID获取任务模型
     *
     * @param taskId 任务ID
     * @return 流程模型
     */
    NodeModel getTaskModel(Long taskId);

    /**
     * 向指定的任务ID添加参与者【加签】
     *
     * @param taskId      任务ID
     * @param performType 参与类型 {@link PerformType}
     * @param taskActors  参与者列表
     * @param flowCreator 执行操作人员
     * @return true 成功 false 失败
     */
    boolean addTaskActor(Long taskId, PerformType performType, List<FlwTaskActor> taskActors, FlowCreator flowCreator);

    default boolean addTaskActor(Long taskId, PerformType performType, FlwTaskActor taskActor, FlowCreator flowCreator) {
        return this.addTaskActor(taskId, performType, Collections.singletonList(taskActor), flowCreator);
    }

    /**
     * 对指定的任务ID删除参与者【减签】
     *
     * @param taskId      任务ID
     * @param actorIds    参与者ID列表
     * @param flowCreator 执行操作人员
     * @return true 成功 false 失败
     */
    boolean removeTaskActor(Long taskId, List<String> actorIds, FlowCreator flowCreator);

    default boolean removeTaskActor(Long taskId, String actorId, FlowCreator flowCreator) {
        return removeTaskActor(taskId, Collections.singletonList(actorId), flowCreator);
    }

    /**
     * 结束调用外部流程任务
     *
     * @param callProcessId  调用外部流程定义ID
     * @param callInstanceId 调用外部流程实例ID
     */
    void endCallProcessTask(Long callProcessId, Long callInstanceId);

    /**
     * 级联删除 flw_his_task, flw_his_task_actor, flw_task, flw_task_actor
     *
     * @param instanceIds 流程实例ID列表
     */
    boolean cascadeRemoveByInstanceIds(List<Long> instanceIds);
}
