"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var NotificationsService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NotificationsService = void 0;
const common_1 = require("@nestjs/common");
const mongoose_1 = require("@nestjs/mongoose");
const mongoose_2 = require("mongoose");
const notification_schema_1 = require("./schemas/notification.schema");
const student_schema_1 = require("../students/schemas/student.schema");
const teacher_schema_1 = require("../teachers/schemas/teacher.schema");
const section_schema_1 = require("../sections/schemas/section.schema");
const sms_service_1 = require("../common/services/sms.service");
const regex_sanitizer_1 = require("../common/utils/regex-sanitizer");
let NotificationsService = NotificationsService_1 = class NotificationsService {
    notificationModel;
    studentModel;
    teacherModel;
    sectionModel;
    smsService;
    logger = new common_1.Logger(NotificationsService_1.name);
    constructor(notificationModel, studentModel, teacherModel, sectionModel, smsService) {
        this.notificationModel = notificationModel;
        this.studentModel = studentModel;
        this.teacherModel = teacherModel;
        this.sectionModel = sectionModel;
        this.smsService = smsService;
    }
    safeId(val) {
        if (!val)
            return '';
        if (typeof val === 'string')
            return val;
        if (typeof val === 'object' && (val._id || val.id)) {
            return String(val._id || val.id);
        }
        return String(val);
    }
    async validateRecipients(recipientIds) {
        if (!recipientIds || recipientIds.length === 0) {
            return;
        }
        const existingStudents = await this.studentModel
            .find({ _id: { $in: recipientIds } }, { _id: 1 })
            .lean();
        const studentIds = existingStudents.map(s => s._id.toString());
        const existingTeachers = await this.teacherModel
            .find({ _id: { $in: recipientIds } }, { _id: 1 })
            .lean();
        const teacherIds = existingTeachers.map(t => t._id.toString());
        const validIds = new Set([...studentIds, ...teacherIds]);
        const invalidIds = recipientIds.filter(id => !validIds.has(id));
        if (invalidIds.length > 0) {
            throw new common_1.BadRequestException(`${invalidIds.length} recipient ID(s) are invalid or do not exist.`);
        }
    }
    async sendNotification(dto, userId, file) {
        const recipients = Array.isArray(dto.recipients) ? dto.recipients.filter(Boolean) : [];
        const channels = Array.isArray(dto.channels) && dto.channels.length > 0
            ? dto.channels
            : ['web'];
        if (recipients.length > 0) {
            await this.validateRecipients(recipients);
        }
        const record = await this.notificationModel.create({
            subject: dto.subject,
            message: dto.message,
            type: dto.type,
            recipients,
            channels,
            sentBy: userId,
            status: 'sent',
            academicYearId: dto.academicYearId || undefined,
            classId: dto.classId || undefined,
            sectionId: dto.sectionId || undefined,
            fileUrl: file?.fileUrl,
            fileName: file?.fileName,
            fileType: file?.fileType,
            fileSize: file?.fileSize,
        });
        if (channels.includes('sms')) {
            this.sendSmsToRecipients(record.toObject()).catch((err) => this.logger.error(`SMS dispatch failed for notification ${record._id}: ${err?.message}`));
        }
        return record.toObject();
    }
    async sendSmsToRecipients(notification) {
        const phoneNumbers = [];
        const rawSms = `[School Notice] ${notification.subject}\n\n${notification.message}`;
        const smsBody = Array.from(rawSms).slice(0, 1330).join('');
        if (notification.recipients && notification.recipients.length > 0) {
            const students = await this.studentModel
                .find({ _id: { $in: notification.recipients } }, { phone: 1 })
                .limit(5000)
                .lean();
            const teachers = await this.teacherModel
                .find({ _id: { $in: notification.recipients } }, { phone: 1, mobileNumber: 1 })
                .limit(500)
                .lean();
            for (const s of students) {
                if (s.phone)
                    phoneNumbers.push(s.phone);
            }
            for (const t of teachers) {
                const phone = t.phone || t.mobileNumber;
                if (phone)
                    phoneNumbers.push(phone);
            }
        }
        else {
            const query = {};
            if (notification.academicYearId)
                query.academicYearId = notification.academicYearId;
            if (notification.classId)
                query.classId = notification.classId;
            if (notification.sectionId)
                query.sectionId = notification.sectionId;
            if (Object.keys(query).length === 0) {
                this.logger.warn(`Skipping SMS for notification ${notification._id}: no targeting scope set`);
                return;
            }
            const students = await this.studentModel
                .find(query, { phone: 1 })
                .limit(5000)
                .lean();
            for (const s of students) {
                if (s.phone)
                    phoneNumbers.push(s.phone);
            }
        }
        const unique = [...new Set(phoneNumbers)];
        this.logger.log(`Sending SMS to ${unique.length} recipients for notification ${notification._id}`);
        const BATCH_SIZE = 10;
        for (let i = 0; i < unique.length; i += BATCH_SIZE) {
            const batch = unique.slice(i, i + BATCH_SIZE);
            await Promise.allSettled(batch.map((phone) => this.smsService.sendSms(phone, smsBody)));
            if (i + BATCH_SIZE < unique.length) {
                await new Promise((resolve) => setTimeout(resolve, 200));
            }
        }
    }
    async getRecipients(notificationId) {
        const notification = await this.notificationModel.findById(notificationId).lean();
        if (!notification)
            throw new common_1.NotFoundException('Notification not found');
        const result = [];
        if (notification.recipients && notification.recipients.length > 0) {
            const students = await this.studentModel
                .find({ _id: { $in: notification.recipients } }, { name: 1, uniqueId: 1, rollNumber: 1 })
                .limit(5000)
                .lean();
            const teachers = await this.teacherModel
                .find({ _id: { $in: notification.recipients } }, { name: 1, uniqueId: 1 })
                .limit(500)
                .lean();
            for (const s of students) {
                result.push({
                    type: 'Student',
                    id: String(s._id),
                    name: s.name,
                    uniqueId: s.uniqueId || s.rollNumber || '',
                });
            }
            for (const t of teachers) {
                result.push({
                    type: 'Teacher',
                    id: String(t._id),
                    name: t.name,
                    uniqueId: t.uniqueId || '',
                });
            }
            return { recipients: result, total: result.length };
        }
        if (!notification.academicYearId && !notification.classId && !notification.sectionId) {
            return { recipients: [], total: 0 };
        }
        const studentQuery = {};
        if (notification.academicYearId)
            studentQuery.academicYearId = notification.academicYearId;
        if (notification.classId)
            studentQuery.classId = notification.classId;
        if (notification.sectionId)
            studentQuery.sectionId = notification.sectionId;
        const students = await this.studentModel
            .find(studentQuery, { name: 1, uniqueId: 1, rollNumber: 1 })
            .limit(5000)
            .lean();
        for (const s of students) {
            result.push({
                type: 'Student',
                id: String(s._id),
                name: s.name,
                uniqueId: s.uniqueId || s.rollNumber || '',
            });
        }
        if (notification.sectionId) {
            const section = await this.sectionModel
                .findById(notification.sectionId, { assignedTeacherId: 1 })
                .lean();
            if (section?.assignedTeacherId) {
                const teacher = await this.teacherModel
                    .findById(section.assignedTeacherId, { name: 1, uniqueId: 1 })
                    .lean();
                if (teacher) {
                    result.push({
                        type: 'Teacher',
                        id: String(teacher._id),
                        name: teacher.name,
                        uniqueId: teacher.uniqueId || '',
                    });
                }
            }
        }
        else if (notification.classId) {
            const sections = await this.sectionModel
                .find({ classId: notification.classId }, { assignedTeacherId: 1 })
                .lean();
            const teacherIds = sections
                .map((s) => s.assignedTeacherId)
                .filter(Boolean);
            if (teacherIds.length > 0) {
                const teachers = await this.teacherModel
                    .find({ _id: { $in: teacherIds } }, { name: 1, uniqueId: 1 })
                    .limit(500)
                    .lean();
                for (const t of teachers) {
                    result.push({
                        type: 'Teacher',
                        id: String(t._id),
                        name: t.name,
                        uniqueId: t.uniqueId || '',
                    });
                }
            }
        }
        return { recipients: result, total: result.length };
    }
    async findAll() {
        return this.notificationModel.find().sort({ updatedAt: -1, createdAt: -1 }).limit(500).lean({ virtuals: true });
    }
    async findOne(id) {
        return this.notificationModel.findById(id).lean({ virtuals: true });
    }
    async update(id, dto, file) {
        const updateData = {};
        if (dto.subject !== undefined)
            updateData.subject = dto.subject;
        if (dto.message !== undefined)
            updateData.message = dto.message;
        if (dto.type !== undefined)
            updateData.type = dto.type;
        if (dto.recipients !== undefined) {
            const recipients = Array.isArray(dto.recipients) ? dto.recipients.filter(Boolean) : [];
            if (recipients.length > 0) {
                await this.validateRecipients(recipients);
            }
            updateData.recipients = recipients;
        }
        if (dto.academicYearId !== undefined)
            updateData.academicYearId = dto.academicYearId || undefined;
        if (dto.classId !== undefined)
            updateData.classId = dto.classId || undefined;
        if (dto.sectionId !== undefined)
            updateData.sectionId = dto.sectionId || undefined;
        if (file) {
            updateData.fileUrl = file.fileUrl;
            updateData.fileName = file.fileName;
            updateData.fileType = file.fileType;
            updateData.fileSize = file.fileSize;
        }
        updateData.updatedAt = new Date();
        const updated = await this.notificationModel.findByIdAndUpdate(id, { $set: updateData }, { new: true, timestamps: true }).lean({ virtuals: true });
        if (!updated) {
            throw new common_1.NotFoundException('Notification not found');
        }
        this.logger.log(`Notification ${id} updated successfully at ${updateData.updatedAt.toISOString()}`);
        return updated;
    }
    async delete(id) {
        const result = await this.notificationModel.findByIdAndDelete(id);
        if (!result) {
            throw new common_1.NotFoundException('Notification not found');
        }
        return { message: 'Notification deleted successfully' };
    }
    async filter(filters) {
        const query = {};
        if (filters.type)
            query.type = filters.type;
        if (filters.status)
            query.status = filters.status;
        if (filters.sentBy)
            query.sentBy = filters.sentBy;
        if (filters.academicYearId)
            query.academicYearId = filters.academicYearId;
        if (filters.classId)
            query.classId = filters.classId;
        if (filters.sectionId)
            query.sectionId = filters.sectionId;
        if (filters.dateFrom || filters.dateTo) {
            query.createdAt = {};
            if (filters.dateFrom) {
                const from = new Date(filters.dateFrom);
                if (!isNaN(+from))
                    query.createdAt.$gte = from;
            }
            if (filters.dateTo) {
                const to = new Date(filters.dateTo);
                if (!isNaN(+to)) {
                    if (/^\d{4}-\d{2}-\d{2}$/.test(filters.dateTo)) {
                        to.setHours(23, 59, 59, 999);
                    }
                    query.createdAt.$lte = to;
                }
            }
            if (Object.keys(query.createdAt).length === 0)
                delete query.createdAt;
        }
        if (filters.q) {
            const sanitizedQuery = (0, regex_sanitizer_1.escapeRegex)(filters.q);
            query.$or = [
                { $text: { $search: filters.q } },
                { subject: { $regex: sanitizedQuery, $options: 'i' } },
                { message: { $regex: sanitizedQuery, $options: 'i' } },
            ];
        }
        if (filters.hasFile === 'true') {
            query.fileUrl = { $exists: true, $ne: null, $nin: ['', null] };
        }
        else if (filters.hasFile === 'false') {
            query.$and = [
                ...(query.$and || []),
                {
                    $or: [
                        { fileUrl: { $exists: false } },
                        { fileUrl: null },
                        { fileUrl: '' },
                    ],
                },
            ];
        }
        return this.notificationModel.find(query).sort({ updatedAt: -1, createdAt: -1 }).limit(500).lean({ virtuals: true });
    }
    async getRecent(limit = 5, academicYearId) {
        const n = Math.max(1, Math.min(Number(limit) || 5, 25));
        const query = {};
        if (academicYearId) {
            query.academicYearId = academicYearId;
        }
        return this.notificationModel
            .find(query, { subject: 1, createdAt: 1, updatedAt: 1 })
            .sort({ updatedAt: -1, createdAt: -1 })
            .limit(n)
            .lean({ virtuals: true });
    }
    async getForStudent(studentId, limit = 5, ayOverride) {
        const n = Math.max(1, Math.min(Number(limit) || 5, 100));
        const student = await this.studentModel
            .findById(studentId, { classId: 1, sectionId: 1, academicYearId: 1 })
            .lean();
        const selectedAY = ayOverride || student?.academicYearId || null;
        const cls = student?.classId || null;
        const sec = student?.sectionId || null;
        const query = {
            type: 'web',
            status: 'sent',
            dismissedBy: { $ne: studentId },
            $or: [
                { recipients: studentId },
                {
                    $and: [
                        { $or: [{ recipients: { $exists: false } }, { recipients: { $size: 0 } }] },
                        { $or: [{ academicYearId: { $exists: false } }, { academicYearId: selectedAY }] },
                        { $or: [{ classId: { $exists: false } }, { classId: cls }] },
                        { $or: [{ sectionId: { $exists: false } }, { sectionId: sec }] },
                    ],
                },
            ],
        };
        const notifications = await this.notificationModel
            .find(query)
            .sort({ updatedAt: -1, createdAt: -1 })
            .limit(n)
            .lean({ virtuals: true });
        return notifications.map((notification) => {
            const { readBy, dismissedBy, recipients, ...rest } = notification;
            return { ...rest, isRead: readBy?.includes(studentId) || false };
        });
    }
    async getForTeacher(teacherId, limit = 5, ayOverride) {
        const n = Math.max(1, Math.min(Number(limit) || 5, 100));
        const sections = await this.sectionModel
            .find({ assignedTeacherId: teacherId }, { _id: 1, classId: 1 })
            .lean();
        const sectionIds = sections.map((s) => this.safeId(s._id));
        const classIds = sections.map((s) => this.safeId(s.classId)).filter(Boolean);
        const globalClause = {
            $and: [
                { academicYearId: { $exists: false } },
                { classId: { $exists: false } },
                { sectionId: { $exists: false } },
            ],
        };
        const orClauses = sectionIds.length === 0 && classIds.length === 0
            ? [globalClause]
            : [globalClause, { classId: { $in: classIds } }, { sectionId: { $in: sectionIds } }];
        const baseQuery = {
            $and: [{ $or: orClauses }],
        };
        if (ayOverride) {
            baseQuery.$and.push({ $or: [{ academicYearId: { $exists: false } }, { academicYearId: ayOverride }] });
        }
        const query = {
            type: 'web',
            status: 'sent',
            dismissedBy: { $ne: teacherId },
            $or: [
                { recipients: teacherId },
                {
                    $and: [
                        { $or: [{ recipients: { $exists: false } }, { recipients: { $size: 0 } }] },
                        ...baseQuery.$and,
                    ],
                },
            ],
        };
        const notifications = await this.notificationModel
            .find(query)
            .sort({ updatedAt: -1, createdAt: -1 })
            .limit(n)
            .lean({ virtuals: true });
        return notifications.map((notification) => {
            const { readBy, dismissedBy, recipients, ...rest } = notification;
            return { ...rest, isRead: readBy?.includes(teacherId) || false };
        });
    }
    async canUserAccessNotification(notificationId, userId, role, ayOverride) {
        const notification = await this.notificationModel.findById(notificationId).lean();
        if (!notification) {
            return false;
        }
        if (role.toLowerCase() === 'admin') {
            return true;
        }
        if (notification.type !== 'web' || notification.status !== 'sent') {
            return false;
        }
        if (notification.recipients && notification.recipients.length > 0) {
            if (notification.recipients.includes(userId)) {
                return true;
            }
            return false;
        }
        if (role.toLowerCase() === 'student') {
            const student = await this.studentModel
                .findById(userId, { classId: 1, sectionId: 1, academicYearId: 1 })
                .lean();
            if (!student) {
                return false;
            }
            const selectedAY = ayOverride || student.academicYearId || null;
            const cls = student.classId || null;
            const sec = student.sectionId || null;
            const ayMatch = !notification.academicYearId || notification.academicYearId === selectedAY;
            const classMatch = !notification.classId || notification.classId === cls;
            const sectionMatch = !notification.sectionId || notification.sectionId === sec;
            return ayMatch && classMatch && sectionMatch;
        }
        else if (role.toLowerCase() === 'teacher') {
            const sections = await this.sectionModel
                .find({ assignedTeacherId: userId }, { _id: 1, classId: 1 })
                .lean();
            const sectionIds = sections.map((s) => this.safeId(s._id));
            const classIds = sections.map((s) => this.safeId(s.classId)).filter(Boolean);
            const isGlobal = !notification.academicYearId && !notification.classId && !notification.sectionId;
            if (isGlobal) {
                return true;
            }
            if (notification.sectionId && sectionIds.includes(String(notification.sectionId))) {
                return true;
            }
            if (notification.classId && classIds.includes(String(notification.classId))) {
                return true;
            }
            if (!notification.classId && !notification.sectionId && ayOverride && notification.academicYearId) {
                return notification.academicYearId === ayOverride;
            }
            return false;
        }
        return false;
    }
    async getUnreadCount(userId, role, ayOverride) {
        if (role.toLowerCase() === 'admin') {
            return { count: 0 };
        }
        let query;
        if (role.toLowerCase() === 'student') {
            const student = await this.studentModel
                .findById(userId, { classId: 1, sectionId: 1, academicYearId: 1 })
                .lean();
            const selectedAY = ayOverride || student?.academicYearId || null;
            const cls = student?.classId || null;
            const sec = student?.sectionId || null;
            query = {
                type: 'web',
                status: 'sent',
                readBy: { $ne: userId },
                dismissedBy: { $ne: userId },
                $or: [
                    { recipients: userId },
                    {
                        $and: [
                            { $or: [{ recipients: { $exists: false } }, { recipients: { $size: 0 } }] },
                            { $or: [{ academicYearId: { $exists: false } }, { academicYearId: selectedAY }] },
                            { $or: [{ classId: { $exists: false } }, { classId: cls }] },
                            { $or: [{ sectionId: { $exists: false } }, { sectionId: sec }] },
                        ],
                    },
                ],
            };
        }
        else if (role.toLowerCase() === 'teacher') {
            const sections = await this.sectionModel
                .find({ assignedTeacherId: userId }, { _id: 1, classId: 1 })
                .lean();
            const sectionIds = sections.map((s) => this.safeId(s._id));
            const classIds = sections.map((s) => this.safeId(s.classId)).filter(Boolean);
            const globalClause = {
                $and: [
                    { academicYearId: { $exists: false } },
                    { classId: { $exists: false } },
                    { sectionId: { $exists: false } },
                ],
            };
            const orClauses = sectionIds.length === 0 && classIds.length === 0
                ? [globalClause]
                : [globalClause, { classId: { $in: classIds } }, { sectionId: { $in: sectionIds } }];
            const baseQuery = {
                $and: [{ $or: orClauses }],
            };
            if (ayOverride) {
                baseQuery.$and.push({ $or: [{ academicYearId: { $exists: false } }, { academicYearId: ayOverride }] });
            }
            query = {
                type: 'web',
                status: 'sent',
                readBy: { $ne: userId },
                dismissedBy: { $ne: userId },
                $or: [
                    { recipients: userId },
                    {
                        $and: [
                            { $or: [{ recipients: { $exists: false } }, { recipients: { $size: 0 } }] },
                            ...baseQuery.$and,
                        ],
                    },
                ],
            };
        }
        else {
            return { count: 0 };
        }
        const count = await this.notificationModel.countDocuments(query);
        return { count };
    }
    async markAsRead(notificationId, userId) {
        const result = await this.notificationModel.findByIdAndUpdate(notificationId, { $addToSet: { readBy: userId } }, { new: true });
        if (!result) {
            throw new common_1.NotFoundException('Notification not found');
        }
        return { message: 'Notification marked as read' };
    }
    async markAllAsRead(userId, role, ayOverride) {
        let query;
        if (role.toLowerCase() === 'student') {
            const student = await this.studentModel
                .findById(userId, { classId: 1, sectionId: 1, academicYearId: 1 })
                .lean();
            const selectedAY = ayOverride || student?.academicYearId || null;
            const cls = student?.classId || null;
            const sec = student?.sectionId || null;
            query = {
                type: 'web',
                status: 'sent',
                readBy: { $ne: userId },
                dismissedBy: { $ne: userId },
                $or: [
                    { recipients: userId },
                    {
                        $and: [
                            { $or: [{ recipients: { $exists: false } }, { recipients: { $size: 0 } }] },
                            { $or: [{ academicYearId: { $exists: false } }, { academicYearId: selectedAY }] },
                            { $or: [{ classId: { $exists: false } }, { classId: cls }] },
                            { $or: [{ sectionId: { $exists: false } }, { sectionId: sec }] },
                        ],
                    },
                ],
            };
        }
        else if (role.toLowerCase() === 'teacher') {
            const sections = await this.sectionModel
                .find({ assignedTeacherId: userId }, { _id: 1, classId: 1 })
                .lean();
            const sectionIds = sections.map((s) => this.safeId(s._id));
            const classIds = sections.map((s) => this.safeId(s.classId)).filter(Boolean);
            const globalClause = {
                $and: [
                    { academicYearId: { $exists: false } },
                    { classId: { $exists: false } },
                    { sectionId: { $exists: false } },
                ],
            };
            const orClauses = sectionIds.length === 0 && classIds.length === 0
                ? [globalClause]
                : [globalClause, { classId: { $in: classIds } }, { sectionId: { $in: sectionIds } }];
            const baseQuery = {
                $and: [{ $or: orClauses }],
            };
            if (ayOverride) {
                baseQuery.$and.push({ $or: [{ academicYearId: { $exists: false } }, { academicYearId: ayOverride }] });
            }
            query = {
                type: 'web',
                status: 'sent',
                readBy: { $ne: userId },
                dismissedBy: { $ne: userId },
                $or: [
                    { recipients: userId },
                    {
                        $and: [
                            { $or: [{ recipients: { $exists: false } }, { recipients: { $size: 0 } }] },
                            ...baseQuery.$and,
                        ],
                    },
                ],
            };
        }
        else {
            return { message: 'No notifications to mark as read' };
        }
        await this.notificationModel.updateMany(query, {
            $addToSet: { readBy: userId },
        });
        return { message: 'All notifications marked as read' };
    }
    async dismiss(notificationId, userId) {
        const result = await this.notificationModel.findByIdAndUpdate(notificationId, { $addToSet: { dismissedBy: userId, readBy: userId } }, { new: true });
        if (!result) {
            throw new common_1.NotFoundException('Notification not found');
        }
        return { message: 'Notification dismissed' };
    }
    async dismissAll(userId, role, ayOverride) {
        let query;
        if (role.toLowerCase() === 'student') {
            const student = await this.studentModel
                .findById(userId, { classId: 1, sectionId: 1, academicYearId: 1 })
                .lean();
            const selectedAY = ayOverride || student?.academicYearId || null;
            const cls = student?.classId || null;
            const sec = student?.sectionId || null;
            query = {
                type: 'web',
                status: 'sent',
                dismissedBy: { $ne: userId },
                $or: [
                    { recipients: userId },
                    {
                        $and: [
                            { $or: [{ recipients: { $exists: false } }, { recipients: { $size: 0 } }] },
                            { $or: [{ academicYearId: { $exists: false } }, { academicYearId: selectedAY }] },
                            { $or: [{ classId: { $exists: false } }, { classId: cls }] },
                            { $or: [{ sectionId: { $exists: false } }, { sectionId: sec }] },
                        ],
                    },
                ],
            };
        }
        else if (role.toLowerCase() === 'teacher') {
            const sections = await this.sectionModel
                .find({ assignedTeacherId: userId }, { _id: 1, classId: 1 })
                .lean();
            const sectionIds = sections.map((s) => this.safeId(s._id));
            const classIds = sections.map((s) => this.safeId(s.classId)).filter(Boolean);
            const globalClause = {
                $and: [
                    { academicYearId: { $exists: false } },
                    { classId: { $exists: false } },
                    { sectionId: { $exists: false } },
                ],
            };
            const orClauses = sectionIds.length === 0 && classIds.length === 0
                ? [globalClause]
                : [globalClause, { classId: { $in: classIds } }, { sectionId: { $in: sectionIds } }];
            const baseQuery = {
                $and: [{ $or: orClauses }],
            };
            if (ayOverride) {
                baseQuery.$and.push({ $or: [{ academicYearId: { $exists: false } }, { academicYearId: ayOverride }] });
            }
            query = {
                type: 'web',
                status: 'sent',
                dismissedBy: { $ne: userId },
                $or: [
                    { recipients: userId },
                    {
                        $and: [
                            { $or: [{ recipients: { $exists: false } }, { recipients: { $size: 0 } }] },
                            ...baseQuery.$and,
                        ],
                    },
                ],
            };
        }
        else {
            return { message: 'No notifications to dismiss' };
        }
        await this.notificationModel.updateMany(query, {
            $addToSet: { dismissedBy: userId, readBy: userId },
        });
        return { message: 'All notifications dismissed' };
    }
};
exports.NotificationsService = NotificationsService;
exports.NotificationsService = NotificationsService = NotificationsService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, mongoose_1.InjectModel)(notification_schema_1.Notification.name)),
    __param(1, (0, mongoose_1.InjectModel)(student_schema_1.Student.name)),
    __param(2, (0, mongoose_1.InjectModel)(teacher_schema_1.Teacher.name)),
    __param(3, (0, mongoose_1.InjectModel)(section_schema_1.Section.name)),
    __metadata("design:paramtypes", [mongoose_2.Model,
        mongoose_2.Model,
        mongoose_2.Model,
        mongoose_2.Model,
        sms_service_1.SmsService])
], NotificationsService);
//# sourceMappingURL=notifications.service.js.map