package cn.iocoder.yudao.module.bpm.service.message;

import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.template.WxMaMsgTemplateUtils;
import cn.iocoder.yudao.framework.common.template.WxMpMsgTemplateUtils;
import cn.iocoder.yudao.framework.common.template.dto.ApprovalResultNotificationMessageDTO;
import cn.iocoder.yudao.framework.common.template.dto.MessageUnreadReminderDTO;
import cn.iocoder.yudao.framework.common.template.dto.ProcessToDoReminderDTO;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.web.config.WebProperties;
import cn.iocoder.yudao.module.bpm.convert.message.BpmMessageConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkTaskDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import cn.iocoder.yudao.module.bpm.enums.message.BpmMessageEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO;
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO;
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAWorkTaskService;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.system.api.auth.AdminOauthUserOtherInfoApi;
import cn.iocoder.yudao.module.system.api.auth.dto.AdminOauthUserOtherInfoApiDTO;
import cn.iocoder.yudao.module.system.api.auth.vo.AdminOauthUserOtherInfoApiVO;
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * BPM 消息 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class BpmMessageServiceImpl implements BpmMessageService {

    @Resource
    private AdminUserApi userApi;

    @Resource
    private NotifyMessageSendApi notifyMessageSendApi;

    @Resource
    private SubscribeMessageSendApi subscribeMessageSendApi;

    @Resource
    private WebProperties webProperties;

    @Resource
    @Lazy // 解决循环依赖
    private BpmProcessInstanceService bpmProcessInstanceService;

    @Resource
    private BpmOAWorkTaskService workTaskService;
    @Resource
    private AdminOauthUserOtherInfoApi adminOauthUserOtherInfoApi;

    @Override
    public void sendMessageWhenProcessInstanceApprove(BpmMessageSendWhenProcessInstanceApproveReqDTO reqDTO) {
        //审批通过
        Map<String, Object> templateParams = new HashMap<>();
        templateParams.put("processInstanceName", reqDTO.getProcessInstanceName());
        templateParams.put("detailUrl", getProcessInstanceDetailUrl(reqDTO.getProcessInstanceId()));
//        smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getStartUserId(),
//                BpmMessageEnum.PROCESS_INSTANCE_APPROVE.getSmsTemplateCode(), templateParams));

        // 获得任务分配数据
        String nickName = null;
        BpmOAWorkTaskDO workTaskDO = workTaskService.getWorkTaskByProcessInstanceId(reqDTO.getProcessInstanceId());
        if (workTaskDO != null) {

            nickName = userApi.getUser(workTaskDO.getReceiverUserId()).getCheckedData().getNickname();

            templateParams = new HashMap<>();
            templateParams.put("userName", nickName);
            templateParams.put("detailUrl", webProperties.getAdminUi().getUrl() + "/work-task/allocation?fromUserId=" + workTaskDO.getFromUserId() + "&userId=" + workTaskDO.getReceiverUserId());

            //站内信
            notifyMessageSendApi.sendSingleMessageToAdmin(BpmMessageConvert.INSTANCE.convert1(
                    reqDTO.getStartUserId(), BpmMessageEnum.BPM_WORK_TASK_COMPLETE.getSmsTemplateCode(), templateParams));
        } else {

            //发送站内信息
            notifyMessageSendApi.sendSingleMessageToAdmin(BpmMessageConvert.INSTANCE.convert1(reqDTO.getStartUserId(),
                    BpmMessageEnum.PROCESS_INSTANCE_APPROVE.getSmsTemplateCode(), templateParams));
        }


        //发送审批结果通知至微信
        List<AdminOauthUserOtherInfoApiVO> list = this.getUserOpenId(Collections.singletonList(reqDTO.getStartUserId()));
        Map<Integer, String> openIdMap = list.stream().collect(Collectors.toMap(AdminOauthUserOtherInfoApiVO::getSocialType, AdminOauthUserOtherInfoApiVO::getOpenId));

        if (workTaskDO != null && StrUtil.isNotEmpty(openIdMap.get(SocialTypeEnum.WECHAT_MINI_APP.getType()))) {
            AdminUserRespDTO userRespDTO = userApi.getUser(workTaskDO.getReceiverUserId()).getCheckedData();
            SubscribeMessageReqDTO dto = new WxMaMsgTemplateUtils().convertMessageUnreadReminder(new MessageUnreadReminderDTO()
                    .setOpenId(openIdMap.get(SocialTypeEnum.WECHAT_MINI_APP.getType()))
                    .setMsgType(reqDTO.getProcessInstanceName())
                    .setSender(nickName)
                    .setComment("你分配的任务已完成！")
                    .setSendingTime(reqDTO.getCreateTime())
                    .setPage("subPages/task/taskAssignment?userId=" + workTaskDO.getReceiverUserId() + "&deptId=" + userRespDTO.getDeptId())
                    .setMiniProgramState("formal"));
            subscribeMessageSendApi.sendMaMsg(dto);
        }

        if (workTaskDO == null && StrUtil.isNotEmpty(openIdMap.get(SocialTypeEnum.WECHAT_MP.getType()))) {
            SubscribeMessageReqDTO dto = new WxMpMsgTemplateUtils().convertApprovalResultNotification(new ApprovalResultNotificationMessageDTO()
                    .setOpenId(openIdMap.get(SocialTypeEnum.WECHAT_MP.getType()))
                    .setProcessInstanceName(reqDTO.getProcessInstanceName())
                    .setTime(reqDTO.getCreateTime())
                    .setResult("通过")
                    .setReason(reqDTO.getReason())
                    .setMiniProgramState("formal")
                    .setPage("subPagesB/bpm/task/todo/examineApprove?id=" + reqDTO.getProcessInstanceId() + "&isDetail=1"));
            subscribeMessageSendApi.sendMpMsg(dto);
        }

        //当流程全部审批通过
        BpmProcessInstanceExtDO processInstance = bpmProcessInstanceService.getProcessInstanceDO(reqDTO.getProcessInstanceId());
        if (processInstance.getResult().equals(BpmProcessInstanceResultEnum.APPROVE.getResult())) {
            //获取抄送用户ID
            String ccIDs = processInstance.getCcids();
            if (ccIDs != null && !ccIDs.isEmpty()) {
                Pattern pattern = Pattern.compile("\\[(\\d+)]");
                Matcher matcher = pattern.matcher(ccIDs);
                List<Long> userIds = new ArrayList<>();
                while (matcher.find()) {
                    String ccID = matcher.group(1);
                    userIds.add(Long.valueOf(ccID));
                    //发送抄送信息至微信
                }
                List<AdminOauthUserOtherInfoApiVO> adminOauthUserOtherInfoApiVOS = this.getUserOpenId(userIds, SocialTypeEnum.WECHAT_MP.getType());
                for (AdminOauthUserOtherInfoApiVO adminOauthUserOtherInfoApiVO : adminOauthUserOtherInfoApiVOS) {
                    if (adminOauthUserOtherInfoApiVO.getOpenId() != null) {
                        SubscribeMessageReqDTO dto = new WxMpMsgTemplateUtils().convertApprovalResultNotification(new ApprovalResultNotificationMessageDTO()
                                .setOpenId(adminOauthUserOtherInfoApiVO.getOpenId())
                                .setProcessInstanceName(reqDTO.getProcessInstanceName())
                                .setTime(reqDTO.getCreateTime())
                                .setResult("抄送")
                                .setReason(reqDTO.getReason())
                                .setMiniProgramState("formal")
                                .setPage("subPagesB/bpm/task/todo/examineApprove?id=" + reqDTO.getProcessInstanceId() + "&isDetail=1"));
                        subscribeMessageSendApi.sendMpMsg(dto);
                    }
                }
            }
        }
    }

    @Override
    public void sendMessageWhenProcessInstanceReject(BpmMessageSendWhenProcessInstanceRejectReqDTO reqDTO) {
        //审批不通过
        Map<String, Object> templateParams = new HashMap<>();
        templateParams.put("processInstanceName", reqDTO.getProcessInstanceName());
        templateParams.put("reason", reqDTO.getReason());
        templateParams.put("detailUrl", getProcessInstanceDetailUrl(reqDTO.getProcessInstanceId()));
//        smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getStartUserId(),
//                BpmMessageEnum.PROCESS_INSTANCE_REJECT.getSmsTemplateCode(), templateParams));
        notifyMessageSendApi.sendSingleMessageToAdmin(BpmMessageConvert.INSTANCE.convert1(
                reqDTO.getStartUserId(), BpmMessageEnum.PROCESS_INSTANCE_REJECT.getSmsTemplateCode(), templateParams));

//        //发送审批结果通知
        List<AdminOauthUserOtherInfoApiVO> list = this.getUserOpenId(Collections.singletonList(reqDTO.getStartUserId()), SocialTypeEnum.WECHAT_MP.getType());
        for (AdminOauthUserOtherInfoApiVO item : list) {
            if (item.getOpenId() != null) {
                SubscribeMessageReqDTO dto = new WxMpMsgTemplateUtils().convertApprovalResultNotification(new ApprovalResultNotificationMessageDTO()
                        .setOpenId(item.getOpenId())
                        .setProcessInstanceName(reqDTO.getProcessInstanceName())
                        .setTime(reqDTO.getCreateTime())
                        .setResult("拒绝")
                        .setReason(reqDTO.getReason())
                        .setMiniProgramState("formal")
                        .setPage("subPagesB/bpm/task/todo/examineApprove?id=" + reqDTO.getProcessInstanceId() + "&isDetail=1"));
                subscribeMessageSendApi.sendMpMsg(dto);
            }
        }

    }

    @Override
    public void sendMessageWhenTaskAssigned(BpmMessageSendWhenTaskCreatedReqDTO reqDTO) {
        //任务分配
        Long startUserId = reqDTO.getStartUserId();         //流程发起人
        Long assigneeUserId = reqDTO.getAssigneeUserId();  //任务审批人
        String taskName = reqDTO.getTaskName();
        //如果流程发起人和任务审批是同一个人， 那么不发送站内信，否则就发送
        if (!assigneeUserId.toString().equals(startUserId.toString())) {
            Map<String, Object> templateParams = new HashMap<>();
            templateParams.put("processInstanceName", reqDTO.getProcessInstanceName());
//          templateParams.put("taskName", reqDTO.getTaskName());
            templateParams.put("startUserNickname", reqDTO.getStartUserNickname());
            templateParams.put("detailUrl", getProcessInstanceDetailUrl(reqDTO.getProcessInstanceId()));

            //短信
//        smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getAssigneeUserId(),
//                BpmMessageEnum.TASK_ASSIGNED.getSmsTemplateCode(), templateParams));

            // 获得任务分配数据
            BpmOAWorkTaskDO workTaskDO = workTaskService.getWorkTaskByProcessInstanceId(reqDTO.getProcessInstanceId());
            if (workTaskDO != null) {

                templateParams = new HashMap<>();
                templateParams.put("taskName", workTaskDO.getTaskName());
                templateParams.put("startUserNickname", reqDTO.getStartUserNickname());
                templateParams.put("detailUrl", webProperties.getAdminUi().getUrl() + "/work-task/my-task?fromUserId=" + workTaskDO.getFromUserId());

                //站内信
                notifyMessageSendApi.sendSingleMessageToAdmin(BpmMessageConvert.INSTANCE.convert1(
                        reqDTO.getAssigneeUserId(), BpmMessageEnum.BPM_WORK_TASK.getSmsTemplateCode(), templateParams));
            } else {

                //站内信
                notifyMessageSendApi.sendSingleMessageToAdmin(BpmMessageConvert.INSTANCE.convert1(
                        reqDTO.getAssigneeUserId(), BpmMessageEnum.TASK_ASSIGNED.getSmsTemplateCode(), templateParams));
            }

            //微信小程序订阅消息
            //发送OA流程待办提醒
            List<AdminOauthUserOtherInfoApiVO> list = getUserOpenId(Collections.singletonList(assigneeUserId));//只有在微信小程序登陆过用户才会有openid
            Map<Integer, String> openIdMap = list.stream().collect(Collectors.toMap(AdminOauthUserOtherInfoApiVO::getSocialType, AdminOauthUserOtherInfoApiVO::getOpenId));
            try {
                if (workTaskDO != null && StrUtil.isNotEmpty(openIdMap.get(SocialTypeEnum.WECHAT_MINI_APP.getType()))) {
                    SubscribeMessageReqDTO dto = new WxMaMsgTemplateUtils().convertMessageUnreadReminder(new MessageUnreadReminderDTO()
                            .setOpenId(openIdMap.get(SocialTypeEnum.WECHAT_MINI_APP.getType()))
                            .setMsgType(reqDTO.getProcessInstanceName())
                            .setSender(reqDTO.getStartUserNickname())
                            .setComment("你收到了一个新的任务！")
                            .setSendingTime(reqDTO.getCreateTime())
                            .setPage("subPages/task/taskDispose?id=" + workTaskDO.getId())
                            .setMiniProgramState("formal"));
                    subscribeMessageSendApi.sendMaMsg(dto);
                }
                if (workTaskDO == null && StrUtil.isNotEmpty(openIdMap.get(SocialTypeEnum.WECHAT_MP.getType()))) {
                    SubscribeMessageReqDTO dto = new WxMpMsgTemplateUtils().convertProcessToDoReminder(new ProcessToDoReminderDTO()
                            .setOpenId(openIdMap.get(SocialTypeEnum.WECHAT_MP.getType()))
                            .setProcessType("您收到了一条新的待办任务:" + reqDTO.getProcessInstanceName())
                            .setStartUserNickname(reqDTO.getStartUserNickname())
                            .setTime(reqDTO.getCreateTime())
                            .setSchedule(reqDTO.getSchedule())
                            .setMiniProgramState("formal")
                            .setPage("subPagesB/bpm/task/todo/examineApprove?id=" + reqDTO.getProcessInstanceId()));
                    subscribeMessageSendApi.sendMpMsg(dto);
                }
            } catch (Exception e) {
                log.error("发送OA流程待办提醒失败:{}", e.getMessage());
            }
        }
    }

    private String getProcessInstanceDetailUrl(String taskId) {
//        return webProperties.getAdminUi().getUrl() + "/bpm/process-instance/detail?id=" + taskId;
        return webProperties.getAdminUi().getUrl() + "/process-instance/detail?id=" + taskId;
    }

    private List<AdminOauthUserOtherInfoApiVO> getUserOpenId(List<Long> userIds, Integer socialType) {
        return adminOauthUserOtherInfoApi.getOpenIdByCondition(
                new AdminOauthUserOtherInfoApiDTO().setUserIds(userIds)
                        .setSocialType(socialType)).getCheckedData();
    }

    private List<AdminOauthUserOtherInfoApiVO> getUserOpenId(List<Long> userIds) {
        return adminOauthUserOtherInfoApi.getOpenIdByCondition(
                new AdminOauthUserOtherInfoApiDTO().setUserIds(userIds)).getCheckedData();
    }
}
