package com.artfess.bpm.persistence.manager.impl;

import com.artfess.base.feign.ApplicationFeignService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.artfess.base.conf.SaaSConfig;
import com.artfess.base.context.BaseContext;

import com.artfess.base.feign.UCFeignService;
import com.artfess.base.groovy.GroovyScriptEngine;
import com.artfess.base.handler.MultiTenantHandler;
import com.artfess.base.handler.MultiTenantIgnoreResult;
import com.artfess.base.jms.JmsActor;
import com.artfess.base.jms.Notice;
import com.artfess.base.jms.NoticeMessageType;
import com.artfess.base.manager.impl.BaseManagerImpl;
import com.artfess.base.model.CommonResult;
import com.artfess.base.template.impl.FreeMarkerEngine;
import com.artfess.base.util.*;
import com.artfess.base.util.time.DateFormatUtil;
import com.artfess.base.util.time.DateUtil;
import com.artfess.base.util.time.TimeUtil;
import com.artfess.bpm.api.cmd.ActionCmd;
import com.artfess.bpm.api.constant.BpmConstants;
import com.artfess.bpm.api.constant.TemplateConstants;
import com.artfess.bpm.api.context.ContextThreadUtil;
import com.artfess.bpm.api.helper.identity.BpmIdentityExtractService;
import com.artfess.bpm.api.model.identity.BpmIdentity;
import com.artfess.bpm.api.model.process.inst.BpmProcessInstance;
import com.artfess.bpm.api.service.BoDataService;
import com.artfess.bpm.api.service.BpmIdentityService;
import com.artfess.bpm.api.service.BpmInstService;
import com.artfess.bpm.api.service.BpmTaskActionService;
import com.artfess.bpm.engine.task.cmd.DefaultTaskFinishCmd;
import com.artfess.bpm.natapi.task.NatTaskService;
import com.artfess.bpm.persistence.dao.BpmTaskReminderDao;
import com.artfess.bpm.persistence.manager.*;
import com.artfess.bpm.persistence.model.*;
import com.artfess.bpm.plugin.task.reminders.def.Reminder;
import com.artfess.bpm.util.MessageUtil;
import com.artfess.bpm.util.PortalDataUtil;
import com.artfess.uc.api.impl.model.UserFacade;
import com.artfess.uc.api.impl.util.ContextUtil;
import com.artfess.uc.api.model.IUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

/**
 * 
 * <pre> 
 * 描述：任务催办 处理实现类
 * 构建组：x5-bpmx-platform
 * 作者:miaojf
 * 邮箱:miaojf@jee-soft.cn
 * 日期:2016-07-28 16:52:36
 * 版权：广州宏天软件有限公司
 * </pre>
 */
@Service("bpmTaskReminderManager")
public class BpmTaskReminderManagerImpl extends BaseManagerImpl<BpmTaskReminderDao, BpmTaskReminder> implements BpmTaskReminderManager{

	@Resource
	BpmTaskManager bpmTaskManager;
	@Resource
	BpmIdentityService bpmIdentityService;
	@Resource
	BpmIdentityExtractService bpmIdentityExtractService;
	@Resource
	BpmReminderHistoryManager bpmReminderHistoryManager;
	@Resource
	NatTaskService natTaskService;
    @Resource
    BpmInstService bpmInstService;
    @Resource
    BoDataService boDataService;
    @Resource
    GroovyScriptEngine groovyScriptEngine;
    @Resource
    UCFeignService ucFeignService;
    @Resource
    BaseContext baseContext;
    @Autowired
	SaaSConfig saaSConfig;
    @Autowired
    BpmExeStackRelationManager bpmExeStackRelationManager;
    @Autowired
    BpmExeStackExecutorManager bpmExeStackExecutorManager;
    @Autowired
    BpmCheckOpinionManager bpmCheckOpinionManager;
    
	@Override
    @Transactional
	public void deleteByTaskId(String taskId) {
		baseMapper.deleteByTaskId(taskId);		
	}
	
	@Override
	public List<BpmTaskReminder> getTriggerReminders() {
		String currentTime = TimeUtil.getCurrentTime();
		String timeSql = " trigger_date_ <='"+currentTime+"'";
		String dbType = SQLUtil.getDbType();
		if("oracle".equals(dbType)) {
			timeSql = " trigger_date_ <= to_date('"+currentTime+"','yyyy-mm-dd hh24:mi:ss') ";
		}
		List<BpmTaskReminder> list = new ArrayList<BpmTaskReminder>();
		try(MultiTenantIgnoreResult setThreadLocalIgnore = MultiTenantHandler.setThreadLocalIgnore()){
			list = baseMapper.getTriggerReminders(timeSql);
		} catch (Exception e) {
			System.out.println("获取催办任务失败："+e.getMessage());
		}
		return list;
	}
	
	@Override
	public void executeTaskReminderJob() throws Exception {
		//获取当前时间要出发的所有催办项
		List<BpmTaskReminder> reminderList = this.getTriggerReminders();
		
		for (BpmTaskReminder reminder : reminderList) {
			try {
				this.doTaskReminderJob(reminder);
			} catch (Exception e) {
				System.out.println("催办执行失败："+e.getMessage());
			}
			
		}
	}
	
	@Transactional
	public void doTaskReminderJob(BpmTaskReminder reminder) throws Exception {
		if(saaSConfig.isEnable()){
			baseContext.setTempTenantId(reminder.getTenantId());
		}
		DefaultBpmTask task = bpmTaskManager.get(reminder.getTaskId());
		if(BeanUtils.isEmpty(task)){
			this.remove(reminder.getId());
			return;
		}
		//根据催办任务重新设置当前用户
		this.setCurrentUser(task);
		task.setIdentityList(bpmIdentityService.searchByNode(task.getProcInstId(),task.getNodeId()));

		BpmProcessInstance inst = bpmInstService.getProcessInstance(task.getProcInstId());
		//当流程被挂起时不进行催办操作
		if (inst.getIsForbidden()==BpmProcessInstance.FORBIDDEN_YES){
			return;
        }
		
		// 如果执行到期	动作任务被处理。则继续
		boolean taskComplate = executeDueAction(reminder,task);
		
		//发送催办
		if(reminder.getIsSendMsg()==1) sendMsg(reminder,task);
		
		if(taskComplate) return;
		
		//处理预警
		handleWarning(reminder,task);
		
		// 如果预警为无动作，无催办，无预警。则删除改催办
		if(BpmTaskReminder.TASK_DUE_ACTION_NO_ACTION.equals(reminder.getDueAction())
				&& (reminder.getIsSendMsg()==0 || reminder.getMsgCount()<=0)
				&& StringUtil.isEmpty(reminder.getWarningset())){
			this.remove(reminder.getId());
			return;
		}
		// 更新催办
		this.update(reminder);
	}
	
	/**
	 * 设置线程变量中的当前用户（由于涉及到人员策略中使用当前用户，所以设置当前用户时不能直接设置为admin，需要找到对应任务的上一节点执行人）
	 * @throws IOException 
	 */
	private void setCurrentUser(DefaultBpmTask task) throws IOException {
		IUser user = null;
		List<BpmExeStackRelation> stackRelations = bpmExeStackRelationManager.getByToNodeId(task.getProcInstId(), task.getNodeId());
		if(BeanUtils.isNotEmpty(stackRelations)) {
			List<BpmExeStackExecutor> executors = bpmExeStackExecutorManager.getByStackId(stackRelations.get(0).getFromStackId());
			if(BeanUtils.isNotEmpty(executors) && executors.size()==1) {
				user = this.getUser(executors.get(0).getAssigneeId(), null);
			}else {
				String dbType = SQLUtil.getDbType();
				DefaultBpmCheckOpinion opinion = bpmCheckOpinionManager.getBpmOpinion(task.getProcInstId(), stackRelations.get(0).getFromNodeId(), dbType);
				if(BeanUtils.isNotEmpty(opinion) && StringUtil.isNotEmpty(opinion.getTaskId())) {
					BpmExeStackExecutor executor = bpmExeStackExecutorManager.getByTaskId(opinion.getTaskId());
					if(BeanUtils.isNotEmpty(executor)) {
						user = this.getUser(executor.getAssigneeId(), null);
					}
				}
			}
		}else {
			user = this.getUser(null, "admin");
		}
		if(BeanUtils.isNotEmpty(user)) {
			ContextUtil.setCurrentUserInJob(user);
		}
	}
	
	private IUser getUser(String id,String account) throws IOException {
		if(StringUtil.isNotEmpty(id)) {
			CommonResult<JsonNode> node = ucFeignService.getUserById(id);
			if(node.getState()) {
				UserFacade user = JsonUtil.toBean(node.getValue(), UserFacade.class);
				return user;
			}
		}else if(StringUtil.isNotEmpty(account)) {
			JsonNode node = ucFeignService.getUser(account, "");
			if(BeanUtils.isNotEmpty(node)) {
				UserFacade user = JsonUtil.toBean(node, UserFacade.class);
				return user;
			}
		}
		return null;
	}

    @Override
    public CommonResult<String> modifyTaskReminder(String instId) throws Exception{
        BpmProcessInstance bpmProcessInstance = bpmInstService.getProcessInstance(instId);
        List<ObjectNode> boDatas = boDataService.getDataByInst(bpmProcessInstance);
        Map<String,Object> map = boDatas.stream().collect(Collectors.toMap(item -> {
        	if(item.hasNonNull("boDefAlias")){
        		return item.get("boDefAlias").asText();
        	}else {
        		return item.get("boDef").get("alias").asText();
        	}
        },item -> item.get("data")));
        List<DefaultBpmTask> tasks = bpmTaskManager.getByInstId(instId);
        tasks.forEach(task -> {
            QueryWrapper wrapper = new QueryWrapper();
            wrapper.eq("task_id_", task.getId());
            List<BpmTaskReminder> reminders = list(wrapper);
            reminders.forEach(reminder -> {
                try {
                    executeScript(reminder, map);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        });
        return new CommonResult<>(true, "修改成功");
    }

    @Override
    public void executeScript(BpmTaskReminder reminder,Map<String,Object> map) throws Exception{
        if (StringUtil.isNotEmpty(reminder.getTypeScript())){
            JsonNode type = (JsonNode) groovyScriptEngine.executeObject(reminder.getTypeScript(),map);
            LocalDateTime dueDate = reminder.getDueDate() ,msgBeginDate = reminder.getMsgSendDate();
            int dueTime = 0,relTime = 0;
            if (StringUtil.isNotEmpty(reminder.getDurationScript())){
                JsonNode node = (JsonNode) groovyScriptEngine.executeObject(reminder.getDurationScript(),map);
                if (BeanUtils.isNotEmpty(node)){
                    dueTime = node.asInt();
                }
            }
            if(StringUtil.isNotEmpty(reminder.getRelTimeScript())){
                JsonNode node = (JsonNode) groovyScriptEngine.executeObject(reminder.getRelTimeScript(),map);
                if (BeanUtils.isNotEmpty(node)){
                    relTime = node.asInt();
                }
            }
            if (Reminder.TASK_TIME_TYPE_CALTIME.equals(type.asText())){ //自然日
                dueDate = TimeUtil.getLocalDateTimeByMills(TimeUtil.getNextTime(TimeUtil.MINUTE, dueTime,TimeUtil.getTimeMillis(reminder.getRelDate())));
                msgBeginDate = TimeUtil.getLocalDateTimeByMills(TimeUtil.getNextTime(TimeUtil.MINUTE, relTime,TimeUtil.getTimeMillis(reminder.getRelDate())));
            }else{ //工作日
                long sendTime = DateUtil.getCurrentTimeInMillis();
                long msgSendTime = DateUtil.getCurrentTimeInMillis();
                if (StringUtil.isNotEmpty(reminder.getSendUserId())){
                    sendTime = ucFeignService.computeSendDate(reminder.getSendUserId(),dueTime*60);
                }
                dueDate = LocalDateTime.ofEpochSecond(sendTime/1000,0, ZoneOffset.ofHours(8));
                msgSendTime = ucFeignService.computeSendDate(reminder.getId(),relTime*60);
                msgBeginDate = LocalDateTime.ofEpochSecond(msgSendTime/1000,0, ZoneOffset.ofHours(8));
            }

            reminder.setDueDate(dueDate);
            reminder.setMsgSendDate(msgBeginDate);
            if(msgBeginDate.isBefore(dueDate))
                reminder.setTriggerDate(msgBeginDate);
            update(reminder);
        }else {
            throw new RuntimeException("未设置脚本获取日期类型");
        }
    }

    @Override
    public void forbiddenTaskReminder(String instId) {
        List<DefaultBpmTask> tasks = bpmTaskManager.getByInstId(instId);
        List<String> taskIds = tasks.stream().map(DefaultBpmTask::getId).collect(Collectors.toList());
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.in("task_id_", taskIds);
        List<BpmTaskReminder> reminders = list(wrapper);

        reminders.forEach(reminder -> {
            long duration = 0, sendDuration = 0;
            if (Reminder.TASK_TIME_TYPE_CALTIME.equals(reminder.getDateType())) {
                duration = TimeUtil.getTimeMillis(reminder.getTriggerDate()) - DateUtil.getCurrentTimeInMillis();
                if (TimeUtil.getTimeMillis(reminder.getMsgSendDate()) - DateUtil.getCurrentTimeInMillis()>0)
                    sendDuration = TimeUtil.getTimeMillis(reminder.getMsgSendDate()) - DateUtil.getCurrentTimeInMillis();
            }else {
                ObjectNode param = JsonUtil.getMapper().createObjectNode();
                param.put("startDate", DateUtil.getCurrentTime());
                param.put("endDate", DateFormatUtil.format(reminder.getTriggerDate(), "yyyy-MM-dd HH:mm:ss"));
                try {
                    duration = ucFeignService.computeDuration(reminder.getSendUserId(), param);
                    param.put("endDate", DateFormatUtil.format(reminder.getMsgSendDate(), "yyyy-MM-dd HH:mm:ss"));
                    sendDuration = ucFeignService.computeDuration(reminder.getSendUserId(), param);
                } catch (Exception e) {}
            }
            reminder.setDuration(duration);
            reminder.setSendDuration(sendDuration);
            reminder.setTriggerDate(null);
            update(reminder);
        });

    }

    @Override
    public void allowTaskReminder(String instId) {
        List<DefaultBpmTask> tasks = bpmTaskManager.getByInstId(instId);
        List<String> taskIds = tasks.stream().map(DefaultBpmTask::getId).collect(Collectors.toList());
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.in("task_id_", taskIds);
        List<BpmTaskReminder> reminders = list(wrapper);

        reminders.forEach(reminder -> {
            LocalDateTime dueDate, msgBeginDate = null;
            if (Reminder.TASK_TIME_TYPE_CALTIME.equals(reminder.getDateType())) {
                //催办过期时间
                try {
                    dueDate = TimeUtil.getLocalDateTimeByMills(TimeUtil.getNextTime(TimeUtil.SECOND, reminder.getDuration().intValue()/1000, TimeUtil.getTimeMillis(LocalDateTime.now())));
                    //如果发送催办消息
                    if(reminder.getIsSendMsg()==1){
                        msgBeginDate = TimeUtil.getLocalDateTimeByMills(TimeUtil.getNextTime(TimeUtil.SECOND, reminder.getSendDuration().intValue()/1000, TimeUtil.getTimeMillis(LocalDateTime.now())));
                    }
                    reminder.setDueDate(dueDate);
                    reminder.setTriggerDate(dueDate);
                    reminder.setMsgSendDate(msgBeginDate);

                    update(reminder);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }else {
                Long sendTime, msgSendTime = null;
                try {
                    sendTime = ucFeignService.computeSendDate(reminder.getSendUserId(),reminder.getDuration()/1000/60);
                    dueDate = TimeUtil.getLocalDateTimeByMills(sendTime);

                    if (reminder.getIsSendMsg()==1){
                        msgSendTime = ucFeignService.computeSendDate(reminder.getSendUserId(), reminder.getSendDuration()/1000/60);
                        msgBeginDate = TimeUtil.getLocalDateTimeByMills(msgSendTime);
                    }

                    reminder.setDueDate(dueDate);
                    reminder.setTriggerDate(dueDate);
                    reminder.setMsgSendDate(msgBeginDate);

                    update(reminder);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    // 处理预警
    @Transactional
    private void handleWarning(BpmTaskReminder reminder, DefaultBpmTask task) throws IOException {
        if(StringUtil.isEmpty(reminder.getWarningset())) return;
        ArrayNode newWarningSet = JsonUtil.getMapper().createArrayNode();
        ArrayNode array = (ArrayNode) JsonUtil.toJsonNode(reminder.getWarningset());
        for (int i = 0; i < array.size(); i++) {
            ObjectNode warn =(ObjectNode) array.get(i);
            LocalDateTime warningDate = TimeUtil.convertString(warn.get("warnDate").asText());
            //处理预警
            if(warningDate.isBefore(LocalDateTime.now())){
                task.setPriority(warn.get("level").asLong());
                bpmTaskManager.updateTaskPriority(task.getId(),warn.get("level").asLong());
                createReminderHistory(reminder, "Warning", warn.get("warnName").asText(),task);
            }else{
                //如果未来要处理的待办早于 催办下次要触发的时间。则修改triggerDate
                if(warningDate.isBefore(reminder.getTriggerDate())){
                    reminder.setTriggerDate(warningDate);
                }
                //将未处理的预警设置到下次之中
                newWarningSet.add(warn);
            }
        }

        if(newWarningSet.size()>0){
            reminder.setWarningset(JsonUtil.toJson(newWarningSet));
        }else{
            reminder.setWarningset("");
        }
    }


    /**
     * 如果无动作则返回 true
     * 如果执行脚本。则修改为无动作
     * 如果结束流程，完成任务则删除当前催办
     * @return false
     */
    @Transactional
    private boolean executeDueAction(BpmTaskReminder reminder, DefaultBpmTask task) {
    	ActionCmd actionCmd = ContextThreadUtil.getActionCmd();
    	if(BeanUtils.isEmpty(actionCmd)) {
    		actionCmd = new DefaultTaskFinishCmd();
    	}
    	actionCmd.addVariable(BpmConstants.PROCESS_INST_ID, task.getProcInstId());
        if(reminder.getDueDate().isAfter(LocalDateTime.now())) {//任务还未到期
            reminder.setTriggerDate(reminder.getDueDate()); //尝试设置触发时间
            return false;
        }
        //无动作 //任务到期
        if(BpmTaskReminder.TASK_DUE_ACTION_NO_ACTION.equals(reminder.getDueAction())){
            return false;
        }
        String msg = "";
        //自动下一任务
        BpmTaskActionService bpmTaskActionService = AppUtil.getBean(BpmTaskActionService.class);
       if(BpmTaskReminder.TASK_DUE_ACTION_AUTO_NEXT.equals(reminder.getDueAction())){
            DefaultTaskFinishCmd taskFinishCmd = new DefaultTaskFinishCmd();
            taskFinishCmd.setTaskId(reminder.getTaskId());
            taskFinishCmd.setActionName("agree");
            taskFinishCmd.setApprovalOpinion("催办到期自动完成");
            try {
                bpmTaskActionService.finishTask(taskFinishCmd);
                msg = "已经自动完成当前任务！";
                this.deleteByTaskId(reminder.getTaskId());//完成当前任务后，删除与该任务关联的催办
            } catch (Exception e) {
                msg = "自动完成当前任务失败！："+e.getMessage();
                e.printStackTrace();
            }
        }
        //结束掉流程
        else if(BpmTaskReminder.TASK_DUE_ACTION_END_PROCESS.equals(reminder.getDueAction())){
            try {
                bpmTaskActionService.endProcessByTaskId(reminder.getTaskId(), reminder.getMsgType(), "催办任务到期，自动结束流程！","");
                //直接走结束方法似乎不会走插件了。所以。这里把催办全清掉。
                this.deleteByTaskId(reminder.getTaskId());
                msg = "已经结束当前流程！";
            } catch (Exception e) {
                msg = "自动结束当前流程失败！："+e.getMessage();
                e.printStackTrace();
            }
        }
        //执行脚本
        else if(BpmTaskReminder.TASK_DUE_ACTION_CALL_METHOD.equals(reminder.getDueAction())&&StringUtil.isNotEmpty(reminder.getDueScript())){
            Map<String, Object> vars = new HashMap<String, Object>();
            Map<String, Object> variables = vars= natTaskService.getVariables(reminder.getTaskId());
            vars.putAll(variables);
            vars.put("task",task);
            GroovyScriptEngine groovyScriptEngine = AppUtil.getBean(GroovyScriptEngine.class);

            try {
                groovyScriptEngine.execute(reminder.getDueScript(), vars);
            } catch (Exception e) {
                createReminderHistory(reminder, reminder.getDueAction(), "执行脚本"+reminder.getDueScript()+"\n失败！"+e.getMessage(),task);
            }

            // 执行过一次脚本以后就无动作。直到自动被删除
            reminder.setDueAction(BpmTaskReminder.TASK_DUE_ACTION_NO_ACTION);
            createReminderHistory(reminder, reminder.getDueAction(), "执行脚本成功："+reminder.getDueScript(),task);
            return false;
        }
       //自动完成任务类型则返回true，不再继续处理催办
        createReminderHistory(reminder, reminder.getDueAction(), msg,task);
        return true;
    }

    /**
     * 发送消息的处理
     * 发消息开始时间 +时间间隔=下次发送消息开始时间，更新发消息开始时间
     * 发消息次数减 1
     * 如果消息发送完毕。则count为0；
     * @throws Exception
     */
    @Transactional
    private void sendMsg(BpmTaskReminder reminder, DefaultBpmTask task) throws Exception {
        LocalDateTime  beginSend = reminder.getMsgSendDate();
        int count = reminder.getMsgCount();
        //如果还没有到发送时间,或者已经催办完毕
        if(beginSend.isAfter(LocalDateTime.now()) || count<=0)
            return;

        int interval = BeanUtils.isNotEmpty(reminder.getMsgInterval())?reminder.getMsgInterval():1;
        //每次 次数减1 ，开始时间加上一间隔。
        reminder.setMsgSendDate(TimeUtil.getLocalDateTimeByMills(TimeUtil.getNextTime(TimeUtil.MINUTE,interval,TimeUtil.getTimeMillis(beginSend))));
        reminder.setMsgCount(count-1);

        // 如果消息触发时间早于其他则设置为下次触发时间
        if(reminder.getMsgSendDate().isBefore(reminder.getTriggerDate())){
            reminder.setTriggerDate(reminder.getMsgSendDate());
        }

        FreeMarkerEngine FreeMarkerEngine=AppUtil.getBean(FreeMarkerEngine.class);
        Map<String, Object> vars = new HashMap<String, Object>();
        IUser currentUser = ContextUtil.getCurrentUser();
        vars.put("title", task.getSubject());
        vars.put("time", reminder.getRelDate());
        vars.put("task", task);
        vars.put("startorName", currentUser.getFullname());
        vars.put("startDate", DateUtil.getCurrentTime("yyyy-MM-dd"));
        //流程变量
        vars.put("flowKey_", task.getProcDefKey());
        vars.put("instanceId_", task.getProcInstId());
        vars.put("startUser", currentUser.getFullname());
        //表单变量
        BpmProcessInstance bpmProcessInstance = bpmInstService.getProcessInstance(task.getProcInstId());
        try {
        	String baseUrl = PortalDataUtil.getPropertyByAlias(TemplateConstants.TEMP_VAR.BASE_URL);
            vars.put(TemplateConstants.TEMP_VAR.BASE_URL, baseUrl);
            vars.put(TemplateConstants.TEMP_VAR.INST_ID, task.getProcInstId());
            vars.put(TemplateConstants.TEMP_VAR.TASK_ID, task.getId());
    		// 任务标题
            vars.put(TemplateConstants.TEMP_VAR.TASK_SUBJECT, task.getSubject());
    		//任务名称
            vars.put(TemplateConstants.TEMP_VAR.NODE_NAME,task.getName());
    		//流程实例名称
            vars.put(TemplateConstants.TEMP_VAR.INST_SUBJECT, task.getSubject());
    		//流程发起时间
            vars.put(TemplateConstants.TEMP_VAR.DATE, bpmProcessInstance.getCreateTime());
    		//流程申请人
            vars.put(TemplateConstants.TEMP_VAR.CREATOR, bpmProcessInstance.getCreator());
    		//流程名称
            vars.put(TemplateConstants.TEMP_VAR.BPMNAME, task.getProcDefName());
    		// 意见
            vars.put(TemplateConstants.TEMP_VAR.CAUSE, "催办消息提醒");
            //发送人信息
            vars.put(TemplateConstants.TEMP_VAR.SENDER, currentUser.getFullname());
        	vars.put(TemplateConstants.TEMP_VAR.DELEGATE,currentUser.getFullname());
        	vars.put(TemplateConstants.TEMP_VAR.AGENT, currentUser.getFullname());
		} catch (Exception e) {
			System.out.println("设置变量出错："+e.getMessage());
		}
        //表单变量
        List<ObjectNode> boDatas = boDataService.getDataByInst(bpmProcessInstance);
        if(BeanUtils.isNotEmpty(boDatas)){
            for(ObjectNode objectNode :boDatas){
                String boName="";
    			if(objectNode.hasNonNull("boDefAlias")){
    				boName = objectNode.get("boDefAlias").asText();
    			}else  {
    				boName=objectNode.get("boDef").get("alias").asText();
    			}
                Map<String, Object> dataMap = new  HashMap<>();
                try {
                    dataMap = JsonUtil.toMap(JsonUtil.toJson(objectNode.get("data")));
                } catch (IOException e) {
                    e.printStackTrace();
                }
                for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
                    vars.put(boName +"." + entry.getKey(),  entry.getValue());
                }
            }
        }
        String html,text;
        try {
             html= StringUtil.getStrByRule(reminder.getHtmlMsg(), vars);
             text=FreeMarkerEngine.parseByTemplate(reminder.getPlainMsg(), vars);
        }catch(Exception e) {
            createReminderHistory(reminder, "sendMsg", "发送消息失败！"+e.getMessage(), task);
            return;
        }
        String userNames = "";
        //获取用户
        List<IUser> recievers = new ArrayList<IUser>();

        //将用户抽取出来。
        recievers= bpmIdentityExtractService.extractUser(bpmIdentityService.searchByNode(task.getProcInstId(),task.getNodeId()));
        Map<String,IUser> reciversMap = recievers.stream().collect(Collectors.toMap(item -> item.getUserId(),item->item));

        Set<String> leaderIdSet = new HashSet<>();

        if(StringUtil.isNotZeroEmpty(task.getOwnerId())){
            userNames = task.getOwnerName();
            leaderIdSet.add(task.getOwnerId());
        }else{
            for (BpmIdentity identity : task.getIdentityList()) {
                userNames +=identity.getName()+",";
                leaderIdSet.add(identity.getId());
            }
        }
        Set<String> secreIdSet =new HashSet<>();
        if (BpmTaskReminder.IS_SEND_PERSON.equals(reminder.getSendPerson())) {
            if (BeanUtils.isNotEmpty(reminder.getSendUserId())){
                IUser user = reciversMap.get(reminder.getSendUserId());
                if(BeanUtils.isNotEmpty(user)){
                	recievers = new ArrayList<>();
                    recievers.add(user);
                    userNames = user.getFullname();
                }
            }else{
                BpmSecretaryManageManager bManage = AppUtil.getBean(BpmSecretaryManageManager.class);
                Map<String, Set<String>> secretarys = bManage.getSecretaryByleaderIds(leaderIdSet, task.getProcDefKey());
                for (Iterator<Entry<String, Set<String>>> iterator = secretarys.entrySet().iterator(); iterator.hasNext();) {
                    Entry<String, Set<String>> next = iterator.next();
                    if (StringUtil.isEmpty(next.getKey())) {
                        iterator.remove();
                    }
                    for (Iterator<String> iterator2 = next.getValue().iterator(); iterator2.hasNext();) {
                        String secreId = iterator2.next();
                        //如果秘书同时也是候选人
                        if (leaderIdSet.contains(secreId) || StringUtil.isEmpty(secreId)) {
                            iterator2.remove();
                        }else{
                            secreIdSet.add(secreId);
                        }
                    }
                }
                Map<String, ObjectNode>  userMap = new  HashMap<>();
                if (!secreIdSet.isEmpty()) {
                    UCFeignService ucFeignService =AppUtil.getBean(UCFeignService.class);
                    Set<String> userIdSet = new HashSet<>();
                    userIdSet.addAll(leaderIdSet);
                    userIdSet.addAll(secreIdSet);
                    ArrayNode user = ucFeignService.getUserByIdsOrAccounts(StringUtil.join(userIdSet));
                    for (JsonNode jsonNode : user) {
                        ObjectNode userNode = (ObjectNode) jsonNode;
                        userMap.put(userNode.get("id").asText(), userNode);
                    }
                    Set<String> sendSecretaryName =new HashSet<>();
                    for (Iterator<Entry<String, Set<String>>> iterator = secretarys.entrySet().iterator(); iterator.hasNext();) {
                        Entry<String, Set<String>> next = iterator.next();
                        String subject = "【"+userMap.get(next.getKey()).get("fullname").asText()+"】共享任务催办";
                        List<JmsActor> actors = new ArrayList<>();
                        for (Iterator<String> iterator2 = next.getValue().iterator(); iterator2.hasNext();) {
                            String secretId = iterator2.next();
                            sendSecretaryName.add(userMap.get(secretId).get("fullname").asText());
                            JmsActor jmsActor = new JmsActor();
                            jmsActor.setId(secretId);
                            jmsActor.setEmail(JsonUtil.getString(userMap.get(secretId), "email"));
                            jmsActor.setMobile(JsonUtil.getString(userMap.get(secretId), "mobile"));
                            jmsActor.setWeixin(JsonUtil.getString(userMap.get(secretId), "weixin"));
                            jmsActor.setClientId(JsonUtil.getString(userMap.get(secretId), "clientId"));
                            jmsActor.setClientToken(JsonUtil.getString(userMap.get(secretId), "clientToken"));
                            actors.add(jmsActor);
                        }
                        sendMsg(subject,reminder,text,html,actors,vars);
                    }
                    userNames+=StringUtil.join(sendSecretaryName);
                }
            }
        }
        sendMsg("任务催办",reminder,text,html,MessageUtil.parseJmsActor(recievers),vars);
        createReminderHistory(reminder, "sendMsg", "向["+userNames+"]发送催办消息成功！", task);
    }


    //发送催办消息
    @Transactional
    private void sendMsg(String subject,BpmTaskReminder reminder,  String text, String html,List<JmsActor> reciever,Map<String, Object> vars) {
        NoticeMessageType[] messageTypes = MessageUtil.parseNotifyType(reminder.getMsgType());
        ApplicationFeignService applicationFeignService = AppUtil.getBean(ApplicationFeignService.class);
        for(NoticeMessageType type : messageTypes){
            if(type.isPlain()) {
                Notice notice = new Notice();
                notice.setSubject(subject);
                notice.setReceiver(reciever);
                notice.setContent(text);
                notice.setMessageTypes(new NoticeMessageType[]{type});
                notice.setVars(vars);
                applicationFeignService.sendNoticeToQueue(notice);
            }
            else {
                Notice notice = new Notice();
                notice.setSubject(subject);
                notice.setReceiver(reciever);
                notice.setContent(html);
                notice.setMessageTypes(new NoticeMessageType[]{type});
                notice.setVars(vars);
                applicationFeignService.sendNoticeToQueue(notice);
            }
        }
    }

    //创建催办执行历史
    @Transactional
    private void createReminderHistory(BpmTaskReminder reminder, String type, String msg, DefaultBpmTask task) {
        BpmReminderHistory history = new BpmReminderHistory();
        history.setExecuteDate(reminder.getDueDate());
        history.setNodeId(task.getNodeId());
        history.setNodeName(task.getName());
        history.setInstId(task.getProcInstId());
        history.setIsntName(task.getSubject());
        history.setRemindType(type);
        history.setNote(msg);
        history.setUserId(task.getOwnerId());
        history.setId(UniqueIdUtil.getSuid());
        history.setTaskId(task.getTaskId());
        bpmReminderHistoryManager.create(history);
    }

}
