package org.springblade.flow.engine.custom.action;

import static org.springblade.flow.base.util.BpmnModelUtils.getAttributeValueByTaskDefinitionKey;
import static org.springblade.flow.engine.custom.constants.BasicActivitiConstants.exActivitiPrefixURL;
import static org.springblade.flow.engine.custom.constants.BasicActivitiConstants.extensionAttributeName;
import static org.springblade.flow.engine.custom.constants.GlobalProcessVariableConstants.BUSINESS_TITLE;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.task.api.Task;
import org.springblade.flow.base.util.SpringContextHolder;
import org.springblade.flow.engine.assembly.GlobalExPropertyDTO;
import org.springblade.flow.engine.assembly.UserTaskExPropertyDTO;
import org.springblade.flow.engine.assembly.prop.UserTaskAdvancedSettingDTO;
import org.springblade.flow.engine.custom.constants.BasicActivitiConstants;
import org.springblade.flow.engine.entity.FlowTaskOperatorRecordEntity;
import org.springblade.flow.engine.enums.FlowMessageEnum;
import org.springblade.flow.engine.enums.FlowRecordEnum;
import org.springblade.flow.engine.model.flowengine.shuntjson.childnode.TimeOutConfig;
import org.springblade.flow.engine.service.FlowTaskOperatorRecordService;
import org.springblade.flow.message.enums.MessageTypeEnum;
import org.springblade.flow.message.model.message.SentMessageForm;
import org.springblade.flow.message.util.SentMessageUtil;
import org.springblade.flow.util.JsonUtil;
import org.springblade.flow.util.JsonUtilEx;
import org.springblade.flow.util.RandomUtil;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;

/**
 * @author LoveMyOrange
 * @create 2022-01-20 20:08
 * @desc 使用Redis实时监听  receiveTask是否到期   实时上Redis不能做到实时, ZK可以做到
 * 有人推荐MQ 和JOB 纯属扯淡, 那要创建多少个queue 和job
 */
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
        String key = message.toString();
        //只监听 流程引擎的 过期key
        if (StrUtil.startWith(key, BasicActivitiConstants.RECEIVE_TASK_TIME_KEY_PREFIX)) {
            String[] split = key.split("-");
            String processInstanceId = split[1];
            String executionId = split[2];
            String activityId = split[3];
            RuntimeService runtimeService = SpringContextHolder.getBean(RuntimeService.class);
            //当然还可以干的别的事
            runtimeService.trigger(executionId);
        }

        //监听UserTask超时的Key
        if (StrUtil.startWith(key, BasicActivitiConstants.USER_TASK_TIME_KEY_PREFIX)) {
            TaskService taskService = SpringContextHolder.getBean(TaskService.class);
            RepositoryService repositoryService = SpringContextHolder.getBean(RepositoryService.class);
            RuntimeService runtimeService = SpringContextHolder.getBean(RuntimeService.class);
            FlowTaskOperatorRecordService flowTaskOperatorRecordService = SpringContextHolder.getBean(FlowTaskOperatorRecordService.class);
            SentMessageUtil sentMessageUtil = SpringContextHolder.getBean(SentMessageUtil.class);


            String[] split = key.split("-");
            String processInstanceId = split[1];
            String taskId = split[2];
            String taskDefinitionKey = split[3];
            String processDefinitionId = split[4];

            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
            Process mainProcess = bpmnModel.getMainProcess();
            String property = getAttributeValueByTaskDefinitionKey(mainProcess, "", "global");
            GlobalExPropertyDTO exPropertyDTO = JSONObject.parseObject(property, new TypeReference<GlobalExPropertyDTO>() {
            });

            UserTask activity = (UserTask) mainProcess.getFlowElement(taskDefinitionKey);
            String taskProperty = activity.getAttributeValue(exActivitiPrefixURL, extensionAttributeName);
            UserTaskExPropertyDTO taskExPropertyDTO = JSONObject.parseObject(taskProperty, new TypeReference<UserTaskExPropertyDTO>() {
            });

            UserTaskAdvancedSettingDTO userTaskAdvancedSettingDTO = taskExPropertyDTO.getUserTaskAdvancedSettingDTO();
            TimeOutConfig timeOutConfig = userTaskAdvancedSettingDTO.getTimeOutConfig();
            String title = runtimeService.getVariable(processInstanceId, BUSINESS_TITLE, String.class);
            if (timeOutConfig != null) {
                if (timeOutConfig.getOn()) {
                    Integer handler = timeOutConfig.getHandler();
                    Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
                    FlowTaskOperatorRecordEntity flowTaskOperatorRecordEntity = new FlowTaskOperatorRecordEntity();
                    flowTaskOperatorRecordEntity.setId(RandomUtil.uuId());
                    flowTaskOperatorRecordEntity.setNodeCode(taskDefinitionKey);
                    flowTaskOperatorRecordEntity.setNodeName(task.getName());
                    flowTaskOperatorRecordEntity.setHandleStatus(FlowRecordEnum.audit.getCode());
                    flowTaskOperatorRecordEntity.setHandleId("admin");
                    flowTaskOperatorRecordEntity.setHandleName("管理员");
                    flowTaskOperatorRecordEntity.setHandleTime(new Date());
                    flowTaskOperatorRecordEntity.setHandleOpinion("任务超时 自动通过");
                    flowTaskOperatorRecordEntity.setOperatorId("admin");
                    flowTaskOperatorRecordEntity.setTaskNodeId(taskId);
                    flowTaskOperatorRecordEntity.setTaskId(processInstanceId);
                    flowTaskOperatorRecordEntity.setStatus("100");//随便
                    if (handler == 1) {
                        //保存
                        flowTaskOperatorRecordService.save(flowTaskOperatorRecordEntity);
                        taskService.complete(taskId);
                    }
                    //退回
                    else if (handler == 2) {
                        String rejectStep = userTaskAdvancedSettingDTO.getRejectStep();
                        flowTaskOperatorRecordEntity.setHandleStatus(FlowRecordEnum.reject.getCode());
                        flowTaskOperatorRecordEntity.setHandleOpinion("任务超时 自动拒绝");
                        flowTaskOperatorRecordService.save(flowTaskOperatorRecordEntity);
                        ArrayList<String> distinct = CollectionUtil.distinct(runtimeService.getActiveActivityIds(processInstanceId));
                        runtimeService.createChangeActivityStateBuilder()
                                .processInstanceId(processInstanceId)
                                .moveActivityIdsToSingleActivityId(distinct, rejectStep)
                                .changeState();
                    }
                    //
                    else {
                        //发送站内信 通知:
                        List<IdentityLink> identityLinksForTask = taskService.getIdentityLinksForTask(taskId);
                        Set<String> userIds = new HashSet<>();
                        for (IdentityLink identityLink : identityLinksForTask) {
                            String userId = identityLink.getUserId();
                            userIds.add(userId);
                        }

                        List<String> messageType = new ArrayList<>();
                        messageType.add(MessageTypeEnum.SysMessage.getCode());
                        SentMessageForm sentMessageForm = new SentMessageForm();
                        sentMessageForm.setSendType(messageType);
                        Map<String, Object> messageInfo = new HashMap<>(16);
                        messageInfo.put("type", FlowMessageEnum.dueDate.getCode());
                        messageInfo.put("id", processInstanceId);
                        sentMessageForm.setContent(JsonUtilEx.getObjectToString(messageInfo));
                        sentMessageForm.setTitle(title + "【这条审批已经超时了,请您及时处理!】");
                        sentMessageForm.setToUserIds(new ArrayList<>(userIds));
                        Map<String, String> smsContent = new HashMap<>(16);
                        this.message(title, title, smsContent);
                        sentMessageForm.setSmsContent(smsContent);
                        //拿到节点上的人发通知:
                        sentMessageUtil.sendMessage(sentMessageForm);
                    }
                }
            }


        }

    }

    /**
     * 短信模板
     *
     * @param title  标题
     * @param status 状态
     * @return
     */
    private void message(String title, String status, Map<String, String> msg) {
        Map<String, String> aliyun = new HashMap<>(16);
        aliyun.put("title", title);
        aliyun.put("status", status);
        msg.put("1", JsonUtil.getObjectToString(aliyun));
        msg.put("2", "2");
    }

}
