"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);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NotificationsService = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("../../config");
const entities_1 = require("../../config/database/entities");
const notification_socket_1 = require("../../notification.socket");
const utils_1 = require("../../utils");
let NotificationsService = class NotificationsService {
    constructor(db, gateway) {
        this.db = db;
        this.gateway = gateway;
    }
    buildPaginationDetails(page, limit, total) {
        const totalPages = Math.ceil(total / limit);
        return {
            pagination: {
                total_items: total,
                total_pages: totalPages,
                current_page: page,
                items_per_page: limit,
                has_next_page: page < totalPages,
                has_previous_page: page > 1,
                next_page: page < totalPages ? page + 1 : null,
                previous_page: page > 1 ? page - 1 : null,
            },
        };
    }
    async sendNotification(data) {
        try {
            let memberIds = await this.resolveRecipients({
                owner_id: data.owner_id,
                member_id: data.member_id,
                member_ids: data.member_ids,
                department_ids: data.department_ids,
                roles: data.roles,
                include_admins: data.include_admins,
                include_all_members: data.include_all_members,
            });
            if (data.include_owner && !memberIds.includes(data.owner_id)) {
                memberIds.push(data.owner_id);
            }
            const duration = data.end_time ? (0, utils_1.getDateDuration)(data.end_time, data.start_time) : data.duration || 0;
            const notification = await this.db.notifications.create({
                data: {
                    owner_id: data.owner_id,
                    title: data.title,
                    message: data.message,
                    type: data.type,
                    meta: data.meta,
                    start_time: data?.start_time || new Date(),
                    end_time: data?.end_time || new Date(),
                    duration,
                    source_id: data.reference_id,
                },
            });
            const targets = [];
            if (data.member_id || data.member_ids?.length) {
                targets.push({
                    notification_id: notification.id,
                    target_type: entities_1.NotificationTargetTypeEnum.member,
                    target_value: [
                        ...(data.member_id ? [data.member_id] : []),
                        ...(data.member_ids ?? []),
                    ],
                });
            }
            if (data.department_ids?.length) {
                targets.push({
                    notification_id: notification.id,
                    target_type: entities_1.NotificationTargetTypeEnum.department,
                    target_value: data.department_ids,
                });
            }
            if (data.roles?.length || data.include_admins) {
                targets.push({
                    notification_id: notification.id,
                    target_type: entities_1.NotificationTargetTypeEnum.role,
                    target_value: [
                        ...(data.roles ?? []),
                        ...(data.include_admins ? ['admin'] : []),
                    ],
                });
            }
            if (data.include_all_members) {
                targets.push({
                    notification_id: notification.id,
                    target_type: entities_1.NotificationTargetTypeEnum.all,
                    target_value: null,
                });
            }
            if (targets.length) {
                await this.db.notification_targets.createMany({
                    data: targets,
                });
            }
            let receivers = [];
            if (memberIds.length) {
                await this.db.notification_receivers.createMany({
                    data: memberIds.map((memberId) => ({
                        notification_id: notification.id,
                        member_id: memberId,
                        is_read: false,
                        read_at: new Date(),
                    })),
                });
                receivers = await this.db.notification_receivers.findMany({
                    where: {
                        notification_id: notification.id,
                        member_id: { in: memberIds },
                    },
                    include: {
                        notification: true,
                    },
                });
            }
            setImmediate(() => {
                try {
                    console.log('📤 Emitting notification', {
                        memberIds,
                    });
                    receivers.forEach((receiver) => {
                        if (receiver?.member_id === data.owner_id) {
                            this.gateway.sendToOwner(data.owner_id, receiver);
                        }
                        else {
                            this.gateway.sendToUsers([receiver.member_id], receiver);
                        }
                    });
                }
                catch (err) {
                    config_1.logger.error('Socket emit failed', err);
                }
            });
            return notification;
        }
        catch (err) {
            config_1.logger.error('Notification failed', err);
            console.log('Notification failed', err);
            return null;
        }
    }
    async getNotifications(query, member_id) {
        try {
            const page = query?.page || 1;
            const limit = query.limit || 20;
            const where = {
                member_id: member_id,
                notification: {},
            };
            if (query.start_date || query.end_date) {
                where.notification.created_at = {};
                if (query.start_date) {
                    where.notification.created_at.gte = query.start_date;
                }
                if (query.end_date) {
                    where.notification.created_at.lte = query.end_date;
                }
            }
            const [rows, total] = await Promise.all([
                this.db.notification_receivers.findMany({
                    where,
                    include: {
                        notification: true,
                    },
                    orderBy: {
                        notification: {
                            created_at: 'desc',
                        },
                    },
                    skip: (page - 1) * limit,
                    take: limit,
                }),
                this.db.notification_receivers.count({ where }),
            ]);
            const receivers = await this.db.notification_receivers.findMany({
                where: { member_id },
                include: {
                    notification: true,
                },
            });
            const summary = receivers.reduce((acc, item) => {
                const type = item.notification.type;
                acc.total_notification += 1;
                if (!item.is_read)
                    acc.unread_notification += 1;
                switch (type) {
                    case 'HOLIDAY':
                        acc.holiday_notification++;
                        break;
                    case 'LEAVE':
                        acc.leave_notification++;
                        break;
                    case 'NOTICE':
                        acc.notice_notification++;
                        break;
                    case 'ATTENDANCE':
                        acc.attendance_notification++;
                        break;
                }
                return acc;
            }, {
                total_notification: 0,
                unread_notification: 0,
                holiday_notification: 0,
                leave_notification: 0,
                notice_notification: 0,
                attendance_notification: 0,
            });
            return {
                data: rows,
                details: {
                    ...this.buildPaginationDetails(page, limit, total),
                    summary,
                },
                message: 'Notifications retrieved successfully',
                status: common_1.HttpStatus.OK,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getNotifications: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async markAsRead(data) {
        try {
            const { notification_id, member_id } = data || {};
            const notificationReceiver = await this.db.notification_receivers.findUnique({
                where: {
                    id: notification_id,
                    member_id: member_id,
                },
            });
            if (!notificationReceiver) {
                throw (0, utils_1.createGeneralError)('Notification not found', 'notificationReceiverId', common_1.HttpStatus.NOT_FOUND);
            }
            await this.db.notification_receivers.update({
                where: {
                    id: notification_id,
                },
                data: {
                    is_read: true,
                    read_at: new Date(),
                },
            });
            return {
                data: null,
                status: common_1.HttpStatus.OK,
                message: 'Notification marked as read',
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getLeaves: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async markAllAsRead(memberId) {
        try {
            await this.db.notification_receivers.updateMany({
                where: {
                    member_id: memberId,
                    is_read: false,
                },
                data: {
                    is_read: true,
                    read_at: new Date(),
                },
            });
            console.log(`All notifications marked as read for member ${memberId}`);
            return {
                data: null,
                status: common_1.HttpStatus.OK,
                message: 'All notifications marked as read',
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in markAllAsRead: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async resolveRecipients(params) {
        const recipients = new Set();
        if (params.member_id) {
            recipients.add(params.member_id);
        }
        if (params.member_ids?.length) {
            params.member_ids.forEach((id) => {
                recipients.add(id);
            });
        }
        if (params.department_ids?.length) {
            const departmentMembers = await this.db.members.findMany({
                where: {
                    owner_id: params.owner_id,
                    department_id: {
                        in: params.department_ids,
                    },
                    status: 'active',
                },
                select: {
                    id: true,
                },
            });
            departmentMembers.forEach((member) => {
                recipients.add(member.id);
            });
        }
        if (params.roles?.length) {
            const roleMembers = await this.db.members.findMany({
                where: {
                    owner_id: params.owner_id,
                    role: {
                        in: params.roles,
                    },
                    status: 'active',
                },
                select: {
                    id: true,
                },
            });
            roleMembers.forEach((member) => {
                recipients.add(member.id);
            });
        }
        if (params.include_admins) {
            const admins = await this.db.members.findMany({
                where: {
                    owner_id: params.owner_id,
                    role: 'admin',
                    status: 'active',
                },
                select: {
                    id: true,
                },
            });
            admins.forEach((admin) => {
                recipients.add(admin.id);
            });
        }
        if (params.include_all_members) {
            const members = await this.db.members.findMany({
                where: {
                    owner_id: params.owner_id,
                    status: 'active',
                },
                select: {
                    id: true,
                },
            });
            members.forEach((member) => {
                recipients.add(member.id);
            });
        }
        return Array.from(recipients);
    }
};
exports.NotificationsService = NotificationsService;
exports.NotificationsService = NotificationsService = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [config_1.DatabaseService,
        notification_socket_1.NotificationGateway])
], NotificationsService);
//# sourceMappingURL=notifications.service.js.map