package com.xjrsoft.module.workflow.listener;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.enums.WorkflowNoticePolicyType;
import com.xjrsoft.common.enums.YesOrNoEnum;
import com.xjrsoft.common.exception.MyException;
import com.xjrsoft.module.oa.utils.SendMessageUtil;
import com.xjrsoft.module.workflow.constant.WorkflowConstant;
import com.xjrsoft.module.workflow.entity.WorkflowSchema;
import com.xjrsoft.module.workflow.model.MemberConfig;
import com.xjrsoft.module.workflow.model.NoticePolicyParam;
import com.xjrsoft.module.workflow.model.TimeoutRemidConfig;
import com.xjrsoft.module.workflow.model.WorkflowSchemaConfig;
import com.xjrsoft.module.workflow.service.IWorkflowExecuteService;
import com.xjrsoft.module.workflow.service.IWorkflowSchemaService;
import com.xjrsoft.module.workflow.utils.WorkFlowUtil;
import org.apache.commons.collections.MapUtils;
import org.camunda.bpm.engine.ProcessEngines;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.task.Task;
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 java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 超时提醒 监听器
 * 监听redis key 过期
 *
 * @Author: tzx
 * @Date: 2022/10/26 14:46
 */
@Component
public class TaskTimeoutListener extends KeyExpirationEventMessageListener {

    private final IWorkflowExecuteService workflowExecuteService;

    public TaskTimeoutListener(RedisMessageListenerContainer listenerContainer, IWorkflowExecuteService workflowExecuteService) {
        super(listenerContainer);
        this.workflowExecuteService = workflowExecuteService;
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
        String expiredKey = message.toString();

        TaskService taskService = ProcessEngines.getDefaultProcessEngine().getTaskService();

        //如果是指定审批人 key 失效
        if (expiredKey.contains(WorkflowConstant.TASK_IS_APPOINT_APPROVE)) {
            String[] split = expiredKey.split(StringPool.UNDERSCORE);
            String taskId = split[0];

            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (task == null) {
                return;
            }
            int code = Convert.toInt(taskService.getVariable(task.getId(),WorkflowConstant.TASK_IS_APPOINT_APPROVE));
            if (code == YesOrNoEnum.NO.getCode()){
                return;
            }
            //到期未指定的任务 将变量设置为不需要指定
//            taskService.setVariableLocal(task.getId(), WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode());

            // 驳回
            workflowExecuteService.dealTimeoutTask(1, taskId);

            List<Task> list = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
            if (list.size() == 1) {
                Task currentTask = list.get(0);
                //获取到审批人 发送消息
                Object approvedIds = taskService.getVariableLocal(currentTask.getId(), WorkflowConstant.TASK_ASSIGNEE_VAR_KEY);

                List<String> variableNames = ListUtil.toList(
                        WorkflowConstant.PROCESS_SCHEMA_ID_KEY,
                        WorkflowConstant.PROCESS_SCHEMA_NAME_KEY,
                        WorkflowConstant.PROCESS_START_USER_NAME_KEY);

                Map<String, Object> variables = taskService.getVariables(currentTask.getId(), variableNames);

//                Long schemaId = Convert.toLong(taskService.getVariable(currentTask.getId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY));

//                IWorkflowSchemaService workflowSchemaService = SpringUtil.getBean(IWorkflowSchemaService.class);
//                WorkflowSchema workflowSchema = workflowSchemaService.getOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaId).select(WorkflowSchema::getJsonContent));

//                WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);

//                Map<String, Object> userTaskConfigMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(currentTask.getTaskDefinitionKey())).findFirst().orElse(new HashMap<>());
//                UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigMap);

                List<String> approveIds = ListUtil.toList(Convert.toStr(approvedIds).split(StringPool.COMMA));

                NoticePolicyParam param = new NoticePolicyParam();
                param.setNoticeUserIds(Convert.toList(Long.class, approveIds));
                param.setTaskId(currentTask.getId());
                param.setTaskName(currentTask.getName());
                param.setProcessId(currentTask.getProcessInstanceId());
                param.setTaskName(currentTask.getName());
                param.setSchemaId(MapUtil.get(variables, WorkflowConstant.PROCESS_SCHEMA_ID_KEY, Long.class));
                param.setSchemaName(MapUtil.get(variables, WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, String.class));
                param.setStartUserName(MapUtil.get(variables, WorkflowConstant.PROCESS_START_USER_NAME_KEY, String.class));
                // 默认强制推送微信消息
                param.setNoticePolicyConfigs(new ArrayList() {{
                    add(WorkflowNoticePolicyType.WECHAT.getCode());
                }});
                //超时消息
                WorkFlowUtil.sendTimeOutNoticePolicy(param, "由于审批超时，系统自动驳回审批");
            }

            return;
        }

        //如果key 不包含此前缀  不再执行此逻辑
        if (!expiredKey.contains(WorkflowConstant.TIMEOUT_REMID_KEY)) {
            return;
        }


        // 将过期key使用冒号 切割
        String[] expiredKeyArr = expiredKey.split(StringPool.COLON);

        //获取到任务id
        String taskId = expiredKeyArr[1];

        //获取到次数
//        String hit = expiredKeyArr[2];

        //获取到通知策略
        String noticePolicyConfigString = expiredKeyArr[3];
        String[] noticePolicyTypeList = noticePolicyConfigString.split(StringPool.UNDERSCORE);

        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();

        if (task == null) {//如果任务为空可能是自动处理了，不进行接下来的操作了
            return;
        }

        //根据taskid  获取发起人 以及 模板名称
        Map<String, Object> variables = taskService.getVariables(taskId, ListUtil.toList(WorkflowConstant.PROCESS_START_USER_NAME_KEY, WorkflowConstant.PROCESS_SCHEMA_NAME_KEY));

        String starter = StrUtil.toString(variables.get(WorkflowConstant.PROCESS_START_USER_NAME_KEY));
        String schemaName = StrUtil.toString(variables.get(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY));

        //获取到需要提醒的人员(过期key  无法获取到value  需要数据库取审批人)
        Object assignee = taskService.getVariableLocal(taskId, WorkflowConstant.TASK_ASSIGNEE_VAR_KEY);

        List<String> approveIds = ListUtil.toList(Convert.toStr(assignee).split(StringPool.COMMA));
        List<Long> ids = Convert.toList(Long.class, approveIds);
        Long schemaId = Convert.toLong(taskService.getVariable(task.getId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY));

        IWorkflowSchemaService workflowSchemaService = SpringUtil.getBean(IWorkflowSchemaService.class);
        WorkflowSchema workflowSchema = workflowSchemaService.getOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaId).select(WorkflowSchema::getJsonContent));

        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);

        //找到当前用户任务节点的配置信息
        TimeoutRemidConfig timeoutRemidConfig = workflowSchemaConfig.getProcessConfig().getTimeoutRemidConfig();
        List<MemberConfig> pushMemberConfigs = timeoutRemidConfig.getPushMemberConfigs();

        List<Map<String, Object>> childNodeConfigList = workflowSchemaConfig.getChildNodeConfig();
        if (pushMemberConfigs.size() > 0) {
            List<Long> userIdsByMemberConfig = WorkFlowUtil.getUserIdsByMemberConfig(pushMemberConfigs, childNodeConfigList, task.getProcessInstanceId());
            ids.addAll(userIdsByMemberConfig);

        }
        List<Long> allPushUserIds = ids.stream().distinct().collect(Collectors.toList());
        //遍历所有设定的通知策略
        // 暂时这样写 后续可以改成 策略模式 或者 工厂模式
        //TODO  sendMessageUtil  改成与 oss 一样的工厂

        NoticePolicyParam param = new NoticePolicyParam();
        param.setNoticeUserIds(Convert.toList(Long.class, allPushUserIds));
        param.setTaskId(task.getId());
        param.setTaskName(task.getName());
        param.setProcessId(task.getProcessInstanceId());
        param.setTaskName(task.getName());
        param.setSchemaId(schemaId);
        param.setSchemaName(schemaName);
        param.setStartUserName(starter);
        for (String type : noticePolicyTypeList) {
            //如果包含系统消息推送
            if (Convert.toInt(type) == WorkflowNoticePolicyType.SYSTEM.getCode()) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutMessage(param);
                });

            }
            //短信发送
            if (Convert.toInt(type) == WorkflowNoticePolicyType.SMS.getCode()) {
                //TODO 短信发送代码
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutSms(param, task.getName());
                });
            }

            //企业微信
            if (Convert.toInt(type) == WorkflowNoticePolicyType.WECHAT.getCode()) {
                //TODO 企业微信发送代码
            }

            //钉钉
            if (Convert.toInt(type) == WorkflowNoticePolicyType.DING.getCode()) {
                //TODO 钉钉发送代码
            }

            //邮箱
            if (Convert.toInt(type) == WorkflowNoticePolicyType.EMAIL.getCode()) {
                //TODO 邮箱发送
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutEmail(param);
                });

            }
            // 超时处理
            Map<String, Object> timeoutHandle = null;
            for (Map<String, Object> childNodeConfig : childNodeConfigList) {
                // 找到当前任务
                if (StrUtil.equals(task.getTaskDefinitionKey(), MapUtils.getString(childNodeConfig, "id"))) {
                    timeoutHandle = MapUtils.getMap(childNodeConfig, "timeOutHandle");
                }
            }
            if (timeoutHandle != null && MapUtils.getInteger(timeoutHandle, "isHandle") == 2) {
                Integer currentHit = Integer.parseInt(expiredKeyArr[2]); // 当前超时提醒次数
                Integer rule = MapUtils.getInteger(timeoutHandle, "rule");
                boolean toHandle = false;
                if (rule == 1) {
                    // 超过最大推送次数则即时处理
                    Integer pushHits = timeoutRemidConfig.getPushHits(); // 配置超时提醒次数
                    toHandle = currentHit.equals(pushHits);
                } else if (rule == 2) {
                    // 首次超时即处理
                    toHandle = currentHit == 1;
                }
                if (toHandle) {
                    Integer handleType = MapUtils.getInteger(timeoutHandle, "type");
                    if (handleType == 1) {
                        // 驳回
                        workflowExecuteService.dealTimeoutTask(handleType, taskId);
                    } else if (handleType == 2) {
                        // 同意
                        workflowExecuteService.dealTimeoutTask(handleType, taskId);
                    } else {
                        throw new MyException("未选择处理方式");
                    }
                }
            }
        }

    }
}
