package com.trade.admin.workflow.service;

import com.trade.admin.workflow.dto.*;
import com.trade.admin.workflow.domain.Project;
import com.trade.common.core.page.GridPage;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

/**
 * @Description:Flowable引擎Service接口 <p>
 * 任务办理人扩展：可单独设计一张表单任务办理人表用来存放各个表单任务办理人，由于部分任务节点存在一致性。<br>
 * 举例，任务A与任务B必须办理人一致，若任务A办理人变更，对应后续的任务B办理人同时进行变更（包括正在待办的任务B）.<br>
 * 该表的设计，需要考虑到流程实例的因素，因为一条业务流程实例开启，尽管业务类型一样，但流转过程中的各个任务处理人并非一样。<br>
 * 举例，同样是尽调流程，两条尽调业务数据，很大可能主体报告办理人是不同的。
 * </p>
 * @Author:wanxiangZhou
 * @E-mail:zhouyu@sunxung.cn
 * @Date:2018年6月13日 下午1:43:07
 */
public interface FlowableService {

    /**
     * 获取最新版本的流程定义 Query process definitions.
     *
     * @param search 查询条件
     * @return 最新版本的流程定义集合
     */
    GridPage<ProcessDefinitionEntityVo> findLatestProcdef(SearchProcessDefinition search);

    /**
     * 部署流程定义
     * <p>
     * 注意事项：要求流程定义的KEY必须与开启流程实例的业务实体类SimpleClassName的值保持一致，这是本项目中的设计规范，否则无法确保业务的正确性。
     * </p>
     *
     * @return 部署对象
     */
    Deployment deploy(DeployRequest deployRequest);

    /**
     * 查看流程定义图片
     *
     * @param response     响应资源
     * @param deploymentId 流程定义部署ID
     * @param resourceName 资源文件名称
     */
    void viewImg(HttpServletResponse response, String deploymentId, String resourceName);

    /**
     * 开启业务流程实例，新增业务处理日志
     *
     * @param entity        业务实体对象
     * @param procVariables 流程变量map
     * @param queryBusiness 业务查询信息，根据业务需求，拼接列表查询条件数据到流程业务KEY中
     * @param msgVariables  消息变量map
     * @param key           流程管理的key
     * @return 流程实例对象
     */
    ProcessInstance startProcessInstance(Project entity, Map<String, Object> procVariables, String queryBusiness,
                                         Map<String, Object> msgVariables, String key);

    /**
     * 分页查询待我处理（办理）的任务<br>
     * 说明：查询条件均包含到业务KEY中
     *
     * @param search               业务查询条件
     * @param processDefinitionKey 流程定义KEY，要求：必须与主业务实体类简单类名称一致。
     * @return 我的任务集合
     */
    List<Task> findMyPendingListPage(SearchBusinessProcessingTask search, String processDefinitionKey);

    /**
     * 查询待我处理（办理）的任务总数
     *
     * @param search               业务查询条件
     * @param processDefinitionKey 流程定义KEY，要求：必须与主业务实体类简单类名称一致。
     * @return 我的任务总数
     */
    long countMyPendingListPage(SearchBusinessProcessingTask search, String processDefinitionKey);

    /**
     * 查询待我处理（办理）的任务，满足特殊业务处理，如账后收放款计划信息。
     *
     * @param sourceBusinessId     源业务ID
     * @param processDefinitionKey 流程定义KEY，要求：必须与主业务实体类简单类名称一致。
     * @return 返回待我处理集合（一条业务并列节点同为一个人时，肯定多条）
     */
    List<Task> findMyPendingList(String sourceBusinessId, String processDefinitionKey);

    /**
     * 分页查询我已处理（办理）的任务<br>
     * 说明：查询条件均包含到业务KEY中
     *
     * @param search               业务查询条件
     * @param processDefinitionKey 流程定义KEY，要求：必须与主业务实体类简单类名称一致。
     * @return 我已办理的任务集合（历史任务）
     */
    List<HistoricTaskInstance> findMyCompletedListPage(SearchBusinessProcessingTask search,
                                                       String processDefinitionKey);

    /**
     * 查询我已处理（办理）的任务总数
     *
     * @param search               业务查询条件
     * @param processDefinitionKey 流程定义KEY，要求：必须与主业务实体类简单类名称一致。
     * @return 我已办理的任务集合（历史任务）总数
     */
    long countMyCompletedListPage(SearchBusinessProcessingTask search, String processDefinitionKey);

    /**
     * 获取业务对象数据
     *
     * @param processInstId 流程实例ID
     * @return 流程业务数据
     */
    Object getBusinessDataByProcessInst(String processInstId);

    /**
     * 根据任务ID获取正在执行的任务（ACT_RU_TASK）
     *
     * @param taskId 任务ID
     * @return
     */
    Task getByTaskQuery(String taskId);

    /**
     * 判断正在执行中的任务办理人归属
     *
     * @param taskId 任务ID
     * @return true 表示当前用户为此任务的执行人，false表示不是
     */
    boolean duplicateAssigneeByTaskQuery(String taskId);

    /**
     * 根据任务ID获取历史任务实例（包括正在执行和执行完成的任务）
     *
     * @param taskId 任务ID
     * @return 历史任务实例，Null表示不存在该任务
     */
    HistoricTaskInstance getHistoricByTaskId(String taskId);

    /**
     * 根据流程实例ID查询正在进行中的任务（ACT_RU_TASK）
     *
     * @param processInstId 流程实例
     * @return
     */
    List<Task> findRuntimeTaskByProcessInstId(String processInstId);

    /**
     * 获取进行中的流程实例（非已结束的历史流程实例）
     *
     * @param processInstId 流程实例ID
     * @return
     */
    ProcessInstance getRuntimeProcessInstById(String processInstId);

    /**
     * 获取历史的流程实例（包括进行中的流程实例）
     *
     * @param processInstId 流程实例ID
     * @return
     */
    HistoricProcessInstance getHistoricProcessInstById(String processInstId);

    /**
     * 获取具体业务所采用的流程实例（未结束的业务）
     *
     * @param processDefKey          流程定义KEY
     * @param processInstBusinessKey 流程实例业务KEY
     * @return
     */
    ProcessInstance getRuntimeProcessInstByBusinessKey(String processDefKey, String processInstBusinessKey);

    /**
     * 获取具体业务所采用的流程实例（正在进行的业务、已结束的业务）
     *
     * @param processDefKey          流程定义KEY
     * @param processInstBusinessKey 流程实例业务KEY
     * @return
     */
    HistoricProcessInstance getHistoricProcessInstByBusinessKey(String processDefKey, String processInstBusinessKey);

    /**
     * 分配任务，重新指定办理人
     *
     * @param assignableTask 任务
     * @param assignee       指定办理人ID
     * @return true表示分配成功，否则失败
     */
    Boolean assignManager(Task assignableTask, Long assignee);


    /**
     * 提交、办理任务，添加业务处理日志<br>
     * 注意：流程变量与系统待办消息变量分开，为了不增加额外的、无效的流程变量，相当于优化了遍历流程变量的时间
     *
     * @param taskId         用户任务ID
     * @param entity         业务对象
     * @param procVariables  流程变量，如若有下一个任务，指定办理人
     * @param result         此次业务结果，任务结果，判断流转方向
     * @param formBusinessId 表单业务ID
     * @param key            流程管理key
     * @return true表示操作成功，否则失败
     */
    Boolean completeMyTask(String taskId, Project entity, Map<String, Object> procVariables, String result,
                           Long formBusinessId, String key);

    /**
     * 任务拾取
     *
     * @param taskId   任务Id
     * @param userId   办理用户Id
     * @param roleKey 角色编码
     */
    void claimTask(String taskId, Long userId, String roleKey);

    /**
     * 任务拾取 多个角色都可以处理当前任务
     *
     * @param taskId    任务Id
     * @param userId    办理用户Id
     * @param roleKeys 角色编码
     */
    void claimTask(String taskId, Long userId, List<String> roleKeys);

    /**
     * 判断该task是否存在
     *
     * @param historicTaskId
     * @return
     */
    Boolean existTask(String historicTaskId);
}
