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);
};
import logger from "../Utils/Logger";
import CallService from "./CallService";
import DatabaseService from "./DatabaseService";
import MailService from "./MailService";
import ProjectCallSMSConfigService from "./ProjectCallSMSConfigService";
import SmsService from "./SmsService";
import TeamMemberService from "./TeamMemberService";
import TelegramService from "./TelegramService";
import UserCallService from "./UserCallService";
import UserEmailService from "./UserEmailService";
import UserSmsService from "./UserSmsService";
import PushNotificationService from "./PushNotificationService";
import UserTelegramService from "./UserTelegramService";
import UserWebhookService from "./UserWebhookService";
import UserWhatsAppService from "./UserWhatsAppService";
import WebhookService from "./WebhookService";
import WhatsAppService from "./WhatsAppService";
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
import BadDataException from "../../Types/Exception/BadDataException";
import NotificationSettingEventType from "../../Types/NotificationSetting/NotificationSettingEventType";
import ObjectID from "../../Types/ObjectID";
import UserNotificationSetting from "../../Models/DatabaseModels/UserNotificationSetting";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import { appendRecipientToWhatsAppMessage } from "../Utils/WhatsAppTemplateUtil";
export class Service extends DatabaseService {
    constructor() {
        super(UserNotificationSetting);
    }
    async sendUserNotification(data) {
        var _a, _b, _c, _d, _e;
        if (!data.projectId) {
            throw new BadDataException("ProjectId is required for SendUserNotification");
        }
        const notificationSettings = await this.findOneBy({
            query: {
                userId: data.userId,
                projectId: data.projectId,
                eventType: data.eventType,
            },
            select: {
                alertByEmail: true,
                alertBySMS: true,
                alertByWhatsApp: true,
                alertByTelegram: true,
                alertByCall: true,
                alertByPush: true,
                alertByWebhook: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (notificationSettings) {
            if (notificationSettings.alertByEmail) {
                // get all the emails of the user.
                const userEmails = await UserEmailService.findBy({
                    query: {
                        userId: data.userId,
                        projectId: data.projectId,
                        isVerified: true,
                    },
                    select: {
                        email: true,
                    },
                    limit: LIMIT_PER_PROJECT,
                    skip: 0,
                    props: {
                        isRoot: true,
                    },
                });
                for (const userEmail of userEmails) {
                    MailService.sendMail(Object.assign(Object.assign({}, data.emailEnvelope), { toEmail: userEmail.email }), {
                        projectId: data.projectId,
                        incidentId: data.incidentId,
                        alertId: data.alertId,
                        alertEpisodeId: data.alertEpisodeId,
                        incidentEpisodeId: data.incidentEpisodeId,
                        monitorId: data.monitorId,
                        scheduledMaintenanceId: data.scheduledMaintenanceId,
                        statusPageId: data.statusPageId,
                        statusPageAnnouncementId: data.statusPageAnnouncementId,
                        userId: data.userId,
                        teamId: data.teamId,
                        // OnCall-related fields
                        onCallPolicyId: data.onCallPolicyId,
                        onCallPolicyEscalationRuleId: data.onCallPolicyEscalationRuleId,
                        onCallDutyPolicyExecutionLogTimelineId: data.onCallDutyPolicyExecutionLogTimelineId,
                        onCallScheduleId: data.onCallScheduleId,
                    }).catch((err) => {
                        logger.error(err);
                    });
                }
            }
            /*
             * If the project has a default Twilio config set, all SMS and Calls
             * sent to project team members will use it instead of the global config.
             */
            const projectTwilioConfig = await ProjectCallSMSConfigService.getProjectDefaultTwilioConfig(data.projectId);
            if (notificationSettings.alertBySMS) {
                const userSmses = await UserSmsService.findBy({
                    query: {
                        userId: data.userId,
                        projectId: data.projectId,
                        isVerified: true,
                    },
                    select: {
                        phone: true,
                    },
                    limit: LIMIT_PER_PROJECT,
                    skip: 0,
                    props: {
                        isRoot: true,
                    },
                });
                for (const userSms of userSmses) {
                    SmsService.sendSms(Object.assign(Object.assign({}, data.smsMessage), { to: userSms.phone }), {
                        projectId: data.projectId,
                        customTwilioConfig: projectTwilioConfig,
                        incidentId: data.incidentId,
                        alertId: data.alertId,
                        alertEpisodeId: data.alertEpisodeId,
                        incidentEpisodeId: data.incidentEpisodeId,
                        monitorId: data.monitorId,
                        scheduledMaintenanceId: data.scheduledMaintenanceId,
                        statusPageId: data.statusPageId,
                        statusPageAnnouncementId: data.statusPageAnnouncementId,
                        userId: data.userId,
                        teamId: data.teamId,
                        // OnCall-related fields
                        onCallPolicyId: data.onCallPolicyId,
                        onCallPolicyEscalationRuleId: data.onCallPolicyEscalationRuleId,
                        onCallDutyPolicyExecutionLogTimelineId: data.onCallDutyPolicyExecutionLogTimelineId,
                        onCallScheduleId: data.onCallScheduleId,
                    }).catch((err) => {
                        logger.error(err);
                    });
                }
            }
            if (notificationSettings.alertByWhatsApp) {
                const userWhatsApps = await UserWhatsAppService.findBy({
                    query: {
                        userId: data.userId,
                        projectId: data.projectId,
                        isVerified: true,
                    },
                    select: {
                        phone: true,
                    },
                    limit: LIMIT_PER_PROJECT,
                    skip: 0,
                    props: {
                        isRoot: true,
                    },
                });
                if (!data.whatsAppMessage) {
                    logger.warn("Skipping WhatsApp notification because WhatsApp template payload is missing.");
                }
                else {
                    for (const userWhatsApp of userWhatsApps) {
                        const whatsAppMessage = appendRecipientToWhatsAppMessage(data.whatsAppMessage, userWhatsApp.phone);
                        WhatsAppService.sendWhatsAppMessage(whatsAppMessage, {
                            projectId: data.projectId,
                            incidentId: data.incidentId,
                            alertId: data.alertId,
                            alertEpisodeId: data.alertEpisodeId,
                            incidentEpisodeId: data.incidentEpisodeId,
                            monitorId: data.monitorId,
                            scheduledMaintenanceId: data.scheduledMaintenanceId,
                            statusPageId: data.statusPageId,
                            statusPageAnnouncementId: data.statusPageAnnouncementId,
                            userId: data.userId,
                            teamId: data.teamId,
                            onCallPolicyId: data.onCallPolicyId,
                            onCallPolicyEscalationRuleId: data.onCallPolicyEscalationRuleId,
                            onCallDutyPolicyExecutionLogTimelineId: data.onCallDutyPolicyExecutionLogTimelineId,
                            onCallScheduleId: data.onCallScheduleId,
                        }).catch((err) => {
                            logger.error(err);
                        });
                    }
                }
            }
            if (notificationSettings.alertByTelegram) {
                const userTelegrams = await UserTelegramService.findBy({
                    query: {
                        userId: data.userId,
                        projectId: data.projectId,
                        isVerified: true,
                    },
                    select: {
                        telegramChatId: true,
                    },
                    limit: LIMIT_PER_PROJECT,
                    skip: 0,
                    props: {
                        isRoot: true,
                    },
                });
                /*
                 * When the caller did not provide a Telegram-specific message we build a
                 * nicely-formatted HTML body from the email subject + SMS body + optional
                 * URL from the email envelope, with a 🔔 prefix. If they did provide one,
                 * we respect their body/parseMode verbatim.
                 */
                const callerProvidedTelegramBody = Boolean((_a = data.telegramMessage) === null || _a === void 0 ? void 0 : _a.body);
                const escapeHtml = (value) => {
                    return value
                        .replace(/&/g, "&amp;")
                        .replace(/</g, "&lt;")
                        .replace(/>/g, "&gt;");
                };
                let telegramBody = "";
                let telegramParseMode = undefined;
                if (callerProvidedTelegramBody) {
                    telegramBody = data.telegramMessage.body;
                    telegramParseMode = data.telegramMessage.parseMode;
                }
                else {
                    const subject = data.emailEnvelope.subject || "";
                    const smsBody = data.smsMessage.message || "";
                    if (subject || smsBody) {
                        const lines = [];
                        if (subject) {
                            lines.push(`🔔 <b>${escapeHtml(subject)}</b>`);
                        }
                        else {
                            lines.push("🔔 <b>OneUptime notification</b>");
                        }
                        if (smsBody) {
                            lines.push("");
                            lines.push(escapeHtml(smsBody));
                        }
                        telegramBody = lines.join("\n");
                        telegramParseMode = "HTML";
                    }
                }
                if (!telegramBody) {
                    logger.warn("Skipping Telegram notification because message body is empty.");
                }
                else {
                    for (const userTelegram of userTelegrams) {
                        if (!userTelegram.telegramChatId) {
                            continue;
                        }
                        const telegramMessage = {
                            to: userTelegram.telegramChatId,
                            body: telegramBody,
                            parseMode: telegramParseMode,
                            disableWebPagePreview: (_c = (_b = data.telegramMessage) === null || _b === void 0 ? void 0 : _b.disableWebPagePreview) !== null && _c !== void 0 ? _c : true,
                        };
                        TelegramService.sendTelegramMessage(telegramMessage, {
                            projectId: data.projectId,
                            incidentId: data.incidentId,
                            alertId: data.alertId,
                            alertEpisodeId: data.alertEpisodeId,
                            incidentEpisodeId: data.incidentEpisodeId,
                            monitorId: data.monitorId,
                            scheduledMaintenanceId: data.scheduledMaintenanceId,
                            statusPageId: data.statusPageId,
                            statusPageAnnouncementId: data.statusPageAnnouncementId,
                            userId: data.userId,
                            teamId: data.teamId,
                            onCallPolicyId: data.onCallPolicyId,
                            onCallPolicyEscalationRuleId: data.onCallPolicyEscalationRuleId,
                            onCallDutyPolicyExecutionLogTimelineId: data.onCallDutyPolicyExecutionLogTimelineId,
                            onCallScheduleId: data.onCallScheduleId,
                        }).catch((err) => {
                            logger.error(err);
                        });
                    }
                }
            }
            if (notificationSettings.alertByCall) {
                const userCalls = await UserCallService.findBy({
                    query: {
                        userId: data.userId,
                        projectId: data.projectId,
                        isVerified: true,
                    },
                    select: {
                        phone: true,
                    },
                    limit: LIMIT_PER_PROJECT,
                    skip: 0,
                    props: {
                        isRoot: true,
                    },
                });
                for (const userCall of userCalls) {
                    CallService.makeCall(Object.assign(Object.assign({}, data.callRequestMessage), { to: userCall.phone }), {
                        projectId: data.projectId,
                        customTwilioConfig: projectTwilioConfig,
                        incidentId: data.incidentId,
                        alertId: data.alertId,
                        alertEpisodeId: data.alertEpisodeId,
                        incidentEpisodeId: data.incidentEpisodeId,
                        monitorId: data.monitorId,
                        scheduledMaintenanceId: data.scheduledMaintenanceId,
                        statusPageId: data.statusPageId,
                        statusPageAnnouncementId: data.statusPageAnnouncementId,
                        userId: data.userId,
                        teamId: data.teamId,
                        // OnCall-related fields
                        onCallPolicyId: data.onCallPolicyId,
                        onCallPolicyEscalationRuleId: data.onCallPolicyEscalationRuleId,
                        onCallDutyPolicyExecutionLogTimelineId: data.onCallDutyPolicyExecutionLogTimelineId,
                        onCallScheduleId: data.onCallScheduleId,
                    }).catch((err) => {
                        logger.error(err);
                    });
                }
            }
            if (notificationSettings.alertByPush) {
                logger.debug(`Sending push notification to user ${data.userId.toString()} for event ${data.eventType}`);
                PushNotificationService.sendPushNotificationToUser(data.userId, data.projectId, data.pushNotificationMessage, {
                    projectId: data.projectId,
                    userId: data.userId,
                    teamId: data.teamId,
                    monitorId: data.monitorId,
                    // OnCall-related fields
                    onCallPolicyId: data.onCallPolicyId,
                    onCallPolicyEscalationRuleId: data.onCallPolicyEscalationRuleId,
                    onCallDutyPolicyExecutionLogTimelineId: data.onCallDutyPolicyExecutionLogTimelineId,
                    onCallScheduleId: data.onCallScheduleId,
                }).catch((err) => {
                    logger.error(err);
                });
            }
            if (notificationSettings.alertByWebhook) {
                const userWebhooks = await UserWebhookService.findBy({
                    query: {
                        userId: data.userId,
                        projectId: data.projectId,
                    },
                    select: {
                        webhookUrl: true,
                        secret: true,
                        name: true,
                    },
                    limit: LIMIT_PER_PROJECT,
                    skip: 0,
                    props: {
                        isRoot: true,
                    },
                });
                const webhookPayload = {
                    eventType: data.eventType,
                    timestamp: new Date().toISOString(),
                    projectId: data.projectId.toString(),
                    userId: data.userId.toString(),
                    subject: ((_d = data.emailEnvelope) === null || _d === void 0 ? void 0 : _d.subject) || "",
                    message: ((_e = data.smsMessage) === null || _e === void 0 ? void 0 : _e.message) || "",
                };
                if (data.incidentId) {
                    webhookPayload["incidentId"] = data.incidentId.toString();
                }
                if (data.alertId) {
                    webhookPayload["alertId"] = data.alertId.toString();
                }
                if (data.monitorId) {
                    webhookPayload["monitorId"] = data.monitorId.toString();
                }
                if (data.scheduledMaintenanceId) {
                    webhookPayload["scheduledMaintenanceId"] =
                        data.scheduledMaintenanceId.toString();
                }
                if (data.statusPageId) {
                    webhookPayload["statusPageId"] = data.statusPageId.toString();
                }
                if (data.statusPageAnnouncementId) {
                    webhookPayload["statusPageAnnouncementId"] =
                        data.statusPageAnnouncementId.toString();
                }
                if (data.onCallPolicyId) {
                    webhookPayload["onCallPolicyId"] = data.onCallPolicyId.toString();
                }
                if (data.onCallPolicyEscalationRuleId) {
                    webhookPayload["onCallPolicyEscalationRuleId"] =
                        data.onCallPolicyEscalationRuleId.toString();
                }
                for (const userWebhook of userWebhooks) {
                    if (!userWebhook.webhookUrl) {
                        continue;
                    }
                    WebhookService.sendWebhook({
                        url: userWebhook.webhookUrl,
                        eventType: data.eventType,
                        payload: webhookPayload,
                        secret: userWebhook.secret,
                    }, {
                        projectId: data.projectId,
                        incidentId: data.incidentId,
                        alertId: data.alertId,
                        monitorId: data.monitorId,
                        scheduledMaintenanceId: data.scheduledMaintenanceId,
                        statusPageId: data.statusPageId,
                        statusPageAnnouncementId: data.statusPageAnnouncementId,
                        userId: data.userId,
                        teamId: data.teamId,
                        onCallPolicyId: data.onCallPolicyId,
                        onCallPolicyEscalationRuleId: data.onCallPolicyEscalationRuleId,
                        onCallDutyPolicyExecutionLogTimelineId: data.onCallDutyPolicyExecutionLogTimelineId,
                        onCallScheduleId: data.onCallScheduleId,
                    }).catch((err) => {
                        logger.error(err);
                    });
                }
            }
        }
    }
    async removeDefaultNotificationSettingsForUser(userId, projectId) {
        // check if this user is not in the project anymore.
        const count = await TeamMemberService.countBy({
            query: {
                projectId,
                userId,
                hasAcceptedInvitation: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (count.toNumber() === 0) {
            await this.deleteBy({
                query: {
                    projectId,
                    userId,
                },
                limit: LIMIT_PER_PROJECT,
                skip: 0,
                props: {
                    isRoot: true,
                },
            });
        }
    }
    async addDefaultNotificationSettingsForUser(userId, projectId) {
        await this.addProbeOwnerNotificationSettings(userId, projectId);
        await this.addIncidentNotificationSettings(userId, projectId);
        await this.addMonitorNotificationSettings(userId, projectId);
        await this.addOnCallNotificationSettings(userId, projectId);
        await this.addAlertNotificationSettings(userId, projectId);
        await this.addAlertEpisodeNotificationSettings(userId, projectId);
        await this.addIncidentEpisodeNotificationSettings(userId, projectId);
    }
    async addProbeOwnerNotificationSettings(userId, projectId) {
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_PROBE_OWNER_ADDED_NOTIFICATION);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_PROBE_STATUS_CHANGED_OWNER_NOTIFICATION);
    }
    async addIncidentNotificationSettings(userId, projectId) {
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_INCIDENT_CREATED_OWNER_NOTIFICATION);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_INCIDENT_STATE_CHANGED_OWNER_NOTIFICATION);
    }
    async addMonitorNotificationSettings(userId, projectId) {
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_MONITOR_STATUS_CHANGED_OWNER_NOTIFICATION);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_MONITOR_NOTIFICATION_WHEN_NO_PROBES_ARE_MONITORING_THE_MONITOR);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_MONITOR_NOTIFICATION_WHEN_PORBE_STATUS_CHANGES);
    }
    async addOnCallNotificationSettings(userId, projectId) {
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_WHEN_USER_IS_ON_CALL_ROSTER);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_WHEN_USER_IS_NEXT_ON_CALL_ROSTER);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_WHEN_USER_IS_ADDED_TO_ON_CALL_POLICY);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_WHEN_USER_IS_REMOVED_FROM_ON_CALL_POLICY);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_WHEN_USER_IS_NO_LONGER_ACTIVE_ON_ON_CALL_ROSTER);
    }
    async addAlertNotificationSettings(userId, projectId) {
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_ALERT_CREATED_OWNER_NOTIFICATION);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_ALERT_STATE_CHANGED_OWNER_NOTIFICATION);
    }
    async addAlertEpisodeNotificationSettings(userId, projectId) {
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_ALERT_EPISODE_CREATED_OWNER_NOTIFICATION);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_ALERT_EPISODE_STATE_CHANGED_OWNER_NOTIFICATION);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_ALERT_ADDED_TO_EPISODE_OWNER_NOTIFICATION);
    }
    async addIncidentEpisodeNotificationSettings(userId, projectId) {
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_INCIDENT_EPISODE_CREATED_OWNER_NOTIFICATION);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_INCIDENT_EPISODE_STATE_CHANGED_OWNER_NOTIFICATION);
        await this.addNotificationSettingIfNotExists(userId, projectId, NotificationSettingEventType.SEND_INCIDENT_ADDED_TO_EPISODE_OWNER_NOTIFICATION);
    }
    async addNotificationSettingIfNotExists(userId, projectId, eventType) {
        const existingNotification = await this.countBy({
            query: {
                userId,
                projectId,
                eventType,
            },
            props: {
                isRoot: true,
            },
        });
        if (existingNotification.toNumber() === 0) {
            const item = new UserNotificationSetting();
            item.userId = userId;
            item.projectId = projectId;
            item.eventType = eventType;
            item.alertByEmail = true;
            await this.create({
                data: item,
                props: {
                    isRoot: true,
                },
            });
        }
    }
    async onBeforeCreate(createBy) {
        // check if the same event for same user is added.
        if (!createBy.data.projectId) {
            throw new BadDataException("ProjectId is required for UserNotificationSetting");
        }
        if (!createBy.data.userId) {
            throw new BadDataException("UserId is required for UserNotificationSetting");
        }
        if (!createBy.data.eventType) {
            throw new BadDataException("EventType is required for UserNotificationSetting");
        }
        const count = await this.countBy({
            query: {
                projectId: createBy.data.projectId,
                userId: createBy.data.userId,
                eventType: createBy.data.eventType,
            },
            props: {
                isRoot: true,
            },
        });
        if (count.toNumber() > 0) {
            throw new BadDataException("Notification Setting of the same event type already exists for the user.");
        }
        return {
            createBy,
            carryForward: undefined,
        };
    }
}
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "sendUserNotification", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID,
        ObjectID]),
    __metadata("design:returntype", Promise)
], Service.prototype, "removeDefaultNotificationSettingsForUser", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID,
        ObjectID]),
    __metadata("design:returntype", Promise)
], Service.prototype, "addDefaultNotificationSettingsForUser", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onBeforeCreate", null);
export default new Service();
//# sourceMappingURL=UserNotificationSettingService.js.map