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 DatabaseConfig from "../DatabaseConfig";
import DatabaseService from "./DatabaseService";
import MonitorService from "./MonitorService";
import ScheduledMaintenanceOwnerTeamService from "./ScheduledMaintenanceOwnerTeamService";
import ScheduledMaintenanceOwnerUserService from "./ScheduledMaintenanceOwnerUserService";
import ScheduledMaintenanceStateService from "./ScheduledMaintenanceStateService";
import ScheduledMaintenanceStateTimelineService from "./ScheduledMaintenanceStateTimelineService";
import TeamMemberService from "./TeamMemberService";
import URL from "../../Types/API/URL";
import SortOrder from "../../Types/BaseDatabase/SortOrder";
import LIMIT_MAX, { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
import BadDataException from "../../Types/Exception/BadDataException";
import ObjectID from "../../Types/ObjectID";
import Typeof from "../../Types/Typeof";
import StatusPageSubscriberNotificationStatus from "../../Types/StatusPage/StatusPageSubscriberNotificationStatus";
import Model from "../../Models/DatabaseModels/ScheduledMaintenance";
import ScheduledMaintenanceOwnerTeam from "../../Models/DatabaseModels/ScheduledMaintenanceOwnerTeam";
import ScheduledMaintenanceOwnerUser from "../../Models/DatabaseModels/ScheduledMaintenanceOwnerUser";
import ScheduledMaintenanceStateTimeline from "../../Models/DatabaseModels/ScheduledMaintenanceStateTimeline";
import Recurring from "../../Types/Events/Recurring";
import OneUptimeDate from "../../Types/Date";
import { StatusPageApiRoute } from "../../ServiceRoute";
import EmailTemplateType from "../../Types/Email/EmailTemplateType";
import MailService from "../../Server/Services/MailService";
import ProjectCallSMSConfigService from "../../Server/Services/ProjectCallSMSConfigService";
import ProjectSmtpConfigService from "../../Server/Services/ProjectSmtpConfigService";
import SmsService from "../../Server/Services/SmsService";
import StatusPageResourceService from "../../Server/Services/StatusPageResourceService";
import StatusPageService from "../../Server/Services/StatusPageService";
import StatusPageSubscriberService from "../../Server/Services/StatusPageSubscriberService";
import QueryHelper from "../../Server/Types/Database/QueryHelper";
import Markdown, { MarkdownContentType } from "../../Server/Types/Markdown";
import logger from "../../Server/Utils/Logger";
import { IsBillingEnabled } from "../EnvironmentConfig";
import StatusPageEventType from "../../Types/StatusPage/StatusPageEventType";
import ScheduledMaintenanceFeedService from "./ScheduledMaintenanceFeedService";
import ScheduledMaintenanceLabelRuleEngineService from "./ScheduledMaintenanceLabelRuleEngineService";
import ScheduledMaintenanceOwnerRuleEngineService from "./ScheduledMaintenanceOwnerRuleEngineService";
import RunbookRuleEngineService from "./RunbookRuleEngineService";
import { ScheduledMaintenanceFeedEventType } from "../../Models/DatabaseModels/ScheduledMaintenanceFeed";
import SlackUtil from "../Utils/Workspace/Slack/Slack";
import StatusPageSubscriberWebhookUtil from "../Utils/StatusPageSubscriberWebhook";
import { Gray500, Red500 } from "../../Types/BrandColors";
import LabelService from "./LabelService";
import ScheduledMaintenanceWorkspaceMessages from "../Utils/Workspace/WorkspaceMessages/ScheduledMaintenance";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import ProjectService from "./ProjectService";
import StatusPageSubscriberNotificationTemplateService, { Service as StatusPageSubscriberNotificationTemplateServiceClass, } from "./StatusPageSubscriberNotificationTemplateService";
import StatusPageSubscriberNotificationEventType from "../../Types/StatusPage/StatusPageSubscriberNotificationEventType";
import StatusPageSubscriberNotificationMethod from "../../Types/StatusPage/StatusPageSubscriberNotificationMethod";
export class Service extends DatabaseService {
    constructor() {
        super(Model);
        if (IsBillingEnabled) {
            this.hardDeleteItemsOlderThanInDays("createdAt", 3 * 365); // 3 years
        }
    }
    async notififySubscribersOnEventScheduled(scheduledEvents) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
        logger.debug("ScheduledMaintenance:SendSubscriberRemindersOnEventScheduled: Running");
        const host = await DatabaseConfig.getHost();
        const httpProtocol = await DatabaseConfig.getHttpProtocol();
        for (const event of scheduledEvents) {
            // get status page resources from monitors.
            logger.debug("ScheduledMaintenance:SendSubscriberRemindersOnEventScheduled: Sending notification for event: " +
                event.id, {
                projectId: (_a = event.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                scheduledMaintenanceId: (_b = event.id) === null || _b === void 0 ? void 0 : _b.toString(),
            });
            let statusPageResources = [];
            if (event.monitors && event.monitors.length > 0) {
                statusPageResources = await StatusPageResourceService.findByMonitors({
                    monitors: event.monitors,
                    select: {
                        _id: true,
                        displayName: true,
                        statusPageId: true,
                    },
                });
            }
            const statusPageToResources = {};
            for (const resource of statusPageResources) {
                if (!resource.statusPageId) {
                    continue;
                }
                if (!statusPageToResources[(_c = resource.statusPageId) === null || _c === void 0 ? void 0 : _c.toString()]) {
                    statusPageToResources[(_d = resource.statusPageId) === null || _d === void 0 ? void 0 : _d.toString()] = [];
                }
                (_f = statusPageToResources[(_e = resource.statusPageId) === null || _e === void 0 ? void 0 : _e.toString()]) === null || _f === void 0 ? void 0 : _f.push(resource);
            }
            const statusPages = await StatusPageSubscriberService.getStatusPagesToSendNotification(((_g = event.statusPages) === null || _g === void 0 ? void 0 : _g.map((i) => {
                return i.id;
            })) || []);
            for (const statuspage of statusPages) {
                if (!statuspage.id) {
                    continue;
                }
                if (!statuspage.showScheduledMaintenanceEventsOnStatusPage) {
                    continue; // Do not send notification to subscribers if scheduledMaintenances are not visible on status page.
                }
                const subscribers = await StatusPageSubscriberService.getSubscribersByStatusPage(statuspage.id, {
                    isRoot: true,
                    ignoreHooks: true,
                });
                const statusPageURL = await StatusPageService.getStatusPageURL(statuspage.id);
                const statusPageName = statuspage.pageTitle || statuspage.name || "Status Page";
                const scheduledEventDetailsUrl = event.id && statusPageURL
                    ? URL.fromString(statusPageURL)
                        .addRoute(`/scheduled-events/${event.id.toString()}`)
                        .toString()
                    : statusPageURL;
                // Send email to Email subscribers.
                const resourcesAffected = ((_h = statusPageToResources[statuspage._id]) === null || _h === void 0 ? void 0 : _h.map((r) => {
                    return r.displayName;
                }).join(", ")) || "";
                // Fetch custom templates for each notification method
                const [emailTemplate, smsTemplate, slackTemplate,] = await Promise.all([
                    StatusPageSubscriberNotificationTemplateService.getTemplateForStatusPage({
                        statusPageId: statuspage.id,
                        eventType: StatusPageSubscriberNotificationEventType.SubscriberScheduledMaintenanceCreated,
                        notificationMethod: StatusPageSubscriberNotificationMethod.Email,
                    }),
                    StatusPageSubscriberNotificationTemplateService.getTemplateForStatusPage({
                        statusPageId: statuspage.id,
                        eventType: StatusPageSubscriberNotificationEventType.SubscriberScheduledMaintenanceCreated,
                        notificationMethod: StatusPageSubscriberNotificationMethod.SMS,
                    }),
                    StatusPageSubscriberNotificationTemplateService.getTemplateForStatusPage({
                        statusPageId: statuspage.id,
                        eventType: StatusPageSubscriberNotificationEventType.SubscriberScheduledMaintenanceCreated,
                        notificationMethod: StatusPageSubscriberNotificationMethod.Slack,
                    }),
                ]);
                for (const subscriber of subscribers) {
                    if (!subscriber._id) {
                        continue;
                    }
                    const shouldNotifySubscriber = StatusPageSubscriberService.shouldSendNotification({
                        subscriber: subscriber,
                        statusPageResources: statusPageToResources[statuspage._id] || [],
                        statusPage: statuspage,
                        eventType: StatusPageEventType.ScheduledEvent,
                    });
                    if (!shouldNotifySubscriber) {
                        continue;
                    }
                    const unsubscribeUrl = StatusPageSubscriberService.getUnsubscribeLink(URL.fromString(statusPageURL), subscriber.id).toString();
                    // Create template variables for custom templates
                    const templateVariables = {
                        statusPageName: statusPageName,
                        statusPageUrl: statusPageURL,
                        detailsUrl: scheduledEventDetailsUrl,
                        scheduledMaintenanceTitle: event.title || "",
                        scheduledMaintenanceDescription: event.description || "",
                        scheduledStartTime: OneUptimeDate.getDateAsUserFriendlyFormattedString(event.startsAt),
                        scheduledEndTime: event.endsAt
                            ? OneUptimeDate.getDateAsUserFriendlyFormattedString(event.endsAt)
                            : "",
                        resourcesAffected: resourcesAffected,
                        unsubscribeUrl: unsubscribeUrl,
                    };
                    // SMS-specific template variables with plain text (no HTML/Markdown)
                    const smsTemplateVariables = Object.assign(Object.assign({}, templateVariables), { scheduledMaintenanceDescription: Markdown.convertToPlainText(event.description || "") });
                    if (subscriber.subscriberPhone) {
                        let smsMessage;
                        if (smsTemplate &&
                            smsTemplate.templateBody &&
                            statuspage.callSmsConfig) {
                            // Use custom template only when custom Twilio is configured
                            smsMessage =
                                StatusPageSubscriberNotificationTemplateServiceClass.compileTemplate(smsTemplate.templateBody, smsTemplateVariables);
                        }
                        else {
                            // Use default template
                            smsMessage = `Scheduled Maintenance: ${event.title || ""} on ${statusPageName}.${resourcesAffected ? ` Impact: ${resourcesAffected}.` : ""} Details: ${scheduledEventDetailsUrl}. Unsub: ${unsubscribeUrl}`;
                        }
                        const sms = {
                            message: smsMessage,
                            to: subscriber.subscriberPhone,
                        };
                        // send sms here.
                        SmsService.sendSms(sms, {
                            projectId: statuspage.projectId,
                            customTwilioConfig: ProjectCallSMSConfigService.toTwilioConfig(statuspage.callSmsConfig),
                            statusPageId: statuspage.id,
                            scheduledMaintenanceId: event.id,
                        }).catch((err) => {
                            var _a;
                            logger.error(err, {
                                projectId: (_a = statuspage.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                            });
                        });
                    }
                    if (subscriber.slackIncomingWebhookUrl) {
                        let slackMessage;
                        if (slackTemplate && slackTemplate.templateBody) {
                            // Use custom template
                            slackMessage =
                                StatusPageSubscriberNotificationTemplateServiceClass.compileTemplate(slackTemplate.templateBody, templateVariables);
                        }
                        else {
                            // Use default template
                            slackMessage = `## 🔧 Scheduled Maintenance - ${event.title || ""}

**Scheduled Date:** ${OneUptimeDate.getDateAsUserFriendlyFormattedString(event.startsAt)}

${resourcesAffected ? `**Resources Affected:** ${resourcesAffected}` : ""}

**Description:** ${event.description || ""}

[View Status Page](${statusPageURL}) | [Unsubscribe](${unsubscribeUrl})`;
                        }
                        // send Slack notification here.
                        SlackUtil.sendMessageToChannelViaIncomingWebhook({
                            url: subscriber.slackIncomingWebhookUrl,
                            text: SlackUtil.convertMarkdownToSlackRichText(slackMessage),
                        }).catch((err) => {
                            var _a;
                            logger.error(err, {
                                projectId: (_a = statuspage.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                            });
                        });
                    }
                    if (subscriber.subscriberWebhook) {
                        StatusPageSubscriberWebhookUtil.sendWebhookNotification({
                            webhookUrl: subscriber.subscriberWebhook,
                            payload: {
                                eventType: "ScheduledMaintenanceCreated",
                                statusPageId: statuspage.id.toString(),
                                statusPageName: statusPageName,
                                statusPageUrl: statusPageURL,
                                unsubscribeUrl: unsubscribeUrl,
                                data: {
                                    scheduledMaintenanceId: ((_j = event.id) === null || _j === void 0 ? void 0 : _j.toString()) || "",
                                    scheduledMaintenanceTitle: event.title || "",
                                    scheduledMaintenanceDescription: event.description || "",
                                    scheduledStartTime: OneUptimeDate.getDateAsUserFriendlyFormattedString(event.startsAt),
                                    scheduledEndTime: event.endsAt
                                        ? OneUptimeDate.getDateAsUserFriendlyFormattedString(event.endsAt)
                                        : "",
                                    resourcesAffected: resourcesAffected,
                                    detailsUrl: scheduledEventDetailsUrl,
                                },
                            },
                        }).catch((err) => {
                            var _a;
                            logger.error(err, {
                                projectId: (_a = statuspage.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                            });
                        });
                    }
                    if (subscriber.subscriberEmail) {
                        // send email here.
                        const statusPageIdString = ((_k = statuspage.id) === null || _k === void 0 ? void 0 : _k.toString()) || ((_l = statuspage._id) === null || _l === void 0 ? void 0 : _l.toString()) || null;
                        // Prepare email variables
                        const emailVars = {
                            statusPageName: statusPageName,
                            statusPageUrl: statusPageURL,
                            detailsUrl: scheduledEventDetailsUrl,
                            logoUrl: statuspage.logoFileId && statusPageIdString
                                ? new URL(httpProtocol, host)
                                    .addRoute(StatusPageApiRoute)
                                    .addRoute(`/logo/${statusPageIdString}`)
                                    .toString()
                                : "",
                            isPublicStatusPage: statuspage.isPublicStatusPage
                                ? "true"
                                : "false",
                            subscriberEmailNotificationFooterText: statuspage.subscriberEmailNotificationFooterText || "",
                            resourcesAffected: resourcesAffected,
                            scheduledAt: OneUptimeDate.getDateAsFormattedHTMLInMultipleTimezones({
                                date: event.startsAt,
                                timezones: statuspage.subscriberTimezones || [],
                                use12HourFormat: true,
                            }),
                            eventTitle: event.title || "",
                            eventDescription: await Markdown.convertToHTML(event.description || "", MarkdownContentType.Email),
                            unsubscribeUrl: unsubscribeUrl,
                        };
                        // Check for custom email template - only use when custom SMTP is configured
                        if (emailTemplate &&
                            emailTemplate.templateBody &&
                            statuspage.smtpConfig) {
                            // Use custom template with BlankTemplate only when custom SMTP is configured
                            const customEmailBody = StatusPageSubscriberNotificationTemplateServiceClass.compileTemplate(emailTemplate.templateBody, Object.assign(Object.assign({}, templateVariables), emailVars));
                            const customEmailSubject = emailTemplate.emailSubject
                                ? StatusPageSubscriberNotificationTemplateServiceClass.compileTemplate(emailTemplate.emailSubject, Object.assign(Object.assign({}, templateVariables), emailVars))
                                : "[Scheduled Maintenance] " + (event.title || statusPageName);
                            MailService.sendMail({
                                toEmail: subscriber.subscriberEmail,
                                templateType: EmailTemplateType.BlankTemplate,
                                vars: {
                                    body: customEmailBody,
                                },
                                subject: customEmailSubject,
                            }, {
                                mailServer: ProjectSmtpConfigService.toEmailServer(statuspage.smtpConfig),
                                projectId: statuspage.projectId,
                                statusPageId: statuspage.id,
                                scheduledMaintenanceId: event.id,
                            }).catch((err) => {
                                var _a;
                                logger.error(err, {
                                    projectId: (_a = statuspage.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                                });
                            });
                        }
                        else {
                            // Use default hard-coded template
                            MailService.sendMail({
                                toEmail: subscriber.subscriberEmail,
                                templateType: EmailTemplateType.SubscriberScheduledMaintenanceEventCreated,
                                vars: emailVars,
                                subject: "[Scheduled Maintenance] " +
                                    (event.title || statusPageName),
                            }, {
                                mailServer: ProjectSmtpConfigService.toEmailServer(statuspage.smtpConfig),
                                projectId: statuspage.projectId,
                                statusPageId: statuspage.id,
                                scheduledMaintenanceId: event.id,
                            }).catch((err) => {
                                var _a;
                                logger.error(err, {
                                    projectId: (_a = statuspage.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                                });
                            });
                        }
                    }
                }
            }
        }
        logger.debug("ScheduledMaintenance:SendSubscriberRemindersOnEventScheduled: Completed");
    }
    async onBeforeUpdate(updateBy) {
        if (updateBy.query._id &&
            (updateBy.data.sendSubscriberNotificationsOnBeforeTheEvent ||
                updateBy.data.startsAt)) {
            logger.debug(`Calculating nextSubscriberNotificationBeforeTheEventAt for Scheduled Maintenance: ${updateBy.query.id}`);
            const scheduledMaintenance = await this.findOneById({
                id: updateBy.query._id,
                select: {
                    startsAt: true,
                    sendSubscriberNotificationsOnBeforeTheEvent: true,
                },
                props: {
                    isRoot: true,
                },
            });
            logger.debug(`Current Scheduled Maintenance data: ${JSON.stringify(scheduledMaintenance)}`);
            if (!scheduledMaintenance) {
                throw new BadDataException("Scheduled Maintenance Event not found");
            }
            const startsAt = updateBy.data.startsAt ||
                scheduledMaintenance.startsAt;
            let notificationSettings = null;
            const updatedNotificationSettings = updateBy.data.sendSubscriberNotificationsOnBeforeTheEvent;
            if (updatedNotificationSettings !== null &&
                updatedNotificationSettings !== undefined) {
                notificationSettings = updatedNotificationSettings;
            }
            else {
                const existingNotificationSettings = scheduledMaintenance.sendSubscriberNotificationsOnBeforeTheEvent;
                if (existingNotificationSettings !== null &&
                    existingNotificationSettings !== undefined) {
                    notificationSettings = existingNotificationSettings;
                }
            }
            logger.debug(`Using startsAt: ${startsAt} and notificationSettings: ${JSON.stringify(notificationSettings)}`);
            if (!notificationSettings || notificationSettings.length === 0) {
                logger.debug("No subscriber notification schedule configured. Clearing nextSubscriberNotificationBeforeTheEventAt.");
                updateBy.data.nextSubscriberNotificationBeforeTheEventAt = null;
            }
            else {
                const nextTimeToNotifyBeforeTheEvent = this.getNextTimeToNotify({
                    eventScheduledDate: startsAt,
                    sendSubscriberNotifiationsOn: notificationSettings,
                });
                updateBy.data.nextSubscriberNotificationBeforeTheEventAt =
                    nextTimeToNotifyBeforeTheEvent;
                logger.debug(`nextSubscriberNotificationBeforeTheEventAt set to: ${nextTimeToNotifyBeforeTheEvent}`);
            }
        }
        // Set notification status based on shouldStatusPageSubscribersBeNotifiedOnEventCreated if it's being updated
        if (updateBy.data.shouldStatusPageSubscribersBeNotifiedOnEventCreated !==
            undefined) {
            if (updateBy.data.shouldStatusPageSubscribersBeNotifiedOnEventCreated ===
                false) {
                updateBy.data.subscriberNotificationStatusOnEventScheduled =
                    StatusPageSubscriberNotificationStatus.Skipped;
                updateBy.data.subscriberNotificationStatusMessage =
                    "Notifications skipped as subscribers are not to be notified for this scheduled maintenance.";
            }
            else if (updateBy.data.shouldStatusPageSubscribersBeNotifiedOnEventCreated ===
                true) {
                updateBy.data.subscriberNotificationStatusOnEventScheduled =
                    StatusPageSubscriberNotificationStatus.Pending;
            }
        }
        return {
            updateBy,
            carryForward: null,
        };
    }
    async onBeforeDelete(deleteBy) {
        const scheduledMaintenanceEvents = await this.findBy({
            query: deleteBy.query,
            limit: LIMIT_MAX,
            skip: 0,
            select: {
                _id: true,
                projectId: true,
                monitors: {
                    _id: true,
                },
            },
            props: {
                isRoot: true,
            },
        });
        return {
            carryForward: {
                scheduledMaintenanceEvents: scheduledMaintenanceEvents,
            },
            deleteBy: deleteBy,
        };
    }
    async onDeleteSuccess(onDelete, _deletedItemIds) {
        var _a, _b;
        if ((_a = onDelete.carryForward) === null || _a === void 0 ? void 0 : _a.scheduledMaintenanceEvents) {
            for (const scheduledMaintenanceEvent of ((_b = onDelete === null || onDelete === void 0 ? void 0 : onDelete.carryForward) === null || _b === void 0 ? void 0 : _b.scheduledMaintenanceEvents) || []) {
                await ScheduledMaintenanceStateTimelineService.enableActiveMonitoringForMonitors(scheduledMaintenanceEvent);
            }
        }
        return onDelete;
    }
    getNextTimeToNotify(data) {
        let recurringDate = null;
        logger.debug(`getNextTimeToNotify: `);
        logger.debug(data);
        logger.debug(`Calculating next time to notify for event scheduled date: ${data.eventScheduledDate}`);
        const notificationSchedules = Array.isArray(data.sendSubscriberNotifiationsOn)
            ? data.sendSubscriberNotifiationsOn
            : [];
        if (notificationSchedules.length === 0) {
            logger.debug("No sendSubscriberNotifiationsOn entries. Returning null for next notification time.");
            return null;
        }
        for (const recurringItem of notificationSchedules) {
            if (!recurringItem) {
                continue;
            }
            const notificationDate = Recurring.getNextDateInterval(data.eventScheduledDate, recurringItem, true);
            logger.debug(`Notification date calculated: ${notificationDate} for recurring item: ${recurringItem}`);
            // if this date is in the future. set it to recurring date.
            if (!recurringDate && OneUptimeDate.isInTheFuture(notificationDate)) {
                recurringDate = notificationDate;
                logger.debug(`Notification date is in the future. Setting recurring date to: ${recurringDate}`);
            }
            else {
                logger.debug(`Notification date is in the past. Skipping.`);
            }
            // if this new date is less than the recurring date then set it to recurring date. We need to get the least date.
            if (recurringDate) {
                if (OneUptimeDate.isBefore(notificationDate, recurringDate) &&
                    OneUptimeDate.isInTheFuture(notificationDate)) {
                    recurringDate = notificationDate;
                    logger.debug(`Found an earlier notification date. Updating recurring date to: ${recurringDate}`);
                }
                else {
                    logger.debug(`Notification date is not earlier than recurring date. Skipping.`);
                }
            }
        }
        logger.debug(`Final recurring date: ${recurringDate}`);
        return recurringDate;
    }
    async onBeforeCreate(createBy) {
        if (!createBy.props.tenantId && !createBy.data.projectId) {
            throw new BadDataException("ProjectId required to create scheduled maintenance.");
        }
        const projectId = createBy.props.tenantId || createBy.data.projectId;
        const scheduledMaintenanceState = await ScheduledMaintenanceStateService.findOneBy({
            query: {
                projectId: projectId,
                isScheduledState: true,
            },
            select: {
                _id: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (!scheduledMaintenanceState || !scheduledMaintenanceState.id) {
            throw new BadDataException("Scheduled state not found for this project. Please add an scheduled event state from settings.");
        }
        createBy.data.currentScheduledMaintenanceStateId =
            scheduledMaintenanceState.id;
        const scheduledMaintenanceCounterResult = await ProjectService.incrementAndGetScheduledMaintenanceCounter(projectId);
        createBy.data.scheduledMaintenanceNumber =
            scheduledMaintenanceCounterResult.counter;
        createBy.data.scheduledMaintenanceNumberWithPrefix =
            scheduledMaintenanceCounterResult.prefix
                ? `${scheduledMaintenanceCounterResult.prefix}${scheduledMaintenanceCounterResult.counter}`
                : `#${scheduledMaintenanceCounterResult.counter}`;
        // get next notification date.
        if (createBy.data.sendSubscriberNotificationsOnBeforeTheEvent &&
            createBy.data.startsAt) {
            const nextNotificationDate = this.getNextTimeToNotify({
                eventScheduledDate: createBy.data.startsAt,
                sendSubscriberNotifiationsOn: createBy.data.sendSubscriberNotificationsOnBeforeTheEvent,
            });
            if (nextNotificationDate) {
                // set this.
                createBy.data.nextSubscriberNotificationBeforeTheEventAt =
                    nextNotificationDate;
            }
        }
        // Set notification status based on shouldStatusPageSubscribersBeNotifiedOnEventCreated
        if (createBy.data.shouldStatusPageSubscribersBeNotifiedOnEventCreated ===
            false) {
            createBy.data.subscriberNotificationStatusOnEventScheduled =
                StatusPageSubscriberNotificationStatus.Skipped;
            createBy.data.subscriberNotificationStatusMessage =
                "Notifications skipped as subscribers are not to be notified for this scheduled maintenance.";
        }
        else if (createBy.data.shouldStatusPageSubscribersBeNotifiedOnEventCreated === true) {
            createBy.data.subscriberNotificationStatusOnEventScheduled =
                StatusPageSubscriberNotificationStatus.Pending;
        }
        return { createBy, carryForward: null };
    }
    async onCreateSuccess(onCreate, createdItem) {
        // Get scheduled maintenance data for feed creation
        const scheduledMaintenance = await this.findOneById({
            id: createdItem.id,
            select: {
                projectId: true,
                scheduledMaintenanceNumber: true,
                scheduledMaintenanceNumberWithPrefix: true,
                title: true,
                description: true,
                currentScheduledMaintenanceState: {
                    name: true,
                },
                startsAt: true,
                endsAt: true,
                monitors: {
                    name: true,
                    _id: true,
                },
                labels: {
                    name: true,
                },
                createdByUserId: true,
                createdByUser: {
                    _id: true,
                    name: true,
                    email: true,
                },
            },
            props: {
                isRoot: true,
            },
        });
        if (!scheduledMaintenance) {
            throw new BadDataException("Scheduled Maintenance not found");
        }
        // Execute operations sequentially with error handling
        Promise.resolve()
            .then(async () => {
            var _a, _b;
            try {
                if (createdItem.projectId && createdItem.id) {
                    return await this.handleScheduledMaintenanceWorkspaceOperationsAsync(createdItem);
                }
                return Promise.resolve();
            }
            catch (error) {
                logger.error(`Workspace operations failed in ScheduledMaintenanceService.onCreateSuccess: ${error}`, {
                    projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                    scheduledMaintenanceId: (_b = createdItem.id) === null || _b === void 0 ? void 0 : _b.toString(),
                });
                return Promise.resolve();
            }
        })
            .then(async () => {
            var _a, _b;
            try {
                return await this.createScheduledMaintenanceFeedAsync(scheduledMaintenance);
            }
            catch (error) {
                logger.error(`Create scheduled maintenance feed failed in ScheduledMaintenanceService.onCreateSuccess: ${error}`, {
                    projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                    scheduledMaintenanceId: (_b = createdItem.id) === null || _b === void 0 ? void 0 : _b.toString(),
                });
                return Promise.resolve();
            }
        })
            .then(async () => {
            var _a, _b;
            try {
                return await this.createScheduledMaintenanceStateTimelineAsync(createdItem);
            }
            catch (error) {
                logger.error(`Create scheduled maintenance state timeline failed in ScheduledMaintenanceService.onCreateSuccess: ${error}`, {
                    projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                    scheduledMaintenanceId: (_b = createdItem.id) === null || _b === void 0 ? void 0 : _b.toString(),
                });
                return Promise.resolve();
            }
        })
            .then(async () => {
            var _a, _b;
            try {
                if (createdItem.projectId &&
                    createdItem.id &&
                    onCreate.createBy.miscDataProps &&
                    (onCreate.createBy.miscDataProps["ownerTeams"] ||
                        onCreate.createBy.miscDataProps["ownerUsers"])) {
                    return await this.addOwners(createdItem.projectId, createdItem.id, onCreate.createBy.miscDataProps["ownerUsers"] || [], onCreate.createBy.miscDataProps["ownerTeams"] || [], false, onCreate.createBy.props);
                }
                return Promise.resolve();
            }
            catch (error) {
                logger.error(`Add owners failed in ScheduledMaintenanceService.onCreateSuccess: ${error}`, {
                    projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                    scheduledMaintenanceId: (_b = createdItem.id) === null || _b === void 0 ? void 0 : _b.toString(),
                });
                return Promise.resolve();
            }
        })
            .then(async () => {
            var _a, _b;
            // Apply owner rules: add matched owner users/teams to the event.
            try {
                await ScheduledMaintenanceOwnerRuleEngineService.applyRulesToScheduledMaintenance(createdItem);
            }
            catch (error) {
                logger.error(`Apply scheduled maintenance owner rules failed in ScheduledMaintenanceService.onCreateSuccess: ${error}`, {
                    projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                    scheduledMaintenanceId: (_b = createdItem.id) === null || _b === void 0 ? void 0 : _b.toString(),
                });
            }
        })
            .then(async () => {
            var _a, _b;
            // Apply label rules: attach matched (and optionally inherited monitor) labels to the event.
            try {
                await ScheduledMaintenanceLabelRuleEngineService.applyRulesToScheduledMaintenance(createdItem);
            }
            catch (error) {
                logger.error(`Apply scheduled maintenance label rules failed in ScheduledMaintenanceService.onCreateSuccess: ${error}`, {
                    projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                    scheduledMaintenanceId: (_b = createdItem.id) === null || _b === void 0 ? void 0 : _b.toString(),
                });
            }
        })
            .then(async () => {
            var _a, _b;
            try {
                await RunbookRuleEngineService.applyRulesToScheduledMaintenance(createdItem);
            }
            catch (error) {
                logger.error(`Apply runbook rules failed in ScheduledMaintenanceService.onCreateSuccess: ${error}`, {
                    projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                    scheduledMaintenanceId: (_b = createdItem.id) === null || _b === void 0 ? void 0 : _b.toString(),
                });
            }
        })
            .catch((error) => {
            var _a, _b;
            logger.error(`Critical error in ScheduledMaintenanceService sequential operations: ${error}`, {
                projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                scheduledMaintenanceId: (_b = createdItem.id) === null || _b === void 0 ? void 0 : _b.toString(),
            });
        });
        return createdItem;
    }
    async handleScheduledMaintenanceWorkspaceOperationsAsync(createdItem) {
        var _a, _b, _c;
        try {
            if (!createdItem.projectId || !createdItem.id) {
                throw new BadDataException("projectId and id are required for workspace operations");
            }
            // send message to workspaces - slack, teams, etc.
            const workspaceResult = await ScheduledMaintenanceWorkspaceMessages.createChannelsAndInviteUsersToChannels({
                projectId: createdItem.projectId,
                scheduledMaintenanceId: createdItem.id,
                scheduledMaintenanceNumber: createdItem.scheduledMaintenanceNumber,
            });
            if (workspaceResult && ((_a = workspaceResult.channelsCreated) === null || _a === void 0 ? void 0 : _a.length) > 0) {
                // update scheduledMaintenance with these channels.
                await this.updateOneById({
                    id: createdItem.id,
                    data: {
                        postUpdatesToWorkspaceChannels: workspaceResult.channelsCreated || [],
                    },
                    props: {
                        isRoot: true,
                    },
                });
            }
        }
        catch (error) {
            logger.error(`Error in handleScheduledMaintenanceWorkspaceOperationsAsync: ${error}`, {
                projectId: (_b = createdItem.projectId) === null || _b === void 0 ? void 0 : _b.toString(),
                scheduledMaintenanceId: (_c = createdItem.id) === null || _c === void 0 ? void 0 : _c.toString(),
            });
            throw error;
        }
    }
    async createScheduledMaintenanceFeedAsync(scheduledMaintenance) {
        var _a, _b, _c, _d, _e;
        try {
            const createdByUserId = scheduledMaintenance.createdByUserId ||
                ((_a = scheduledMaintenance.createdByUser) === null || _a === void 0 ? void 0 : _a.id);
            let feedInfoInMarkdown = `#### 🕒 Scheduled Maintenance ${scheduledMaintenance.scheduledMaintenanceNumberWithPrefix || "#" + ((_b = scheduledMaintenance.scheduledMaintenanceNumber) === null || _b === void 0 ? void 0 : _b.toString())} Created:
            
**${scheduledMaintenance.title || "No title provided."}**:
      
${scheduledMaintenance.description || "No description provided."}
      
`;
            // add starts at and ends at.
            if (scheduledMaintenance.startsAt) {
                feedInfoInMarkdown += `**Starts At**: ${OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(scheduledMaintenance.startsAt)} \n\n`;
            }
            if (scheduledMaintenance.endsAt) {
                feedInfoInMarkdown += `**Ends At**: ${OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(scheduledMaintenance.endsAt)} \n\n`;
            }
            if ((_c = scheduledMaintenance.currentScheduledMaintenanceState) === null || _c === void 0 ? void 0 : _c.name) {
                feedInfoInMarkdown += `⏳ **Scheduled Maintenance State**: ${scheduledMaintenance.currentScheduledMaintenanceState.name} \n\n`;
            }
            if (scheduledMaintenance.monitors &&
                scheduledMaintenance.monitors.length > 0) {
                feedInfoInMarkdown += `🌎 **Resources Affected**:\n`;
                for (const monitor of scheduledMaintenance.monitors) {
                    feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(scheduledMaintenance.projectId, monitor.id)).toString()})\n`;
                }
                feedInfoInMarkdown += `\n\n`;
            }
            const scheduledMaintenanceCreateMessageBlocks = await ScheduledMaintenanceWorkspaceMessages.getScheduledMaintenanceCreateMessageBlocks({
                scheduledMaintenanceId: scheduledMaintenance.id,
                projectId: scheduledMaintenance.projectId,
            });
            await ScheduledMaintenanceFeedService.createScheduledMaintenanceFeedItem({
                scheduledMaintenanceId: scheduledMaintenance.id,
                projectId: scheduledMaintenance.projectId,
                scheduledMaintenanceFeedEventType: ScheduledMaintenanceFeedEventType.ScheduledMaintenanceCreated,
                displayColor: Red500,
                feedInfoInMarkdown: feedInfoInMarkdown,
                userId: createdByUserId || undefined,
                workspaceNotification: {
                    appendMessageBlocks: scheduledMaintenanceCreateMessageBlocks,
                    sendWorkspaceNotification: true,
                },
            });
        }
        catch (error) {
            logger.error(`Error in createScheduledMaintenanceFeedAsync: ${error}`, {
                projectId: (_d = scheduledMaintenance.projectId) === null || _d === void 0 ? void 0 : _d.toString(),
                scheduledMaintenanceId: (_e = scheduledMaintenance.id) === null || _e === void 0 ? void 0 : _e.toString(),
            });
            throw error;
        }
    }
    async createScheduledMaintenanceStateTimelineAsync(createdItem) {
        var _a, _b;
        try {
            const timeline = new ScheduledMaintenanceStateTimeline();
            timeline.projectId = createdItem.projectId;
            timeline.scheduledMaintenanceId = createdItem.id;
            timeline.isOwnerNotified = true; // ignore notifying owners because you already notify for Scheduled Event, no need to notify them for timeline event.
            timeline.shouldStatusPageSubscribersBeNotified = Boolean(createdItem.shouldStatusPageSubscribersBeNotifiedOnEventCreated);
            // Map boolean to enum value - ignore notifying subscribers because you already notify for Scheduled Event, no need to notify them for timeline event.
            timeline.subscriberNotificationStatus =
                createdItem.shouldStatusPageSubscribersBeNotifiedOnEventCreated
                    ? StatusPageSubscriberNotificationStatus.Success
                    : StatusPageSubscriberNotificationStatus.Pending;
            timeline.scheduledMaintenanceStateId =
                createdItem.currentScheduledMaintenanceStateId;
            await ScheduledMaintenanceStateTimelineService.create({
                data: timeline,
                props: {
                    isRoot: true,
                },
            });
        }
        catch (error) {
            logger.error(`Error in createScheduledMaintenanceStateTimelineAsync: ${error}`, {
                projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                scheduledMaintenanceId: (_b = createdItem.id) === null || _b === void 0 ? void 0 : _b.toString(),
            });
            throw error;
        }
    }
    async addOwners(projectId, scheduledMaintenanceId, userIds, teamIds, notifyOwners, props) {
        for (let teamId of teamIds) {
            if (typeof teamId === Typeof.String) {
                teamId = new ObjectID(teamId.toString());
            }
            const teamOwner = new ScheduledMaintenanceOwnerTeam();
            teamOwner.scheduledMaintenanceId = scheduledMaintenanceId;
            teamOwner.projectId = projectId;
            teamOwner.teamId = teamId;
            teamOwner.isOwnerNotified = !notifyOwners;
            await ScheduledMaintenanceOwnerTeamService.create({
                data: teamOwner,
                props: props,
            });
        }
        for (let userId of userIds) {
            if (typeof userId === Typeof.String) {
                userId = new ObjectID(userId.toString());
            }
            const teamOwner = new ScheduledMaintenanceOwnerUser();
            teamOwner.scheduledMaintenanceId = scheduledMaintenanceId;
            teamOwner.projectId = projectId;
            teamOwner.isOwnerNotified = !notifyOwners;
            teamOwner.userId = userId;
            await ScheduledMaintenanceOwnerUserService.create({
                data: teamOwner,
                props: props,
            });
        }
    }
    async getScheduledMaintenanceLinkInDashboard(projectId, scheduledMaintenanceId) {
        if (!projectId) {
            throw new BadDataException("projectId is required");
        }
        if (!scheduledMaintenanceId) {
            throw new BadDataException("scheduledMaintenanceId is required");
        }
        const dashboardUrl = await DatabaseConfig.getDashboardUrl();
        if (!dashboardUrl) {
            throw new BadDataException("Dashboard URL not found");
        }
        return URL.fromString(dashboardUrl.toString()).addRoute(`/${projectId.toString()}/scheduled-maintenance-events/${scheduledMaintenanceId.toString()}`);
    }
    async findOwners(scheduledMaintenanceId) {
        if (!scheduledMaintenanceId) {
            throw new BadDataException("scheduledMaintenanceId is required");
        }
        const ownerUsers = await ScheduledMaintenanceOwnerUserService.findBy({
            query: {
                scheduledMaintenanceId: scheduledMaintenanceId,
            },
            select: {
                _id: true,
                user: {
                    _id: true,
                    email: true,
                    name: true,
                    timezone: true,
                },
            },
            props: {
                isRoot: true,
            },
            limit: LIMIT_PER_PROJECT,
            skip: 0,
        });
        const ownerTeams = await ScheduledMaintenanceOwnerTeamService.findBy({
            query: {
                scheduledMaintenanceId: scheduledMaintenanceId,
            },
            select: {
                _id: true,
                teamId: true,
            },
            skip: 0,
            limit: LIMIT_PER_PROJECT,
            props: {
                isRoot: true,
            },
        });
        const users = ownerUsers.map((ownerUser) => {
            return ownerUser.user;
        }) || [];
        if (ownerTeams.length > 0) {
            const teamIds = ownerTeams.map((ownerTeam) => {
                return ownerTeam.teamId;
            }) || [];
            const teamUsers = await TeamMemberService.getUsersInTeams(teamIds);
            for (const teamUser of teamUsers) {
                //check if the user is already added.
                const isUserAlreadyAdded = users.find((user) => {
                    return user.id.toString() === teamUser.id.toString();
                });
                if (!isUserAlreadyAdded) {
                    users.push(teamUser);
                }
            }
        }
        return users;
    }
    async changeAttachedMonitorStates(item, props) {
        var _a;
        if (!item.projectId) {
            throw new BadDataException("projectId is required");
        }
        if (!item.id) {
            throw new BadDataException("id is required");
        }
        if (item.changeMonitorStatusToId && item.projectId) {
            // change status of all the monitors.
            await MonitorService.changeMonitorStatus(item.projectId, ((_a = item.monitors) === null || _a === void 0 ? void 0 : _a.map((monitor) => {
                return new ObjectID(monitor._id || "");
            })) || [], item.changeMonitorStatusToId, true, // notify owners
            "Changed because of scheduled maintenance event: " + item.id.toString(), undefined, props);
        }
    }
    async onUpdateSuccess(onUpdate, updatedItemIds) {
        if (onUpdate.updateBy.data.currentScheduledMaintenanceStateId &&
            onUpdate.updateBy.props.tenantId) {
            for (const itemId of updatedItemIds) {
                await this.changeScheduledMaintenanceState({
                    projectId: onUpdate.updateBy.props.tenantId,
                    scheduledMaintenanceId: itemId,
                    scheduledMaintenanceStateId: onUpdate.updateBy.data
                        .currentScheduledMaintenanceStateId,
                    shouldNotifyStatusPageSubscribers: true,
                    isSubscribersNotified: false,
                    notifyOwners: true, // notifyOwners = true
                    props: {
                        isRoot: true,
                    },
                });
            }
        }
        if (updatedItemIds.length > 0) {
            for (const scheduledMaintenanceId of updatedItemIds) {
                let shouldAddScheduledMaintenanceFeed = false;
                let feedInfoInMarkdown = "**Scheduled Maintenance was updated.**";
                const createdByUserId = onUpdate.updateBy.props.userId;
                if (onUpdate.updateBy.data.title) {
                    // add scheduledMaintenance feed.
                    feedInfoInMarkdown += `\n\n**Title**: 
${onUpdate.updateBy.data.title || "No title provided."}
`;
                    shouldAddScheduledMaintenanceFeed = true;
                }
                if (onUpdate.updateBy.data.startsAt) {
                    // add scheduledMaintenance feed.
                    feedInfoInMarkdown += `\n\n**Starts At**: 
${OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(onUpdate.updateBy.data.startsAt) || "No title provided."}
`;
                    shouldAddScheduledMaintenanceFeed = true;
                }
                if (onUpdate.updateBy.data.endsAt) {
                    // add scheduledMaintenance feed.
                    feedInfoInMarkdown += `\n\n**Ends At**:
${OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(onUpdate.updateBy.data.endsAt) || "No title provided."}
`;
                    shouldAddScheduledMaintenanceFeed = true;
                }
                if (onUpdate.updateBy.data.description) {
                    // add scheduledMaintenance feed.
                    feedInfoInMarkdown += `\n\n**Scheduled Maintenance Description**: 
${onUpdate.updateBy.data.description || "No description provided."}
          `;
                    shouldAddScheduledMaintenanceFeed = true;
                }
                if (onUpdate.updateBy.data.sendSubscriberNotificationsOnBeforeTheEvent &&
                    Array.isArray(onUpdate.updateBy.data.sendSubscriberNotificationsOnBeforeTheEvent) &&
                    onUpdate.updateBy.data.sendSubscriberNotificationsOnBeforeTheEvent
                        .length > 0) {
                    feedInfoInMarkdown += `\n\n**Notify Subscribers Before Event Starts**: 
${onUpdate.updateBy.data
                        .sendSubscriberNotificationsOnBeforeTheEvent
                        .map((recurring) => {
                        return `- ${recurring.toString()}`;
                    })
                        .join("\n")}
          `;
                    shouldAddScheduledMaintenanceFeed = true;
                }
                if (onUpdate.updateBy.data.monitors &&
                    onUpdate.updateBy.data.monitors.length > 0 &&
                    Array.isArray(onUpdate.updateBy.data.monitors)) {
                    const monitorIds = onUpdate.updateBy.data.monitors
                        .map((monitor) => {
                        var _a;
                        if (monitor._id) {
                            return new ObjectID((_a = monitor._id) === null || _a === void 0 ? void 0 : _a.toString());
                        }
                        return null;
                    })
                        .filter((monitorId) => {
                        return monitorId !== null;
                    });
                    const monitors = await MonitorService.findBy({
                        query: {
                            _id: QueryHelper.any(monitorIds),
                        },
                        select: {
                            name: true,
                        },
                        limit: LIMIT_PER_PROJECT,
                        skip: 0,
                        props: {
                            isRoot: true,
                        },
                    });
                    if (monitors.length > 0) {
                        feedInfoInMarkdown += `\n\n**Resources Affected**:

${monitors
                            .map((monitor) => {
                            return `- ${monitor.name}`;
                        })
                            .join("\n")}
`;
                        shouldAddScheduledMaintenanceFeed = true;
                    }
                }
                if (onUpdate.updateBy.data.statusPages &&
                    onUpdate.updateBy.data.statusPages.length > 0 &&
                    Array.isArray(onUpdate.updateBy.data.statusPages)) {
                    const statusPageIds = onUpdate.updateBy.data.statusPages
                        .map((statusPage) => {
                        var _a;
                        if (statusPage._id) {
                            return new ObjectID((_a = statusPage._id) === null || _a === void 0 ? void 0 : _a.toString());
                        }
                        return null;
                    })
                        .filter((statusPageId) => {
                        return statusPageId !== null;
                    });
                    const statusPages = await StatusPageService.findBy({
                        query: {
                            _id: QueryHelper.any(statusPageIds),
                        },
                        select: {
                            name: true,
                        },
                        limit: LIMIT_PER_PROJECT,
                        skip: 0,
                        props: {
                            isRoot: true,
                        },
                    });
                    if (statusPages.length > 0) {
                        feedInfoInMarkdown += `\n\n**Show on these status pages:**:

${statusPages
                            .map((statusPage) => {
                            return `- ${statusPage.name}`;
                        })
                            .join("\n")}
`;
                        shouldAddScheduledMaintenanceFeed = true;
                    }
                }
                if (onUpdate.updateBy.data.labels &&
                    onUpdate.updateBy.data.labels.length > 0 &&
                    Array.isArray(onUpdate.updateBy.data.labels)) {
                    const labelIds = onUpdate.updateBy.data.labels
                        .map((label) => {
                        var _a;
                        if (label._id) {
                            return new ObjectID((_a = label._id) === null || _a === void 0 ? void 0 : _a.toString());
                        }
                        return null;
                    })
                        .filter((labelId) => {
                        return labelId !== null;
                    });
                    const labels = await LabelService.findBy({
                        query: {
                            _id: QueryHelper.any(labelIds),
                        },
                        select: {
                            name: true,
                        },
                        limit: LIMIT_PER_PROJECT,
                        skip: 0,
                        props: {
                            isRoot: true,
                        },
                    });
                    if (labels.length > 0) {
                        feedInfoInMarkdown += `\n\n**Labels**:

${labels
                            .map((label) => {
                            return `- ${label.name}`;
                        })
                            .join("\n")}
`;
                        shouldAddScheduledMaintenanceFeed = true;
                    }
                }
                if (shouldAddScheduledMaintenanceFeed) {
                    await ScheduledMaintenanceFeedService.createScheduledMaintenanceFeedItem({
                        scheduledMaintenanceId: scheduledMaintenanceId,
                        projectId: onUpdate.updateBy.props.tenantId,
                        scheduledMaintenanceFeedEventType: ScheduledMaintenanceFeedEventType.ScheduledMaintenanceUpdated,
                        displayColor: Gray500,
                        feedInfoInMarkdown: feedInfoInMarkdown,
                        userId: createdByUserId || undefined,
                    });
                }
            }
        }
        return onUpdate;
    }
    async changeScheduledMaintenanceState(data) {
        const { projectId, scheduledMaintenanceId, scheduledMaintenanceStateId, notifyOwners, shouldNotifyStatusPageSubscribers, isSubscribersNotified, props, } = data;
        if (!projectId) {
            throw new BadDataException("projectId is required");
        }
        if (!scheduledMaintenanceId) {
            throw new BadDataException("scheduledMaintenanceId is required");
        }
        if (!scheduledMaintenanceStateId) {
            throw new BadDataException("scheduledMaintenanceStateId is required");
        }
        // get last scheduled status timeline.
        const lastState = await ScheduledMaintenanceStateTimelineService.findOneBy({
            query: {
                scheduledMaintenanceId: scheduledMaintenanceId,
                projectId: projectId,
            },
            select: {
                _id: true,
                scheduledMaintenanceStateId: true,
            },
            sort: {
                createdAt: SortOrder.Descending,
            },
            props: {
                isRoot: true,
            },
        });
        if (lastState &&
            lastState.scheduledMaintenanceStateId &&
            lastState.scheduledMaintenanceStateId.toString() ===
                scheduledMaintenanceStateId.toString()) {
            return;
        }
        const statusTimeline = new ScheduledMaintenanceStateTimeline();
        statusTimeline.scheduledMaintenanceId = scheduledMaintenanceId;
        statusTimeline.scheduledMaintenanceStateId = scheduledMaintenanceStateId;
        statusTimeline.projectId = projectId;
        statusTimeline.isOwnerNotified = !notifyOwners;
        // Map boolean to enum value
        statusTimeline.subscriberNotificationStatus = isSubscribersNotified
            ? StatusPageSubscriberNotificationStatus.Success
            : StatusPageSubscriberNotificationStatus.Pending;
        statusTimeline.shouldStatusPageSubscribersBeNotified =
            shouldNotifyStatusPageSubscribers;
        await ScheduledMaintenanceStateTimelineService.create({
            data: statusTimeline,
            props: props,
        });
        await this.updateBy({
            data: {
                currentScheduledMaintenanceStateId: scheduledMaintenanceStateId.id,
            },
            skip: 0,
            limit: LIMIT_PER_PROJECT,
            query: {
                _id: scheduledMaintenanceId.toString(),
            },
            props: {
                isRoot: true,
            },
        });
    }
    async isScheduledMaintenanceCompleted(data) {
        const scheduledMaintenance = await this.findOneBy({
            query: {
                _id: data.scheduledMaintenanceId,
            },
            select: {
                projectId: true,
                currentScheduledMaintenanceState: {
                    order: true,
                },
            },
            props: {
                isRoot: true,
            },
        });
        if (!scheduledMaintenance) {
            throw new BadDataException("ScheduledMaintenance not found");
        }
        if (!scheduledMaintenance.projectId) {
            throw new BadDataException("Incident Project ID not found");
        }
        const resolvedScheduledMaintenanceState = await ScheduledMaintenanceStateService.getCompletedScheduledMaintenanceState({
            projectId: scheduledMaintenance.projectId,
            props: {
                isRoot: true,
            },
        });
        const currentScheduledMaintenanceStateOrder = scheduledMaintenance.currentScheduledMaintenanceState.order;
        const resolvedScheduledMaintenanceStateOrder = resolvedScheduledMaintenanceState.order;
        if (currentScheduledMaintenanceStateOrder >=
            resolvedScheduledMaintenanceStateOrder) {
            return true;
        }
        return false;
    }
    async getScheduledMaintenanceNumber(data) {
        const scheduledMaintenance = await this.findOneById({
            id: data.scheduledMaintenanceId,
            select: {
                scheduledMaintenanceNumber: true,
                scheduledMaintenanceNumberWithPrefix: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (!scheduledMaintenance) {
            throw new BadDataException("ScheduledMaintenance not found.");
        }
        return {
            number: scheduledMaintenance.scheduledMaintenanceNumber
                ? Number(scheduledMaintenance.scheduledMaintenanceNumber)
                : null,
            numberWithPrefix: scheduledMaintenance.scheduledMaintenanceNumberWithPrefix || null,
        };
    }
    async isScheduledMaintenanceOngoing(data) {
        const scheduledMaintenance = await this.findOneBy({
            query: {
                _id: data.scheduledMaintenanceId,
            },
            select: {
                projectId: true,
                currentScheduledMaintenanceState: {
                    order: true,
                },
            },
            props: {
                isRoot: true,
            },
        });
        if (!scheduledMaintenance) {
            throw new BadDataException("ScheduledMaintenance not found");
        }
        if (!scheduledMaintenance.projectId) {
            throw new BadDataException("Incident Project ID not found");
        }
        const ackScheduledMaintenanceState = await ScheduledMaintenanceStateService.getOngoingScheduledMaintenanceState({
            projectId: scheduledMaintenance.projectId,
            props: {
                isRoot: true,
            },
        });
        const currentScheduledMaintenanceStateOrder = scheduledMaintenance.currentScheduledMaintenanceState.order;
        const ackScheduledMaintenanceStateOrder = ackScheduledMaintenanceState.order;
        if (currentScheduledMaintenanceStateOrder >= ackScheduledMaintenanceStateOrder) {
            return true;
        }
        return false;
    }
    async markScheduledMaintenanceAsComplete(scheduledMaintenanceId, resolvedByUserId) {
        const scheduledMaintenance = await this.findOneById({
            id: scheduledMaintenanceId,
            select: {
                projectId: true,
                scheduledMaintenanceNumber: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (!scheduledMaintenance || !scheduledMaintenance.projectId) {
            throw new BadDataException("ScheduledMaintenance not found.");
        }
        const scheduledMaintenanceState = await ScheduledMaintenanceStateService.findOneBy({
            query: {
                projectId: scheduledMaintenance.projectId,
                isResolvedState: true,
            },
            select: {
                _id: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (!scheduledMaintenanceState || !scheduledMaintenanceState.id) {
            throw new BadDataException("Acknowledged state not found for this project. Please add acknowledged state from settings.");
        }
        const scheduledMaintenanceStateTimeline = new ScheduledMaintenanceStateTimeline();
        scheduledMaintenanceStateTimeline.projectId =
            scheduledMaintenance.projectId;
        scheduledMaintenanceStateTimeline.scheduledMaintenanceId =
            scheduledMaintenanceId;
        scheduledMaintenanceStateTimeline.scheduledMaintenanceStateId =
            scheduledMaintenanceState.id;
        scheduledMaintenanceStateTimeline.createdByUserId = resolvedByUserId;
        await ScheduledMaintenanceStateTimelineService.create({
            data: scheduledMaintenanceStateTimeline,
            props: {
                isRoot: true,
            },
        });
        // store scheduledMaintenance metric
        return scheduledMaintenance;
    }
    async markScheduledMaintenanceAsOngoing(scheduledMaintenanceId, markedByUserId) {
        const scheduledMaintenance = await this.findOneById({
            id: scheduledMaintenanceId,
            select: {
                projectId: true,
                scheduledMaintenanceNumber: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (!scheduledMaintenance || !scheduledMaintenance.projectId) {
            throw new BadDataException("ScheduledMaintenance not found.");
        }
        const scheduledMaintenanceState = await ScheduledMaintenanceStateService.findOneBy({
            query: {
                projectId: scheduledMaintenance.projectId,
                isOngoingState: true,
            },
            select: {
                _id: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (!scheduledMaintenanceState || !scheduledMaintenanceState.id) {
            throw new BadDataException("Acknowledged state not found for this project. Please add acknowledged state from settings.");
        }
        const scheduledMaintenanceStateTimeline = new ScheduledMaintenanceStateTimeline();
        scheduledMaintenanceStateTimeline.projectId =
            scheduledMaintenance.projectId;
        scheduledMaintenanceStateTimeline.scheduledMaintenanceId =
            scheduledMaintenanceId;
        scheduledMaintenanceStateTimeline.scheduledMaintenanceStateId =
            scheduledMaintenanceState.id;
        scheduledMaintenanceStateTimeline.createdByUserId = markedByUserId;
        await ScheduledMaintenanceStateTimelineService.create({
            data: scheduledMaintenanceStateTimeline,
            props: {
                isRoot: true,
            },
        });
        // store scheduledMaintenance metric
        return scheduledMaintenance;
    }
    async getWorkspaceChannelForScheduledMaintenance(data) {
        const scheduledMaintenance = await this.findOneById({
            id: data.scheduledMaintenanceId,
            select: {
                postUpdatesToWorkspaceChannels: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (!scheduledMaintenance) {
            throw new BadDataException("ScheduledMaintenance not found.");
        }
        return (scheduledMaintenance.postUpdatesToWorkspaceChannels || []).filter((channel) => {
            if (!data.workspaceType) {
                return true;
            }
            return channel.workspaceType === data.workspaceType;
        });
    }
    /**
     * Ensures the currentScheduledMaintenanceStateId of the scheduled maintenance matches the latest timeline entry.
     */
    async refreshScheduledMaintenanceCurrentStatus(scheduledMaintenanceId) {
        var _a, _b;
        const scheduledMaintenance = await this.findOneById({
            id: scheduledMaintenanceId,
            select: {
                _id: true,
                projectId: true,
                currentScheduledMaintenanceStateId: true,
            },
            props: { isRoot: true },
        });
        if (!scheduledMaintenance || !scheduledMaintenance.projectId) {
            return;
        }
        const latestTimeline = await ScheduledMaintenanceStateTimelineService.findOneBy({
            query: {
                scheduledMaintenanceId: scheduledMaintenance.id,
                projectId: scheduledMaintenance.projectId,
            },
            sort: {
                startsAt: SortOrder.Descending,
            },
            select: {
                scheduledMaintenanceStateId: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (latestTimeline &&
            latestTimeline.scheduledMaintenanceStateId &&
            ((_a = scheduledMaintenance.currentScheduledMaintenanceStateId) === null || _a === void 0 ? void 0 : _a.toString()) !==
                latestTimeline.scheduledMaintenanceStateId.toString()) {
            await this.updateOneBy({
                query: { _id: scheduledMaintenance.id.toString() },
                data: {
                    currentScheduledMaintenanceStateId: latestTimeline.scheduledMaintenanceStateId,
                },
                props: { isRoot: true },
            });
            logger.info(`Updated ScheduledMaintenance ${scheduledMaintenance.id} current state to ${latestTimeline.scheduledMaintenanceStateId}`, {
                projectId: (_b = scheduledMaintenance.projectId) === null || _b === void 0 ? void 0 : _b.toString(),
            });
        }
    }
}
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array]),
    __metadata("design:returntype", Promise)
], Service.prototype, "notififySubscribersOnEventScheduled", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onBeforeUpdate", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onBeforeDelete", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Array]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onDeleteSuccess", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onBeforeCreate", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Model]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onCreateSuccess", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Model]),
    __metadata("design:returntype", Promise)
], Service.prototype, "handleScheduledMaintenanceWorkspaceOperationsAsync", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Model]),
    __metadata("design:returntype", Promise)
], Service.prototype, "createScheduledMaintenanceFeedAsync", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Model]),
    __metadata("design:returntype", Promise)
], Service.prototype, "createScheduledMaintenanceStateTimelineAsync", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID,
        ObjectID,
        Array,
        Array, Boolean, Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "addOwners", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID,
        ObjectID]),
    __metadata("design:returntype", Promise)
], Service.prototype, "getScheduledMaintenanceLinkInDashboard", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID]),
    __metadata("design:returntype", Promise)
], Service.prototype, "findOwners", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Model, Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "changeAttachedMonitorStates", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Array]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onUpdateSuccess", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "changeScheduledMaintenanceState", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "isScheduledMaintenanceCompleted", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "getScheduledMaintenanceNumber", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "isScheduledMaintenanceOngoing", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID,
        ObjectID]),
    __metadata("design:returntype", Promise)
], Service.prototype, "markScheduledMaintenanceAsComplete", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID,
        ObjectID]),
    __metadata("design:returntype", Promise)
], Service.prototype, "markScheduledMaintenanceAsOngoing", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "getWorkspaceChannelForScheduledMaintenance", null);
export default new Service();
//# sourceMappingURL=ScheduledMaintenanceService.js.map