package com.srs.flowable.listener.disciplinary; // 您可以根据需要调整包路径

import com.srs.common.utils.SecurityUtils;
import com.srs.comprehensive.domain.CphMsg;
import com.srs.comprehensive.service.ICphMsgService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;

/**
 * 为即将到来的任务创建内部“我的消息”记录。  知无涯
 * <p>
 * 该监听器被设计为在SequenceFlow的'take'事件上触发。
 * 它会智能地从流程变量中读取单个接收人(变量名: approval)或多个接收人(变量名: userList)，
 * 然后为每一位接收人创建一条内部消息。
 * </p>
 */
@Component("genericMessageListener")
@Slf4j
public class GenericMessageListener implements ExecutionListener {

    @Autowired
    private ICphMsgService cphMsgService;

    @Override
    public void notify(DelegateExecution execution) {
        log.info("流程实例 [{}]: 触发通用消息监听器...", execution.getProcessInstanceId());

        List<Long> receiverIdList = getReceiverIds(execution);
        if (receiverIdList.isEmpty()) {
            return;
        }

        // --- 关键改动：获取下一个即将创建的任务ID ---
        // 注意：在线上监听器中，任务尚未创建，所以我们无法直接获取任务ID。
        // 但我们可以获取到这个“活动”的定义ID，它在流程定义中是唯一的。
        String activityId = execution.getCurrentActivityId();

        String taskName = execution.getCurrentFlowElement() != null ? execution.getCurrentFlowElement().getName() : "新";

        // --- 关键改动：构建带有隐藏标识的消息内容 ---
        String messageText = "您有一条新的【" + taskName + "】待办任务需要处理";
        // 我们嵌入一个隐藏的span，它包含了流程实例ID和活动ID作为唯一标识
        String hiddenIdentifier = String.format("<span id='flow-identifier' data-proc-inst-id='%s' data-activity-id='%s' style='display:none;'></span>",
                execution.getProcessInstanceId(),
                activityId);

        String finalContent = messageText + hiddenIdentifier;

        Long senderId = getSenderId();

        for (Long receiverId : receiverIdList) {
            try {
                CphMsg cphMsg = new CphMsg();
                cphMsg.setReceiver(receiverId);
                cphMsg.setSender(senderId);
                cphMsg.setContent(finalContent); // 使用包含隐藏标识的内容

                cphMsgService.insertCphMsg(cphMsg);
                log.info("已成功为用户 [{}] 创建内部消息 (关联 Activity ID: {})。", receiverId, activityId);
            } catch (Exception e) {
                log.error("为用户 [{}] 创建内部消息时发生异常: {}", receiverId, e.getMessage(), e);
            }
        }
    }

    /**
     * 智能地从流程变量中解析出接收人ID列表。
     * 策略是：
     * 1. 优先检查 'userList' 变量，这通常用于多实例任务。
     * 2. 如果 'userList' 不存在或无效，则检查 'approval' 变量，这通常用于单实例任务。
     *
     * @param execution 当前的执行实例
     * @return 包含一个或多个用户ID的列表，如果都找不到则返回空列表。
     */
    @SuppressWarnings("unchecked")
    private List<Long> getReceiverIds(DelegateExecution execution) {
        // 优先检查 'userList' (用于多实例)
        Object userListObj = execution.getVariable("userList");
        if (userListObj instanceof List && !((List<?>) userListObj).isEmpty()) {
            try {
                // 确保列表内容是Long类型
                return (List<Long>) userListObj;
            } catch (ClassCastException e) {
                log.error("流程变量 'userList' 不是 Long 类型的列表。", e);
            }
        }

        // 其次检查 'approval' (用于单实例)
        Object approvalObj = execution.getVariable("approval");
        if (approvalObj instanceof Number) {
            return Collections.singletonList(((Number) approvalObj).longValue());
        }
        // 兼容字符串形式的ID
        if (approvalObj instanceof String) {
            try {
                return Collections.singletonList(Long.parseLong((String) approvalObj));
            } catch (NumberFormatException e) {
                log.warn("流程变量 'approval' 的值 '{}' 无法转换为Long类型。", approvalObj);
            }
        }

        // 如果都找不到，返回一个不可变的空列表
        return Collections.emptyList();
    }

    /**
     * 安全地获取当前操作的发送人ID。
     * 在异步执行的监听器中，可能无法获取到安全上下文，因此提供了默认值。
     *
     * @return 发送人用户ID，默认为1L (系统管理员)。
     */
    private Long getSenderId() {
        try {
            Long userId = SecurityUtils.getUserId();
            // 如果SecurityUtils返回null，也使用默认值
            return userId != null ? userId : 1L;
        } catch (Exception e) {
            log.warn("在监听器中获取发送人ID时发生异常，将使用默认系统管理员ID(1L)。异常信息: {}", e.getMessage());
            return 1L; // 默认为系统管理员
        }
    }
}