package com.srs.flowable.listener.outsideAccommodation;

import com.srs.common.core.domain.entity.SysUser;
import com.srs.common.doman.vo.TeacherVo;
import com.srs.common.utils.DateUtils;
import com.srs.common.utils.SecurityUtils;
import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
import com.srs.dormitory.domain.DmsOutsideAccommodationApply;
import com.srs.flowable.domain.EnlistmentReserve;
import com.srs.flowable.domain.NotificationManage;
import com.srs.flowable.domain.OutsideAccommodationApply;
import com.srs.flowable.mapper.EnlistmentReserveMapper;
import com.srs.flowable.mapper.LeaveMapper;
import com.srs.flowable.mapper.OutsideAccommodationApplyMapper;
import com.srs.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.engine.RepositoryService;
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.List;


/**
 * 审批流程负责人自动流转监听器
 * 用于节点审批之前时，更新下一个节点的负责人变量(approval)
 */
@Component("OutsideAccommodationStartListener") // Spring Bean名称，与BPMN表达式对应
@Slf4j
public class OutsideAccommodationStartListener implements ExecutionListener {

    @Autowired
    private ISysUserService sysUserService; // 用户服务（查询部门/学院负责人）

    // 用于查询流程定义中的节点信息
    @Autowired
    private RepositoryService repositoryService;

    @Override
    public void notify(DelegateExecution execution) {
        // 1. 获取当前节点ID和流程定义ID
        String currentActivityId = execution.getCurrentActivityId(); // 当前节点ID（兼容所有版本）
        String processDefinitionId = execution.getProcessDefinitionId(); // 流程定义ID

        // 2. 根据节点ID查询节点名称（通过流程定义获取名称）
        String currentNodeName = getNodeNameByActivityId(processDefinitionId, currentActivityId);
        if (currentNodeName == null) {
            throw new RuntimeException("未找到节点ID=" + currentActivityId + "的名称");
        }

        // 获取申请表id
        Long accommodationId = Long.valueOf(execution.getVariable("accommodationId").toString());


        // 后续逻辑不变：查询下一个节点负责人并更新变量
        Long nextAssigneeId = getNextAssignee(currentNodeName, accommodationId);
        if (nextAssigneeId != null) {
            execution.setVariable("approval", nextAssigneeId);
            execution.setVariable("currentNode", currentNodeName);
            // ========== 外宿申请审批通知逻辑 ==========
            sendOutsideAccommodationNotification(execution, currentNodeName, nextAssigneeId, accommodationId);
        }
    }

    /**
     * 根据节点ID和流程定义ID，查询节点名称（兼容所有版本的核心方法）
     */
    private String getNodeNameByActivityId(String processDefinitionId, String activityId) {
        // 获取流程模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        if (bpmnModel == null) {
            throw new RuntimeException("未找到流程定义ID=" + processDefinitionId + "的模型");
        }

        // 从模型中获取节点信息（FlowNode包含用户任务、网关等节点）
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(activityId);
        return flowNode != null ? flowNode.getName() : null;
    }

    /**
     * 根据当前节点查询下一个节点的负责人
     */
    private Long getNextAssignee(String currentNodeName, Long accommodationId) {
        OutsideAccommodationApplyMapper outsideAccommodationApplyMapper = SpringUtils.getBean(OutsideAccommodationApplyMapper.class);
        // 根据Id查询外宿申请记录
        OutsideAccommodationApply outsideAccommodationApply = outsideAccommodationApplyMapper.selectDmsOutsideAccommodationApplyById(accommodationId);
        // 根据学生学号来获取对应辅导员的信息
        TeacherVo counselorInfo = outsideAccommodationApplyMapper.getCounselorInfo(outsideAccommodationApply.getStudentNo());
        // 获取辅导员的部门id
        Long currentDeptId = counselorInfo.getDeptId();
        if (currentDeptId == null) {
            throw new RuntimeException("未分配部门，无法匹配负责人");
        }
        // 注意：节点名称需与BPMN模型中完全一致（区分大小写）
        switch (currentNodeName) {
            case "辅导员审批":
                // 辅导员开始审批前 → 找到对应辅导员
                // 返回匹配的辅导员用户ID（作为当前节点负责人）
                return counselorInfo.getUserId();

            case "二级学院书记审批":

                // 二级学院书记开始审批前 → 找到对应二级学院书记
                // 查询角色ID=106（二级学院书记）的所有用户
                SysUser queryUser = new SysUser();
                queryUser.setRoleId(106L); // 二级学院书记角色固定ID
                List<SysUser> academicAffairsUsers = sysUserService.selectAllocatedList(queryUser);
                if (academicAffairsUsers.isEmpty()) {
                    throw new RuntimeException("未查询到角色（二级学院书记）的用户");
                }

                // 从学务用户中筛选出部门ID与当前二级学院书记部门一致的用户
                SysUser targetAcademic = academicAffairsUsers.stream()
                        .filter(user -> currentDeptId.equals(user.getDeptId())) // 部门ID匹配
                        .findFirst() // 取第一个匹配的二级学院书记（若有多个，可根据排序或优先级调整）
                        .orElseThrow(() -> new RuntimeException("未找到部门ID=" + currentDeptId + "的二级学院书记负责人"));


                // 返回匹配的二级学院书记用户ID（作为当前节点负责人）
                return targetAcademic.getUserId();

            case "学工处审批":

                // 学工处审批前 → 找到对应学工处
                // 查询角色ID=100（学工处）的所有用户
                SysUser qUser = new SysUser();
                qUser.setRoleId(100L); // 学工处角色固定ID=100
                List<SysUser> collegeUsers = sysUserService.selectAllocatedList(qUser);
                if (collegeUsers.isEmpty()) {
                    throw new RuntimeException("未查询到角色（学工处）的用户");
                }

                // 筛选出部门ID（学院ID）与登录用户所属学院一致的学工处负责人
                SysUser targetCollegeLeader = collegeUsers.stream()
                        .filter(user -> currentDeptId.equals(user.getDeptId())) // 学院ID匹配（部门ID即学院ID）
                        .findFirst()
                        // 找不到匹配的则取列表第二个用户
                        .orElse(collegeUsers.get(2));
                        //.orElseThrow(() -> new RuntimeException("未找到学院ID=" + currentDeptId + "的学工处负责人"));


                // 返回匹配的学工处负责人ID
                return targetCollegeLeader.getUserId();

            case "学校领导审批":
                // 学校领导审批前 → 找到对应学校领导
                // 查询角色ID=107（学校领导）的所有用户
                SysUser sysUser = new SysUser();
                sysUser.setRoleId(107L); // 学校领导角色固定ID=107
                List<SysUser> sysUsers = sysUserService.selectAllocatedList(sysUser);
                if (sysUsers.isEmpty()) {
                    throw new RuntimeException("未查询到角色（学校领导）的用户");
                }

                // 筛选出部门ID（学院ID）与登录用户所属学院一致的学校领导负责人
                // 改造：findFirst() 找不到则取列表第一个，而非直接抛异常
                SysUser userByDeptId = sysUsers.stream()
                        .filter(user -> currentDeptId.equals(user.getDeptId())) // 学院ID匹配（部门ID即学院ID）
                        .findFirst()
                        // 找不到匹配的则取列表第一个用户
                        .orElse(sysUsers.get(0));

                // 兜底校验（防止极端情况，理论上sysUsers非空，sysUsers.get(0)不会为null）
                if (userByDeptId == null) {
                    throw new RuntimeException("学校领导用户数据异常，无可用负责人");
                }

                // 返回匹配的学校领导负责人ID（优先匹配学院，无匹配则取第一个）
                return userByDeptId.getUserId();

            default:
                throw new RuntimeException("未配置节点[" + currentNodeName + "]的当前负责人规则");
        }
    }
    /**
     * 发送外宿申请审批通知（系统通知+企业微信通知）
     */
    private void sendOutsideAccommodationNotification(DelegateExecution execution, String currentNodeName,
                                                      Long nextAssigneeId, Long accommodationId) {
        try {
            // 获取需要的Mapper和工具类
            OutsideAccommodationApplyMapper outsideAccommodationApplyMapper = SpringUtils.getBean(OutsideAccommodationApplyMapper.class);
            LeaveMapper leaveMapper = (LeaveMapper) SpringUtils.getBean("leaveMapper");
            WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);

            // 1. 查询外宿申请详情
            com.srs.flowable.domain.OutsideAccommodationApply outsideAccommodationApply = outsideAccommodationApplyMapper.selectDmsOutsideAccommodationApplyById(accommodationId);
            if (outsideAccommodationApply == null) {
                log.warn("未找到外宿申请记录，ID:{}", accommodationId);
                return;
            }

            // 2. 查询下一个审批人的信息（获取用户名/工号）
            SysUser nextApprover = sysUserService.selectUserById(nextAssigneeId);
            if (nextApprover == null) {
                log.warn("未找到审批人信息，用户ID:{}", nextAssigneeId);
                return;
            }
            String approverUserName = nextApprover.getUserName(); // 审批人工号/用户名
            String approverName = nextApprover.getNickName(); // 审批人姓名

            log.info("开始发送【外宿申请审批】通知，审批节点：{}，审批人：{}({})",
                    currentNodeName, approverName, approverUserName);

            // 3. 处理系统通知（先删后加，避免重复通知）
            NotificationManage notificationManage = new NotificationManage();
            notificationManage.setContent(String.format("您有一条【外宿申请审批】待处理（节点：%s）", currentNodeName));
            notificationManage.setReceiver(nextAssigneeId); // 接收人：下一个审批人

            // 3.1 查询是否已有相同通知，有则删除
            NotificationManage existNotify = leaveMapper.selectCphMsgListForFlowable(notificationManage);
            if (existNotify != null) {
                int delRes = leaveMapper.deleteCphMsgById(existNotify.getId());
                log.info("删除重复的系统通知，通知ID:{}，删除结果:{}", existNotify.getId(), delRes);
            }

            // 3.2 添加新的系统通知
            notificationManage.setSender(SecurityUtils.getUserId() != null ? SecurityUtils.getUserId() : 0L); // 发送人：当前操作人（兜底处理）
            notificationManage.setCreateTime(DateUtils.getNowDate()); // 创建时间
            int addRes = leaveMapper.insertCphMsg(notificationManage);
            log.info("新增系统通知成功，接收人ID:{}，添加结果:{}", nextAssigneeId, addRes);

            // 4. 企业微信推送消息
            if (approverUserName != null && !approverUserName.isEmpty()) {
                // 构造带超链接的消息内容
                String weChatContent = String.format(
                        "您有一条【外宿申请审批】待处理（节点：%s），<a href='https://zhxg.gxsdxy.cn/wab/#/pages/Approval/index'>请点击前往处理</a>",
                        currentNodeName
                );

                // 发送企业微信文本消息
                weChatUtil.sendTextMessage(approverUserName, weChatContent);
                log.info("企业微信通知发送成功，接收人工号:{}，节点:{}", approverUserName, currentNodeName);
            } else {
                log.warn("审批人工号为空，无法发送企业微信通知，用户ID:{}", nextAssigneeId);
            }

            // ========== 删除当前审批人的待处理通知 ==========
            // 4.1 获取当前审批人ID（当前操作人=已完成审批的人）
            Long currentApproverId = SecurityUtils.getUserId();
            if (currentApproverId == null) {
                log.warn("当前审批人ID为空，无法删除其待处理通知");
                return;
            }

            // 4.2 构造当前审批人的待处理通知查询条件
            NotificationManage currentNotifyQuery = new NotificationManage();
            // 内容匹配：当前节点的待处理通知（关键词+节点名称）
            currentNotifyQuery.setContent(String.format("您有一条【外宿申请审批】待处理（节点：%s）", currentNodeName));
            currentNotifyQuery.setReceiver(currentApproverId); // 接收人=当前审批人

            // 4.3 查询当前审批人的该节点待处理通知
            NotificationManage currentExistNotify = leaveMapper.selectCphMsgListForFlowable(currentNotifyQuery);
            if (currentExistNotify != null) {
                // 4.4 删除该通知（清理已处理的待办）
                int currentDelRes = leaveMapper.deleteCphMsgById(currentExistNotify.getId());
                log.info("删除当前审批人({})的【{}】待处理通知，通知ID:{}，删除结果:{}",
                        currentApproverId, currentNodeName, currentExistNotify.getId(), currentDelRes);
            } else {
                log.info("当前审批人({})无【{}】节点的待处理通知，无需删除", currentApproverId, currentNodeName);
            }

        } catch (Exception e) {
            // 捕获所有异常，仅记录日志，不影响主流程
            log.error("发送外宿申请审批通知失败，节点：{}，审批人ID：{}，错误信息：{}",
                    currentNodeName, nextAssigneeId, e.getMessage(), e);
        }
    }
}