package com.sifang.modules.flowable.service;

import com.google.gson.Gson;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.sifang.modules.customer.constant.UserConstants;
import com.sifang.modules.flowable.constants.ItemConstants;
import com.sifang.modules.flowable.dao.ItemManageDao;
import com.sifang.modules.flowable.dao.ItemTaskDetailDao;
import com.sifang.modules.flowable.utils.FormUtils;
import com.sifang.modules.flowable.utils.TaskVo;
import com.sifang.modules.flowpath.dao.ExamineInfoDao;
import com.sifang.modules.sunshine.SystemSetting.dao.TraderDao;
import com.sifang.modules.sunshine.SystemSetting.entity.CrmTrader;
import com.sifang.modules.sys.common.UserUtils;
import com.sifang.modules.sys.common.entity.User;
import com.sifang.modules.sys.common.service.BaseService;
import com.sifang.modules.sys.common.utils.DateUtils;
import com.sifang.modules.sys.common.utils.StringUtil;
import com.sifang.modules.sys.util.CrmUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.flowable.engine.TaskService;
import org.springframework.transaction.annotation.Transactional;


import java.util.*;

@Service
public class ProcessFlowableService extends BaseService {

    @Autowired
    ExamineInfoDao examineInfoDao;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    TaskService taskService;

    @Autowired
    HistoryService historyService;

    @Autowired
    RepositoryService repositoryService;

    @Autowired
    private ItemManageDao itemManageDao;

    @Autowired
    private ItemTaskDetailDao itemTaskDetailDao;

    @Autowired
    private TraderDao traderDao;


    /**
     * 启动流程
     * @param user  用户
     * @param applicationId   申请的id
     * @param processDef       流程设置
     * @param formId           表单的id
     */
    @Transactional(rollbackFor = Exception.class)
    public String startProcessFlowable(User user, String applicationId, Record processDef, String formId,  Date submitTime,String UserName,String content,String processInsName,String traderId){
        logger.info(" >>>>>>>>>>>>启动流程 startProcessFlowable  {applicationId}:{},formId:{};" ,applicationId,formId);
        CrmTrader trader=traderDao.get(traderId);
        String province="";
        String city="";
        if(trader!=null){
            province=trader.getProvince();
            city=trader.getCity();
        }
        Map<String,Object> map=new HashMap<>();
        map.put("applicationId",applicationId);
        map.put("formId",formId);
        map.put("reject","1");
        String processDefId= processDef.getStr("id");
        List<Record> auditItems=FormUtils.getDefAuditItems(processDefId);
        Random rand = new Random();
        String oneAuditUseId="";
        for(Record r:auditItems){
            List<String> emps=new ArrayList<>();
            String userId="";
            if("1".equals(r.getStr("audit_type"))){  // 1平台角色 2 平台员工
                //根据角色，获取角色员工(要根据员工的数据权限分配)
                emps=FormUtils.getPlateEmpUserIdByRoleId(r.getStr("role_id"),province,city,traderId);
            }else{
                String str=r.getStr("emp_user_id");
                //获取符合数据权限的员工id
                emps=FormUtils.getFitUserEmpId(str,province,city,traderId);
            }
            if(emps==null || emps.size()==0){
                throw new RuntimeException(r.getStr("item_name")+" 该节点没有符合审批设置的员工审批，不能启动流程！");
            }
            if(StringUtil.equalsAny(r.getStr("audit_method"),"1","2","3")){  //1 或签 2会签  3 依次审批
                map.put("assigneeList"+r.get("sort"),emps);
            }else{   //任意人
                int i=rand.nextInt(emps.size());
                userId=emps.get(i);
                map.put("assignee"+r.get("sort"),userId);
            }
            if(r.getInt("sort")==1){
                if(StringUtil.isNotBlank(userId)){
                    oneAuditUseId=userId;
                }else {
                    oneAuditUseId=String.join(",",emps);
                }
            }
        }
        processDef.set("oneAuditUseId",oneAuditUseId);
        logger.info(">>>>>>>>>>>>startProcessFlowable  map:{}",new Gson().toJson(map));
        ProcessInstance processInstance=runtimeService.startProcessInstanceByKey("Process_"+processDefId,map);
        logger.info( " >>>> 流程提交成功.流程Id为：" + processInstance.getId());
        String str="";
        if(UserConstants.TYPE_TRADER.equals(user.getUserType()) || UserConstants.TYPE_JXS_EMP.equals(user.getUserType())){
            str=UserUtils.findName(user) +"，提交表单"+(StringUtil.isNotBlank(content)?"；"+content:"");
        }else{
            str=user.getDepartmentName()+" "+" "+UserName+"，提交表单"+(StringUtil.isNotBlank(content)?"；"+content:"");
        }
        //保存流程的过程信息
        examineInfoDao.saveExamineInfo(applicationId,str,submitTime,UserName,formId);
        logger.info(" >>>>>>>>>> 流程启动成功 startProcessFlowable  service  ");

        itemManageDao.addItem(formId,applicationId,processInstance.getId(),processInsName,submitTime,UserName,traderId);
        return processInstance.getId();
    }


    @Transactional(rollbackFor = Exception.class)
    public String startProcessFlowable2(User user, String applicationId, Record processDef, String formId,  Date submitTime,String UserName,String content,String processInsName,String province,String city){
        logger.info(" >>>>>>>>>>>>启动流程 startProcessFlowable  {applicationId}:{},formId:{};" ,applicationId,formId);
        Map<String,Object> map=new HashMap<>();
        map.put("applicationId",applicationId);
        map.put("formId",formId);
        map.put("reject","1");
        String processDefId= processDef.getStr("id");
        List<Record> auditItems=FormUtils.getDefAuditItems(processDefId);
        Random rand = new Random();
        String oneAuditUseId="";
        for(Record r:auditItems){
            List<String> emps=new ArrayList<>();
            String userId="";
            if("1".equals(r.getStr("audit_type"))){  // 1平台角色 2 平台员工
                //根据角色，获取角色员工(要根据员工的数据权限分配)
                emps=FormUtils.getPlateEmpUserIdByRoleId(r.getStr("role_id"),province,city,"");
            }else{
                String str=r.getStr("emp_user_id");
                //获取符合数据权限的员工id
                emps=FormUtils.getFitUserEmpId(str,province,city,"");
            }
            if(emps==null || emps.size()==0){
                throw new RuntimeException(r.getStr("item_name")+" 该节点没有符合审批设置的员工审批，不能启动流程！");
            }
            if(StringUtil.equalsAny(r.getStr("audit_method"),"1","2","3")){  //1 或签 2会签  3 依次审批
                map.put("assigneeList"+r.get("sort"),emps);
            }else{   //任意人
                int i=rand.nextInt(emps.size());
                userId=emps.get(i);
                map.put("assignee"+r.get("sort"),userId);
            }
            if(r.getInt("sort")==1){
                if(StringUtil.isNotBlank(userId)){
                    oneAuditUseId=userId;
                }else {
                    oneAuditUseId=String.join(",",emps);
                }
            }
        }
        processDef.set("oneAuditUseId",oneAuditUseId);
        logger.info(">>>>>>>>>>>>startProcessFlowable  map:{}",new Gson().toJson(map));
        ProcessInstance processInstance=runtimeService.startProcessInstanceByKey("Process_"+processDefId,map);
        logger.info( " >>>> 流程提交成功.流程Id为：" + processInstance.getId());
        String str="";
        if(UserConstants.TYPE_TRADER.equals(user.getUserType()) || UserConstants.TYPE_JXS_EMP.equals(user.getUserType())){
            str=UserUtils.findName(user) +"，提交表单"+(StringUtil.isNotBlank(content)?"；"+content:"");
        }else{
            str=user.getDepartmentName()+" "+" "+UserName+"，提交表单"+(StringUtil.isNotBlank(content)?"；"+content:"");
        }
        //保存流程的过程信息
        examineInfoDao.saveExamineInfo(applicationId,str,submitTime,UserName,formId);
        logger.info(" >>>>>>>>>> 流程启动成功 startProcessFlowable  service  ");

        itemManageDao.addItem(formId,applicationId,processInstance.getId(),processInsName,submitTime,UserName);
        return processInstance.getId();
    }

    /**
     * 流程审批通过
     * @param taskId   任务的id
     * @param content   审核备注
     * @param applicationId  当前申请的id
     * @param currentUser     当前用户
     */
    public void approveTask(String taskId, String content, String applicationId, User currentUser,Date submitTime,String formId,String processDefId){
        logger.info(">>>>>>>>>>>>>>>>>applicationId:{},task:{}",applicationId,taskId);
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new RuntimeException("流程不存在,请刷新页面！");
        }
        String UserName = currentUser.getUserName();
        taskService.claim(taskId,currentUser.getId());  //领取任务
        logger.info(UserName+" >>>>>> 审批流程通过 {task} :" +task.getId());
        taskService.setOwner(taskId,UserName);
        String type="";
        if (!"编辑后提交".equals(content)) {
            type="，同意 ";
        }
        String str = currentUser.getDepartmentName() + " "  + UserName + " " + type + (StringUtil.isNotBlank(content) ? "；" + content : "");
        //保存流程的过程信息
        examineInfoDao.saveExamineInfo(applicationId,str,submitTime,UserName,formId);
        Map<String, Object> map =new HashMap<>();
        map.put("approve", true);
        map.put("reject","1");
        taskService.complete(taskId,map);
    }

    /**
     * 流程审批通过
     * @param content   审核备注
     * @param applicationId  当前申请的id
     * @param currentUser     当前用户
     */
    @Transactional(rollbackFor = Exception.class)
    public void approveTask2(Task task, String content, String applicationId, User currentUser,String formId){
        Date date=new Date();
        logger.info(">>>>>>>>>>>>>>>>>applicationId:{},task:{}",applicationId,task.getId());
        if (task == null) {
            throw new RuntimeException("流程不存在,请刷新页面！");
        }
        String UserName = currentUser.getUserName();
        String type="；";
        if (!"编辑后提交".equals(content)) {
            type="，同意 ；";
        }
        String str = currentUser.getDepartmentName() + " " + UserName + type+ (StringUtil.isNotBlank(content) ?content : "");
        //保存流程的过程信息
        examineInfoDao.saveExamineInfo(applicationId,str,date,UserName,formId);

        itemTaskDetailDao.addItemTaskDetail(formId,applicationId,task.getProcessInstanceId(),task.getId(), ItemConstants.RESULT_OK,date,currentUser,task.getCreateTime(),task.getName());

        taskService.claim(task.getId(),currentUser.getId());  //领取任务
        logger.info(UserName+" >>>>>> 审批流程通过 {task} :" +task.getId());
        taskService.setOwner(task.getId(),UserName);
        Map<String, Object> map =new HashMap<>();
        map.put("approve", true);
        map.put("reject","1");
        taskService.complete(task.getId(),map);
    }



    /**
     * 驳回一个流程
     * @param taskId    任务的id
     * @param content   审核备注
     * @param applicationId  当前申请的id
     * @param currentUser    当前用户
     */
    @Transactional(rollbackFor = Exception.class)
    public void rejectTask(String taskId, String content, String applicationId, User currentUser,String formId){
        logger.info(">>>>>>>>>>>>>>>>rejectTask  taskId:{},applicationId:{}",taskId,applicationId);
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new RuntimeException("流程不存在");
        }
        String UserName = currentUser.getUserName();
        taskService.claim(taskId,currentUser.getId());  //领取任务
        logger.info(" >>>>>> 审批流程驳回 {task} :" +task.toString());
        String userId=(String)taskService.getVariable(taskId,"userId");
        taskService.setOwner(taskId,UserName);
        Date date=new Date();
       //保存流程的过程信息
        String roleStr=task.getName();
        if(roleStr.length()>2){
            roleStr=roleStr.substring(1,roleStr.length()-2);
        }
        String str=currentUser.getDepartmentName()+" "+roleStr+" "+UserName+"，驳回"+(StringUtil.isNotBlank(content)?"；"+content:"");
        examineInfoDao.saveExamineInfo(applicationId,str,date,UserName,formId);
        Map<String, Object> map = new HashMap<>();
        map.put("approve",false);
        map.put("reject","2");
        map.put("assigneeUserId",userId);
        taskService.complete(taskId, map);

        itemTaskDetailDao.addItemTaskDetail(formId,applicationId,task.getProcessInstanceId(),taskId,ItemConstants.RESULT_BACK,date,currentUser,task.getCreateTime(),task.getName());
    }

    /**
     * 驳回一个流程
     * @param content   审核备注
     * @param applicationId  当前申请的id
     * @param currentUser    当前用户
     */
    @Transactional(rollbackFor = Exception.class)
    public void rejectTask2(Task task, String content, String applicationId, User currentUser,String formId,String createBy){
        logger.info(">>>>>>>>>>>>>>>>rejectTask  taskId:{},applicationId:{}",task.getId(),applicationId);
        String UserName = currentUser.getUserName();

        Date date=new Date();
        String str=currentUser.getDepartmentName()+" "+UserName+"，驳回"+(StringUtil.isNotBlank(content)?"；"+content:"");
        examineInfoDao.saveExamineInfo(applicationId,str,date,UserName,formId);

        itemTaskDetailDao.addItemTaskDetail(formId,applicationId,task.getProcessInstanceId(),task.getId(),ItemConstants.RESULT_BACK,date,currentUser,task.getCreateTime(),task.getName());
        taskService.claim(task.getId(),currentUser.getId());  //领取任务
        logger.info(" >>>>>> 审批流程驳回 {task} :" +task.toString());
        Map<String, Object> map = new HashMap<>();
        map.put("approve",false);
        map.put("reject","2");
        map.put("assigneeUserId",createBy);
        taskService.complete(task.getId(), map);
    }


    //删除申请
    @Transactional(rollbackFor = Exception.class)
    public void deleteApplication(String applicationId,String processInstanceId,String UserName,String status,String formId){
        logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>删除申请  deleteApplication applicationId:{};processInstanceId:{}",applicationId,processInstanceId);
        //删除任务
        if("2".equals(status) || "3".equals(status)){ //处理中的申请  才删除流程
            List<Task> taskList=taskService.createTaskQuery().processInstanceId(processInstanceId).list();
            if(taskList.size()>0){
                logger.info(">>>>>>>>>>>>> 开始删除任务  {} ",processInstanceId);
                //删除任务
                runtimeService.deleteProcessInstance(processInstanceId,"删除任务！");
                logger.info(">>>>>>>>>>>  删除任务成功  ");
            }
        }
        Db.update(" delete from act_ru_task where PROC_INST_ID_=?  ",processInstanceId);
        //保存流程的过程信息
        examineInfoDao.saveExamineInfo(applicationId,UserName +" (删除申请)",new Date(),UserName,formId);
    }

    //删除申请
    @Transactional(rollbackFor = Exception.class)
    public void deleteApplication2(String applicationId,String processInstanceId,String UserName,String status,String formId,String content){
        logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>删除申请  deleteApplication applicationId:{};processInstanceId:{}",applicationId,processInstanceId);
        //删除任务
        if("2".equals(status) || "3".equals(status)){ //处理中的申请  才删除流程
            List<Task> taskList=taskService.createTaskQuery().processInstanceId(processInstanceId).list();
            if(taskList.size()>0){
                logger.info(">>>>>>>>>>>>> 开始删除任务  {} ",processInstanceId);
                //删除任务
                runtimeService.deleteProcessInstance(processInstanceId,"删除任务！");
                logger.info(">>>>>>>>>>>  删除任务成功  ");
            }
        }
        Db.update(" delete from act_ru_task where PROC_INST_ID_=?  ",processInstanceId);
        //保存流程的过程信息
        examineInfoDao.saveExamineInfo(applicationId,UserName +content,new Date(),UserName,formId);
    }


    public List getBpmnModel(String processInstanceId,String status){

        //当前节点
        List<TaskVo> lists = findHistoryTask(processInstanceId);//已经处理过的任务
       /* if("2".equals(status) || "3".equals(status)){
            return lists;
        }*/
        if("3".equals(status)){
            return lists;
        }
        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();  //当前任务
        if(task == null){
            return lists;
        }
        List<TaskVo> lista =nextFlowNode(processInstanceId,task);    //整个流程任务
        if(task != null){
            if("审核不通过".equals(task.getName())){
                return lista;
            }
        }
        List<TaskVo> hisList = new ArrayList<>();
        for(TaskVo vo:lists){
            if(task.getName().equals(vo.getTaskName())){
                break;
            }
            hisList.add(vo);
        }

        for(TaskVo ta:lista){//流程节点
            for(TaskVo vo:hisList){ //已办节点
                if(ta.getTaskName().equals(vo.getTaskName())){
                    ta.setApproveUserName(vo.getApproveUserName());
                    ta.setStatus(vo.getStatus());
                }
                if(ta.getTaskName().equals(task.getName())){
                    break;
                }

            }
        }
        return lista;
    }

    /**
     * 查询历史任务
     *
     * @param processInstanceId 指定流程实例ID
     */
    public List<TaskVo> findHistoryTask(String processInstanceId) {
        List<HistoricTaskInstance> list = historyService//与历史数据（历史表）相关的Service
                .createHistoricTaskInstanceQuery()//创建历史任务实例查询
                .processInstanceId(processInstanceId)
                .orderByHistoricTaskInstanceStartTime().asc()
                .list();
        List<TaskVo> listta = new ArrayList<>();
        if (list != null && list.size() > 0) {
            int sort = 12;
            for (HistoricTaskInstance hti : list) {
                    TaskVo vo = new TaskVo();
                    vo.setStatus("3");
                    vo.setTaskId(hti.getId());
                    vo.setFormKey(hti.getFormKey());
                    vo.setTaskName(hti.getName());
                    vo.setApproveUserName(hti.getOwner());
                    vo.setStartTime(DateUtils.formatDateTime(hti.getStartTime()));
                    vo.setSort(sort);
                    listta.add(vo);
                    sort = sort + 1;

                System.out.println(hti.getId() + "    " + hti.getName() + "    " + hti.getProcessInstanceId() + "   " + hti.getStartTime() + "   " + hti.getEndTime() + "   " + hti.getDurationInMillis());
                System.out.println("################################   " + hti.getAssignee());
            }
        }
        return listta;
    }

    /**
     * 获取任务节点
     *
     * @param processInstanceId
     */
    public List<TaskVo> nextFlowNode(String processInstanceId, Task task) {

        List<TaskVo> list = new ArrayList<>();
        //获取流程发布Id信息
        String definitionId = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult().getProcessDefinitionId();
         //获取所有节点信息
        List<Process> processes = repositoryService.getBpmnModel(definitionId).getProcesses();
        System.out.println("processes size:" + processes.size());
        for (Process process : processes) {
            Collection<FlowElement> flowElements = process.getFlowElements();
            if (CollectionUtils.isNotEmpty(flowElements)) {
                int sort = 15;
                for (FlowElement flowElement : flowElements) {
                    if (flowElement instanceof UserTask) {

                        TaskVo vo = new TaskVo();
                        System.out.println("UserTask：" + flowElement.getName() + "  " + ((UserTask) flowElement).getCandidateGroups());
                        //业务操作
                        UserTask userTask = (UserTask) flowElement;
                        List<String> roles = userTask.getCandidateGroups();
                        if (roles.size() < 1) {
                            continue;
                        }
                        String roleId = roles.get(0);
                        String userLlist = Db.queryStr("SELECT GROUP_CONCAT(e.name) FROM `crm_platform_employee` e " +
                                "LEFT JOIN `crm_platform_employee_role_rel` r ON e.id=r.employee_id " +
                                "WHERE FIND_IN_SET(?,r.role_ids) AND e.status='0' ", roleId);
                        if (task.getName().equals(flowElement.getName())) {
                            vo.setStatus("1");
                            vo.setTaskId(task.getId());
                        } else {
                            vo.setStatus("2");
                            vo.setTaskId(userTask.getId());
                        }
                        vo.setSort(sort);
                        vo.setFormKey(userTask.getFormKey());
                        vo.setTaskName(flowElement.getName());
                        if (StringUtil.isBlank(userLlist)) {
                            vo.setApproveUserName("无");
                        } else {
                            vo.setApproveUserName(userLlist);
                        }

                        list.add(vo);
                        sort = sort - 1;
                    }
                    if (flowElement instanceof StartEvent) {
                        System.out.println("SubProcess " + flowElement.getName());
                    }
                    if (flowElement instanceof EndEvent) {
                        System.out.println("EndEvent " + flowElement.getName());
                    }

                }
            }

        }
        return list;
    }

    /**
     *  抄送的任务   阅读
     *  */
    @Transactional(rollbackFor = Exception.class)
    public void readApplication(String processInstanceId,String formId,String applicationId,User user){
        //根据申请id 和 formId 找到抄送任务id
        List<Record> tasks=Db.find(" SELECT ID_,CREATE_TIME_ FROM `act_ru_task` where PARENT_TASK_ID_=? and CATEGORY_='3' and ASSIGNEE_=? and FORM_KEY_=? ",processInstanceId,user.getId(),formId);
        for(Record task:tasks){
            String taskId=task.getStr("ID_");
            if(StringUtil.isNotBlank(taskId)){
                itemTaskDetailDao.addItemTaskDetail(formId,applicationId,processInstanceId,taskId,ItemConstants.RESULT_LOOK,new Date(),user,task.getDate("CREATE_TIME_"),"抄送");
                taskService.claim(taskId,user.getId());  //领取任务
                taskService.complete(taskId);
            }
        }
    }
}
