package com.codvision.workflow.listener.task;

import cn.hutool.json.JSONUtil;
import com.codvision.auth.entity.SysUser;
import com.codvision.auth.service.ISysUserService;
import com.codvision.auth.support.SendSms;
import com.codvision.base.service.ISysConfigService;
import com.codvision.workflow.entity.dto.WorkFlowSmsDTO;
import com.codvision.workflow.service.WorkFlowService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.TaskService;
import org.flowable.task.service.delegate.DelegateTask;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.codvision.workflow.constant.WorkFlowConstant.CLAIM_SMS_PARAMS;
import static com.codvision.workflow.constant.WorkFlowConstant.SMS_CURRENT_USERS;


/**
 * 阿里云短信消息通知
 * @author hxl
 */
@Slf4j
@RequiredArgsConstructor
@Component(value = "workFlowAliyunSmsMsgNoticeListener")
public class WorkFlowAliyunSmsMsgNoticeListener {

    private static final Pattern PATTERN = Pattern.compile("\\$\\{([^}]+)}");
    private final ISysConfigService configService;
    private final TaskService taskService;
    private final WorkFlowService workFlowService;
    private final ISysUserService sysUserService;

    /**
     * 发送短信消息通知（事件类型 -> create）
     * @param delegateTask 当前任务
     * @param expression 布尔表达式，为true时生效
     * @param smsJson 短信信息，json形式
     */
    public void sendMsg(DelegateTask delegateTask, boolean expression, String smsJson) {
        try {
            if (!expression) {
                return;
            }

            WorkFlowSmsDTO sms = preHandle(delegateTask.getId(), smsJson);
            if (sms == null) {
                return;
            }

            sendSmsMsg(sms);
        } catch (Exception e) {
            // 发送短信可以看做边缘业务功能，捕获后仅打印异常信息，防止发生异常影响流程的正常进行
            log.error(e.getMessage());
        }
    }

    /**
     * 签收发送短信消息通知（事件类型 -> create）
     * @param delegateTask 当前任务
     * @param smsJson 短信信息，json形式
     */
    public void sendClaimMsg(DelegateTask delegateTask, String smsJson) {
        WorkFlowSmsDTO sms = preHandle(delegateTask.getId(), smsJson);
        if (sms == null) {
            return;
        }

        taskService.setVariableLocal(delegateTask.getId(), CLAIM_SMS_PARAMS, sms);
    }


    @SneakyThrows
    private void sendSmsMsg(WorkFlowSmsDTO sms) {
        SendSms sendSms = new SendSms(configService);
        sendSms.sendWithParam(sms.getPhoneNumbers(), sms.getSignName(), sms.getTemplateCode(), sms.getTemplateParam());
    }

    private WorkFlowSmsDTO preHandle(String taskId, String smsJson) {
        if (StringUtils.isBlank(smsJson) || !JSONUtil.isTypeJSONObject(smsJson)) {
            return null;
        }

        WorkFlowSmsDTO sms = JSONUtil.toBean(smsJson, WorkFlowSmsDTO.class);
        if (StringUtils.isBlank(sms.getTemplateCode()) || StringUtils.isBlank(sms.getSignName())
                || StringUtils.isBlank(sms.getTemplateParam()) || StringUtils.isBlank(sms.getPhoneNumbers())) {
            return null;
        }

        if (!JSONUtil.isTypeJSONObject(sms.getTemplateParam())) {
            return null;
        }

        sms.setPhoneNumbers(initSmsParams(taskId, sms.getPhoneNumbers()));
        sms.setTemplateParam(initSmsParams(taskId, sms.getTemplateParam()));
        return sms;
    }

    private String initSmsParams(String taskId, String str) {
        Map<String, Object> varMap = new HashMap<>(16);
        Matcher matcher = PATTERN.matcher(str);
        while (matcher.find()) {
            String var = matcher.group(1);
            if (StringUtils.isBlank(var)) {
                continue;
            }

            if (varMap.containsKey(var)) {
                continue;
            }

            if (SMS_CURRENT_USERS.equals(var)) {
                List<Integer> taskRelatedUserIds = workFlowService.getTaskRelatedUserIds(taskId);
                if (CollectionUtils.isEmpty(taskRelatedUserIds)) {
                    continue;
                }

                List<SysUser> sysUsers = sysUserService.listByIds(taskRelatedUserIds);
                if (CollectionUtils.isEmpty(sysUsers)) {
                    continue;
                }

                String value = sysUsers.stream().map(SysUser::getMobile).filter(StringUtils::isNotBlank).distinct().collect(Collectors.joining(","));
                if (StringUtils.isNotBlank(value)) {
                    varMap.put(var, value);
                }
            } else {
                Object o = taskService.getVariable(taskId, var);
                if (o == null) {
                    continue;
                }

                varMap.put(var, o);
            }
        }

        for (Map.Entry<String, Object> entry : varMap.entrySet()) {
            str = str.replaceAll("\\$\\{"+entry.getKey()+"}", String.valueOf(entry.getValue()));
        }

        return str;
    }

}
