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 QueryHelper from "../Types/Database/QueryHelper";
import DatabaseService from "./DatabaseService";
import MonitorService from "./MonitorService";
import MonitorStatusService from "./MonitorStatusService";
import MonitorStatusTimelineService from "./MonitorStatusTimelineService";
import ScheduledMaintenancePublicNoteService from "./ScheduledMaintenancePublicNoteService";
import ScheduledMaintenanceService from "./ScheduledMaintenanceService";
import ScheduledMaintenanceStateService from "./ScheduledMaintenanceStateService";
import SortOrder from "../../Types/BaseDatabase/SortOrder";
import OneUptimeDate from "../../Types/Date";
import BadDataException from "../../Types/Exception/BadDataException";
import ObjectID from "../../Types/ObjectID";
import StatusPageSubscriberNotificationStatus from "../../Types/StatusPage/StatusPageSubscriberNotificationStatus";
import MonitorStatusTimeline from "../../Models/DatabaseModels/MonitorStatusTimeline";
import ScheduledMaintenance from "../../Models/DatabaseModels/ScheduledMaintenance";
import ScheduledMaintenancePublicNote from "../../Models/DatabaseModels/ScheduledMaintenancePublicNote";
import ScheduledMaintenanceStateTimeline from "../../Models/DatabaseModels/ScheduledMaintenanceStateTimeline";
import { IsBillingEnabled } from "../EnvironmentConfig";
import ScheduledMaintenanceFeedService from "./ScheduledMaintenanceFeedService";
import { ScheduledMaintenanceFeedEventType } from "../../Models/DatabaseModels/ScheduledMaintenanceFeed";
import logger from "../Utils/Logger";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
import WorkspaceNotificationRuleService from "./WorkspaceNotificationRuleService";
import Semaphore from "../Infrastructure/Semaphore";
export class Service extends DatabaseService {
    constructor() {
        super(ScheduledMaintenanceStateTimeline);
        if (IsBillingEnabled) {
            this.hardDeleteItemsOlderThanInDays("createdAt", 3 * 365); // 3 years
        }
    }
    async isLastScheduledMaintenanceState(data) {
        var _a;
        // find all the states for this project and sort it by order. Then, check if this is the last state.
        const scheduledMaintenanceStates = await ScheduledMaintenanceStateService.findBy({
            query: {
                projectId: data.projectId,
            },
            limit: LIMIT_PER_PROJECT,
            skip: 0,
            sort: {
                order: SortOrder.Ascending,
            },
            props: {
                isRoot: true,
            },
        });
        const scheduledMaintenanceState = scheduledMaintenanceStates.find((scheduledMaintenanceState) => {
            var _a;
            return (((_a = scheduledMaintenanceState.id) === null || _a === void 0 ? void 0 : _a.toString()) ===
                data.scheduledMaintenanceStateId.toString());
        }) || null;
        if (!scheduledMaintenanceState) {
            throw new BadDataException("ScheduledMaintenance state not found.");
        }
        const lastScheduledMaintenanceState = scheduledMaintenanceStates[scheduledMaintenanceStates.length - 1];
        if (lastScheduledMaintenanceState && lastScheduledMaintenanceState.id) {
            return (lastScheduledMaintenanceState.id.toString() ===
                ((_a = scheduledMaintenanceState.id) === null || _a === void 0 ? void 0 : _a.toString()));
        }
        return false;
    }
    async onBeforeCreate(createBy) {
        var _a, _b, _c, _d, _e, _f;
        if (!createBy.data.scheduledMaintenanceId) {
            throw new BadDataException("scheduledMaintenanceId is null");
        }
        let mutex = null;
        try {
            try {
                mutex = await Semaphore.lock({
                    key: createBy.data.scheduledMaintenanceId.toString(),
                    namespace: "ScheduledMaintenanceStateTimeline.create",
                });
            }
            catch (err) {
                logger.error(err, {
                    scheduledMaintenanceId: (_a = createBy.data.scheduledMaintenanceId) === null || _a === void 0 ? void 0 : _a.toString(),
                });
            }
            if (!createBy.data.startsAt) {
                createBy.data.startsAt = OneUptimeDate.getCurrentDate();
            }
            const scheduledMaintenanceStateId = createBy.data.scheduledMaintenanceStateId ||
                ((_b = createBy.data.scheduledMaintenanceState) === null || _b === void 0 ? void 0 : _b.id);
            if (!scheduledMaintenanceStateId) {
                throw new BadDataException("scheduledMaintenanceStateId is null");
            }
            const stateBeforeThis = await this.findOneBy({
                query: {
                    scheduledMaintenanceId: createBy.data.scheduledMaintenanceId,
                    startsAt: QueryHelper.lessThanEqualTo(createBy.data.startsAt),
                },
                sort: {
                    startsAt: SortOrder.Descending,
                },
                props: {
                    isRoot: true,
                },
                select: {
                    scheduledMaintenanceStateId: true,
                    scheduledMaintenanceState: {
                        order: true,
                        name: true,
                    },
                    startsAt: true,
                    endsAt: true,
                },
            });
            // If this is the first state, then do not notify the owner.
            if (!stateBeforeThis) {
                // since this is the first status, do not notify the owner.
                createBy.data.isOwnerNotified = true;
            }
            if (stateBeforeThis &&
                stateBeforeThis.scheduledMaintenanceStateId &&
                scheduledMaintenanceStateId) {
                if (stateBeforeThis.scheduledMaintenanceStateId.toString() ===
                    scheduledMaintenanceStateId.toString()) {
                    throw new BadDataException("Scheduled Maintenance state cannot be same as previous state.");
                }
            }
            if (stateBeforeThis && ((_c = stateBeforeThis.scheduledMaintenanceState) === null || _c === void 0 ? void 0 : _c.order)) {
                const newScheduledMaintenanceState = await ScheduledMaintenanceStateService.findOneBy({
                    query: {
                        _id: scheduledMaintenanceStateId,
                    },
                    select: {
                        order: true,
                        name: true,
                    },
                    props: {
                        isRoot: true,
                    },
                });
                if (newScheduledMaintenanceState &&
                    newScheduledMaintenanceState.order) {
                    // check if the new scheduledMaintenance state is in order is greater than the previous state order
                    if (stateBeforeThis &&
                        stateBeforeThis.scheduledMaintenanceState &&
                        stateBeforeThis.scheduledMaintenanceState.order &&
                        newScheduledMaintenanceState.order <=
                            stateBeforeThis.scheduledMaintenanceState.order) {
                        throw new BadDataException(`ScheduledMaintenance cannot transition to ${newScheduledMaintenanceState.name} state from ${stateBeforeThis.scheduledMaintenanceState.name} state because ${newScheduledMaintenanceState.name} is before ${stateBeforeThis.scheduledMaintenanceState.name} in the order of scheduledMaintenance states.`);
                    }
                }
            }
            const stateAfterThis = await this.findOneBy({
                query: {
                    scheduledMaintenanceId: createBy.data.scheduledMaintenanceId,
                    startsAt: QueryHelper.greaterThan(createBy.data.startsAt),
                },
                sort: {
                    startsAt: SortOrder.Ascending,
                },
                props: {
                    isRoot: true,
                },
                select: {
                    scheduledMaintenanceStateId: true,
                    startsAt: true,
                    endsAt: true,
                },
            });
            // compute ends at. It's the start of the next status.
            if (stateAfterThis && stateAfterThis.startsAt) {
                createBy.data.endsAt = stateAfterThis.startsAt;
            }
            if (stateAfterThis &&
                stateAfterThis.scheduledMaintenanceStateId &&
                scheduledMaintenanceStateId) {
                if (stateAfterThis.scheduledMaintenanceStateId.toString() ===
                    scheduledMaintenanceStateId.toString()) {
                    throw new BadDataException("Scheduled Maintenance state cannot be same as next state.");
                }
            }
            const publicNote = (_d = createBy.miscDataProps) === null || _d === void 0 ? void 0 : _d["publicNote"];
            if (publicNote) {
                const scheduledMaintenancePublicNote = new ScheduledMaintenancePublicNote();
                scheduledMaintenancePublicNote.scheduledMaintenanceId =
                    createBy.data.scheduledMaintenanceId;
                scheduledMaintenancePublicNote.note = publicNote;
                scheduledMaintenancePublicNote.postedAt = createBy.data.startsAt;
                scheduledMaintenancePublicNote.createdAt = createBy.data.startsAt;
                scheduledMaintenancePublicNote.projectId = createBy.data.projectId;
                scheduledMaintenancePublicNote.shouldStatusPageSubscribersBeNotifiedOnNoteCreated =
                    Boolean(createBy.data.shouldStatusPageSubscribersBeNotified);
                // mark status page subscribers as notified for this state change because we dont want to send duplicate (two) emails one for public note and one for state change.
                if (scheduledMaintenancePublicNote.shouldStatusPageSubscribersBeNotifiedOnNoteCreated) {
                    createBy.data.subscriberNotificationStatus =
                        StatusPageSubscriberNotificationStatus.Success;
                }
                await ScheduledMaintenancePublicNoteService.create({
                    data: scheduledMaintenancePublicNote,
                    props: createBy.props,
                });
            }
            // Set notification status based on shouldStatusPageSubscribersBeNotified
            if (createBy.data.shouldStatusPageSubscribersBeNotified === false) {
                createBy.data.subscriberNotificationStatus =
                    StatusPageSubscriberNotificationStatus.Skipped;
                createBy.data.subscriberNotificationStatusMessage =
                    "Notifications skipped as subscribers are not to be notified for this scheduled maintenance state change.";
            }
            else if (createBy.data.shouldStatusPageSubscribersBeNotified === true) {
                createBy.data.subscriberNotificationStatus =
                    StatusPageSubscriberNotificationStatus.Pending;
            }
            return {
                createBy,
                carryForward: {
                    statusTimelineBeforeThisStatus: stateBeforeThis || null,
                    statusTimelineAfterThisStatus: stateAfterThis || null,
                    publicNote: publicNote,
                    mutex: mutex,
                },
            };
        }
        catch (error) {
            // release the mutex if it was acquired.
            if (mutex) {
                try {
                    await Semaphore.release(mutex);
                }
                catch (err) {
                    logger.error(err, {
                        projectId: (_e = createBy.data.projectId) === null || _e === void 0 ? void 0 : _e.toString(),
                        scheduledMaintenanceId: (_f = createBy.data.scheduledMaintenanceId) === null || _f === void 0 ? void 0 : _f.toString(),
                    });
                }
            }
            throw error;
        }
    }
    async onCreateSuccess(onCreate, createdItem) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
        const mutex = onCreate.carryForward.mutex;
        if (!createdItem.scheduledMaintenanceId) {
            throw new BadDataException("scheduledMaintenanceId is null");
        }
        if (!createdItem.scheduledMaintenanceStateId) {
            throw new BadDataException("scheduledMaintenanceStateId is null");
        }
        // update the last status as ended.
        logger.debug("Status Timeline Before this", {
            projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
            scheduledMaintenanceId: (_b = createdItem.scheduledMaintenanceId) === null || _b === void 0 ? void 0 : _b.toString(),
        });
        logger.debug(onCreate.carryForward.statusTimelineBeforeThisStatus, {
            projectId: (_c = createdItem.projectId) === null || _c === void 0 ? void 0 : _c.toString(),
            scheduledMaintenanceId: (_d = createdItem.scheduledMaintenanceId) === null || _d === void 0 ? void 0 : _d.toString(),
        });
        logger.debug("Status Timeline After this", {
            projectId: (_e = createdItem.projectId) === null || _e === void 0 ? void 0 : _e.toString(),
            scheduledMaintenanceId: (_f = createdItem.scheduledMaintenanceId) === null || _f === void 0 ? void 0 : _f.toString(),
        });
        logger.debug(onCreate.carryForward.statusTimelineAfterThisStatus, {
            projectId: (_g = createdItem.projectId) === null || _g === void 0 ? void 0 : _g.toString(),
            scheduledMaintenanceId: (_h = createdItem.scheduledMaintenanceId) === null || _h === void 0 ? void 0 : _h.toString(),
        });
        logger.debug("Created Item", {
            projectId: (_j = createdItem.projectId) === null || _j === void 0 ? void 0 : _j.toString(),
            scheduledMaintenanceId: (_k = createdItem.scheduledMaintenanceId) === null || _k === void 0 ? void 0 : _k.toString(),
        });
        logger.debug(createdItem, {
            projectId: (_l = createdItem.projectId) === null || _l === void 0 ? void 0 : _l.toString(),
            scheduledMaintenanceId: (_m = createdItem.scheduledMaintenanceId) === null || _m === void 0 ? void 0 : _m.toString(),
        });
        /*
         * now there are three cases.
         * 1. This is the first status OR there's no status after this.
         */
        if (!onCreate.carryForward.statusTimelineBeforeThisStatus) {
            // This is the first status, no need to update previous status.
            logger.debug("This is the first status.", {
                projectId: (_o = createdItem.projectId) === null || _o === void 0 ? void 0 : _o.toString(),
                scheduledMaintenanceId: (_p = createdItem.scheduledMaintenanceId) === null || _p === void 0 ? void 0 : _p.toString(),
            });
        }
        else if (!onCreate.carryForward.statusTimelineAfterThisStatus) {
            /*
             * 2. This is the last status.
             * Update the previous status to end at the start of this status.
             */
            await this.updateOneById({
                id: onCreate.carryForward.statusTimelineBeforeThisStatus.id,
                data: {
                    endsAt: createdItem.startsAt,
                },
                props: {
                    isRoot: true,
                },
            });
            logger.debug("This is the last status.", {
                projectId: (_q = createdItem.projectId) === null || _q === void 0 ? void 0 : _q.toString(),
                scheduledMaintenanceId: (_r = createdItem.scheduledMaintenanceId) === null || _r === void 0 ? void 0 : _r.toString(),
            });
        }
        else {
            /*
             * 3. This is in the middle.
             * Update the previous status to end at the start of this status.
             */
            await this.updateOneById({
                id: onCreate.carryForward.statusTimelineBeforeThisStatus.id,
                data: {
                    endsAt: createdItem.startsAt,
                },
                props: {
                    isRoot: true,
                },
            });
            // Update the next status to start at the end of this status.
            await this.updateOneById({
                id: onCreate.carryForward.statusTimelineAfterThisStatus.id,
                data: {
                    startsAt: createdItem.endsAt,
                },
                props: {
                    isRoot: true,
                },
            });
            logger.debug("This status is in the middle.", {
                projectId: (_s = createdItem.projectId) === null || _s === void 0 ? void 0 : _s.toString(),
                scheduledMaintenanceId: (_t = createdItem.scheduledMaintenanceId) === null || _t === void 0 ? void 0 : _t.toString(),
            });
        }
        if (!createdItem.endsAt) {
            await ScheduledMaintenanceService.updateOneBy({
                query: {
                    _id: (_u = createdItem.scheduledMaintenanceId) === null || _u === void 0 ? void 0 : _u.toString(),
                },
                data: {
                    currentScheduledMaintenanceStateId: createdItem.scheduledMaintenanceStateId,
                },
                props: onCreate.createBy.props,
            });
        }
        if (mutex) {
            try {
                await Semaphore.release(mutex);
            }
            catch (err) {
                logger.error(err, {
                    projectId: (_v = createdItem.projectId) === null || _v === void 0 ? void 0 : _v.toString(),
                    scheduledMaintenanceId: (_w = createdItem.scheduledMaintenanceId) === null || _w === void 0 ? void 0 : _w.toString(),
                });
            }
        }
        const scheduledMaintenanceState = await ScheduledMaintenanceStateService.findOneBy({
            query: {
                _id: createdItem.scheduledMaintenanceStateId.toString(),
            },
            props: {
                isRoot: true,
            },
            select: {
                _id: true,
                isResolvedState: true,
                isOngoingState: true,
                isScheduledState: true,
                color: true,
                name: true,
            },
        });
        const stateName = (scheduledMaintenanceState === null || scheduledMaintenanceState === void 0 ? void 0 : scheduledMaintenanceState.name) || "";
        let stateEmoji = "➡️";
        // if resolved state then change emoji to ✅.
        if (scheduledMaintenanceState === null || scheduledMaintenanceState === void 0 ? void 0 : scheduledMaintenanceState.isResolvedState) {
            stateEmoji = "✅";
        }
        else if (scheduledMaintenanceState === null || scheduledMaintenanceState === void 0 ? void 0 : scheduledMaintenanceState.isOngoingState) {
            // eyes emoji for acknowledged state.
            stateEmoji = "⏳";
        }
        else if (scheduledMaintenanceState === null || scheduledMaintenanceState === void 0 ? void 0 : scheduledMaintenanceState.isScheduledState) {
            stateEmoji = "🕒";
        }
        const scheduledMaintenanceNumberResult = await ScheduledMaintenanceService.getScheduledMaintenanceNumber({
            scheduledMaintenanceId: createdItem.scheduledMaintenanceId,
        });
        const projectId = createdItem.projectId;
        const scheduledMaintenanceId = createdItem.scheduledMaintenanceId;
        await ScheduledMaintenanceFeedService.createScheduledMaintenanceFeedItem({
            scheduledMaintenanceId: createdItem.scheduledMaintenanceId,
            projectId: createdItem.projectId,
            scheduledMaintenanceFeedEventType: ScheduledMaintenanceFeedEventType.ScheduledMaintenanceStateChanged,
            displayColor: scheduledMaintenanceState === null || scheduledMaintenanceState === void 0 ? void 0 : scheduledMaintenanceState.color,
            feedInfoInMarkdown: stateEmoji +
                ` Changed **[Scheduled Maintenance ${scheduledMaintenanceNumberResult.numberWithPrefix || "#" + scheduledMaintenanceNumberResult.number}](${(await ScheduledMaintenanceService.getScheduledMaintenanceLinkInDashboard(projectId, scheduledMaintenanceId)).toString()}) State** to **` +
                stateName +
                "**",
            userId: createdItem.createdByUserId || onCreate.createBy.props.userId,
            workspaceNotification: {
                sendWorkspaceNotification: true,
                notifyUserId: createdItem.createdByUserId || onCreate.createBy.props.userId,
            },
        });
        const isResolvedState = await ScheduledMaintenanceStateService.findOneBy({
            query: {
                _id: createdItem.scheduledMaintenanceStateId.toString(),
                isResolvedState: true,
            },
            props: {
                isRoot: true,
            },
            select: {
                _id: true,
            },
        });
        const isEndedState = await ScheduledMaintenanceStateService.findOneBy({
            query: {
                _id: createdItem.scheduledMaintenanceStateId.toString(),
                isEndedState: true,
            },
            props: {
                isRoot: true,
            },
            select: {
                _id: true,
            },
        });
        const isOngoingState = await ScheduledMaintenanceStateService.findOneBy({
            query: {
                _id: createdItem.scheduledMaintenanceStateId.toString(),
                isOngoingState: true,
            },
            props: {
                isRoot: true,
            },
            select: {
                _id: true,
            },
        });
        const scheduledMaintenanceEvent = await ScheduledMaintenanceService.findOneBy({
            query: {
                _id: (_x = createdItem.scheduledMaintenanceId) === null || _x === void 0 ? void 0 : _x.toString(),
            },
            select: {
                _id: true,
                projectId: true,
                monitors: {
                    _id: true,
                },
                nextSubscriberNotificationBeforeTheEventAt: true,
            },
            props: {
                isRoot: true,
            },
        });
        const hasProgressedBeyondScheduledState = Boolean(scheduledMaintenanceState && !scheduledMaintenanceState.isScheduledState);
        if (hasProgressedBeyondScheduledState &&
            (scheduledMaintenanceEvent === null || scheduledMaintenanceEvent === void 0 ? void 0 : scheduledMaintenanceEvent.nextSubscriberNotificationBeforeTheEventAt)) {
            await ScheduledMaintenanceService.updateOneById({
                id: createdItem.scheduledMaintenanceId,
                data: {
                    nextSubscriberNotificationBeforeTheEventAt: null,
                },
                props: onCreate.createBy.props,
            });
        }
        if (isOngoingState) {
            if (scheduledMaintenanceEvent &&
                scheduledMaintenanceEvent.monitors &&
                scheduledMaintenanceEvent.monitors.length > 0) {
                for (const monitor of scheduledMaintenanceEvent.monitors) {
                    await MonitorService.updateOneById({
                        id: monitor.id,
                        data: {
                            disableActiveMonitoringBecauseOfScheduledMaintenanceEvent: true, /// This will stop active monitoring.
                        },
                        props: {
                            isRoot: true,
                        },
                    });
                }
            }
        }
        if (isResolvedState || isEndedState) {
            // resolve all the monitors.
            await this.enableActiveMonitoringForMonitors(scheduledMaintenanceEvent);
        }
        const isLastScheduledMaintenanceState = await this.isLastScheduledMaintenanceState({
            projectId: createdItem.projectId,
            scheduledMaintenanceStateId: createdItem.scheduledMaintenanceStateId,
        });
        if (isLastScheduledMaintenanceState) {
            WorkspaceNotificationRuleService.archiveWorkspaceChannels({
                projectId: createdItem.projectId,
                notificationFor: {
                    scheduledMaintenanceId: createdItem.scheduledMaintenanceId,
                },
                sendMessageBeforeArchiving: {
                    _type: "WorkspacePayloadMarkdown",
                    text: `**[Scheduled Event ${scheduledMaintenanceNumberResult.numberWithPrefix || "#" + scheduledMaintenanceNumberResult.number}](${(await ScheduledMaintenanceService.getScheduledMaintenanceLinkInDashboard(createdItem.projectId, createdItem.scheduledMaintenanceId)).toString()})** is complete. Archiving channel.`,
                },
            }).catch((error) => {
                var _a, _b, _c, _d;
                logger.error(`Error while archiving workspace channels:`, {
                    projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                    scheduledMaintenanceId: (_b = createdItem.scheduledMaintenanceId) === null || _b === void 0 ? void 0 : _b.toString(),
                });
                logger.error(error, {
                    projectId: (_c = createdItem.projectId) === null || _c === void 0 ? void 0 : _c.toString(),
                    scheduledMaintenanceId: (_d = createdItem.scheduledMaintenanceId) === null || _d === void 0 ? void 0 : _d.toString(),
                });
            });
        }
        return createdItem;
    }
    async enableActiveMonitoringForMonitors(scheduledMaintenanceEvent) {
        var _a, _b;
        if (scheduledMaintenanceEvent &&
            scheduledMaintenanceEvent.monitors &&
            scheduledMaintenanceEvent.monitors.length > 0) {
            // get resolved monitor state.
            const resolvedMonitorState = await MonitorStatusService.findOneBy({
                query: {
                    projectId: scheduledMaintenanceEvent.projectId,
                    isOperationalState: true,
                },
                props: {
                    isRoot: true,
                },
                select: {
                    _id: true,
                },
            });
            // check if this monitor is not in this status already.
            if (resolvedMonitorState) {
                for (const monitor of scheduledMaintenanceEvent.monitors) {
                    // check if the monitor is not in this status already.
                    const dbMonitor = await MonitorService.findOneById({
                        id: monitor.id,
                        select: {
                            currentMonitorStatusId: true,
                        },
                        props: {
                            isRoot: true,
                        },
                    });
                    const hasMoreOngoingScheduledMaintenanceEvents = await this.hasThisMonitorMoreOngoingScheduledMaintenanceEvents(monitor.id);
                    if (hasMoreOngoingScheduledMaintenanceEvents) {
                        // dont do anything because other events are active at the same time.
                        continue;
                    }
                    await MonitorService.updateOneById({
                        id: monitor.id,
                        data: {
                            disableActiveMonitoringBecauseOfScheduledMaintenanceEvent: false, /// This will start active monitoring again.
                        },
                        props: {
                            isRoot: true,
                        },
                    });
                    if (((_a = dbMonitor === null || dbMonitor === void 0 ? void 0 : dbMonitor.currentMonitorStatusId) === null || _a === void 0 ? void 0 : _a.toString()) ===
                        ((_b = resolvedMonitorState.id) === null || _b === void 0 ? void 0 : _b.toString())) {
                        // if already in resolved state then skip.
                        continue;
                    }
                    const monitorStatusTimeline = new MonitorStatusTimeline();
                    monitorStatusTimeline.monitorId = monitor.id;
                    monitorStatusTimeline.projectId =
                        scheduledMaintenanceEvent.projectId;
                    monitorStatusTimeline.monitorStatusId = resolvedMonitorState.id;
                    await MonitorStatusTimelineService.create({
                        data: monitorStatusTimeline,
                        props: {
                            isRoot: true,
                        },
                    });
                }
            }
        }
    }
    async hasThisMonitorMoreOngoingScheduledMaintenanceEvents(id) {
        const count = await ScheduledMaintenanceService.countBy({
            query: {
                monitors: QueryHelper.inRelationArray([id]),
                currentScheduledMaintenanceState: {
                    isOngoingState: true,
                },
            },
            props: {
                isRoot: true,
            },
        });
        if (count.toNumber() > 0) {
            return true;
        }
        return false;
    }
    async onBeforeDelete(deleteBy) {
        if (deleteBy.query._id) {
            const scheduledMaintenanceStateTimelineToBeDeleted = await this.findOneById({
                id: new ObjectID(deleteBy.query._id),
                select: {
                    scheduledMaintenanceId: true,
                    startsAt: true,
                    endsAt: true,
                },
                props: {
                    isRoot: true,
                },
            });
            const scheduledMaintenanceId = scheduledMaintenanceStateTimelineToBeDeleted === null || scheduledMaintenanceStateTimelineToBeDeleted === void 0 ? void 0 : scheduledMaintenanceStateTimelineToBeDeleted.scheduledMaintenanceId;
            if (scheduledMaintenanceId) {
                const scheduledMaintenanceStateTimeline = await this.countBy({
                    query: {
                        scheduledMaintenanceId: scheduledMaintenanceId,
                    },
                    props: {
                        isRoot: true,
                    },
                });
                if (!scheduledMaintenanceStateTimelineToBeDeleted) {
                    throw new BadDataException("Scheduled maintenance state timeline not found.");
                }
                if (scheduledMaintenanceStateTimeline.isOne()) {
                    throw new BadDataException("Cannot delete the only state timeline. Scheduled Maintenance should have at least one state in its timeline.");
                }
                /*
                 * There are three cases.
                 * 1. This is the first state.
                 * 2. This is the last state.
                 * 3. This is in the middle.
                 */
                const stateBeforeThis = await this.findOneBy({
                    query: {
                        _id: QueryHelper.notEquals(deleteBy.query._id),
                        scheduledMaintenanceId: scheduledMaintenanceId,
                        startsAt: QueryHelper.lessThanEqualTo(scheduledMaintenanceStateTimelineToBeDeleted.startsAt),
                    },
                    sort: {
                        startsAt: SortOrder.Descending,
                    },
                    props: {
                        isRoot: true,
                    },
                    select: {
                        scheduledMaintenanceStateId: true,
                        startsAt: true,
                        endsAt: true,
                    },
                });
                const stateAfterThis = await this.findOneBy({
                    query: {
                        scheduledMaintenanceId: scheduledMaintenanceId,
                        startsAt: QueryHelper.greaterThan(scheduledMaintenanceStateTimelineToBeDeleted.startsAt),
                    },
                    sort: {
                        startsAt: SortOrder.Ascending,
                    },
                    props: {
                        isRoot: true,
                    },
                    select: {
                        scheduledMaintenanceStateId: true,
                        startsAt: true,
                        endsAt: true,
                    },
                });
                if (!stateBeforeThis) {
                    // This is the first state, no need to update previous state.
                    logger.debug("This is the first state.", {
                        scheduledMaintenanceId: scheduledMaintenanceId === null || scheduledMaintenanceId === void 0 ? void 0 : scheduledMaintenanceId.toString(),
                    });
                }
                else if (!stateAfterThis) {
                    /*
                     * This is the last state.
                     * Update the previous state to end at the end of this state.
                     */
                    await this.updateOneById({
                        id: stateBeforeThis.id,
                        data: {
                            endsAt: scheduledMaintenanceStateTimelineToBeDeleted.endsAt,
                        },
                        props: {
                            isRoot: true,
                        },
                    });
                    logger.debug("This is the last state.", {
                        scheduledMaintenanceId: scheduledMaintenanceId === null || scheduledMaintenanceId === void 0 ? void 0 : scheduledMaintenanceId.toString(),
                    });
                }
                else {
                    /*
                     * This state is in the middle.
                     * Update the previous state to end at the start of the next state.
                     */
                    await this.updateOneById({
                        id: stateBeforeThis.id,
                        data: {
                            endsAt: stateAfterThis.startsAt,
                        },
                        props: {
                            isRoot: true,
                        },
                    });
                    // Update the next state to start at the start of this state.
                    await this.updateOneById({
                        id: stateAfterThis.id,
                        data: {
                            startsAt: scheduledMaintenanceStateTimelineToBeDeleted.startsAt,
                        },
                        props: {
                            isRoot: true,
                        },
                    });
                    logger.debug("This state is in the middle.", {
                        scheduledMaintenanceId: scheduledMaintenanceId === null || scheduledMaintenanceId === void 0 ? void 0 : scheduledMaintenanceId.toString(),
                    });
                }
            }
            return { deleteBy, carryForward: scheduledMaintenanceId };
        }
        return { deleteBy, carryForward: null };
    }
    async onDeleteSuccess(onDelete, _itemIdsBeforeDelete) {
        if (onDelete.carryForward) {
            // this is scheduledMaintenanceId.
            const scheduledMaintenanceId = onDelete.carryForward;
            // get last status of this scheduled maintenance.
            const scheduledMaintenanceStateTimeline = await this.findOneBy({
                query: {
                    scheduledMaintenanceId: scheduledMaintenanceId,
                },
                sort: {
                    startsAt: SortOrder.Descending,
                },
                props: {
                    isRoot: true,
                },
                select: {
                    _id: true,
                    scheduledMaintenanceStateId: true,
                },
            });
            if (scheduledMaintenanceStateTimeline &&
                scheduledMaintenanceStateTimeline.scheduledMaintenanceStateId) {
                await ScheduledMaintenanceService.updateOneBy({
                    query: {
                        _id: scheduledMaintenanceId.toString(),
                    },
                    data: {
                        currentScheduledMaintenanceStateId: scheduledMaintenanceStateTimeline.scheduledMaintenanceStateId,
                    },
                    props: {
                        isRoot: true,
                    },
                });
            }
        }
        return onDelete;
    }
}
__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, ScheduledMaintenanceStateTimeline]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onCreateSuccess", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ScheduledMaintenance]),
    __metadata("design:returntype", Promise)
], Service.prototype, "enableActiveMonitoringForMonitors", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID]),
    __metadata("design:returntype", Promise)
], Service.prototype, "hasThisMonitorMoreOngoingScheduledMaintenanceEvents", 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);
export default new Service();
//# sourceMappingURL=ScheduledMaintenanceStateTimelineService.js.map