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 DatabaseService from "./DatabaseService";
import IncidentService from "./IncidentService";
import OnCallDutyPolicyExecutionLogTimelineService from "./OnCallDutyPolicyExecutionLogTimelineService";
import UserNotificationRuleService from "./UserNotificationRuleService";
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
import BadDataException from "../../Types/Exception/BadDataException";
import NotificationRuleType from "../../Types/NotificationRule/NotificationRuleType";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import OnCallDutyExecutionLogTimelineStatus from "../../Types/OnCallDutyPolicy/OnCalDutyExecutionLogTimelineStatus";
import PositiveNumber from "../../Types/PositiveNumber";
import UserNotificationEventType from "../../Types/UserNotification/UserNotificationEventType";
import UserNotificationExecutionStatus from "../../Types/UserNotification/UserNotificationExecutionStatus";
import Model from "../../Models/DatabaseModels/UserOnCallLog";
import { IsBillingEnabled } from "../EnvironmentConfig";
import AlertService from "./AlertService";
import AlertEpisodeService from "./AlertEpisodeService";
import IncidentEpisodeService from "./IncidentEpisodeService";
export class Service extends DatabaseService {
    constructor() {
        super(Model);
        if (IsBillingEnabled) {
            this.hardDeleteItemsOlderThanInDays("createdAt", 30);
        }
    }
    async onBeforeCreate(createBy) {
        createBy.data.status = UserNotificationExecutionStatus.Scheduled;
        return {
            createBy,
            carryForward: null,
        };
    }
    async onUpdateSuccess(onUpdate, _updatedItemIds) {
        if (onUpdate.updateBy.data.status) {
            //update the corresponding oncallTimeline.
            const items = await this.findBy({
                query: onUpdate.updateBy.query,
                select: {
                    onCallDutyPolicyExecutionLogTimelineId: true,
                },
                skip: 0,
                limit: LIMIT_PER_PROJECT,
                props: {
                    isRoot: true,
                },
            });
            let status = undefined;
            switch (onUpdate.updateBy.data.status) {
                case UserNotificationExecutionStatus.Completed:
                    status = OnCallDutyExecutionLogTimelineStatus.NotificationSent;
                    break;
                case UserNotificationExecutionStatus.Error:
                    status = OnCallDutyExecutionLogTimelineStatus.Error;
                    break;
                case UserNotificationExecutionStatus.Executing:
                    status = OnCallDutyExecutionLogTimelineStatus.Executing;
                    break;
                case UserNotificationExecutionStatus.Scheduled:
                    status = OnCallDutyExecutionLogTimelineStatus.Started;
                    break;
                case UserNotificationExecutionStatus.Started:
                    status = OnCallDutyExecutionLogTimelineStatus.Started;
                    break;
                default:
                    throw new BadDataException("Invalid status");
            }
            for (const item of items) {
                await OnCallDutyPolicyExecutionLogTimelineService.updateOneById({
                    id: item.onCallDutyPolicyExecutionLogTimelineId,
                    data: {
                        status: status,
                        statusMessage: onUpdate.updateBy.data.statusMessage,
                    },
                    props: {
                        isRoot: true,
                    },
                });
            }
        }
        return onUpdate;
    }
    async onCreateSuccess(_onCreate, createdItem) {
        // update this item to be processed.
        await this.updateOneById({
            id: createdItem.id,
            data: {
                status: UserNotificationExecutionStatus.Started,
            },
            props: {
                isRoot: true,
            },
        });
        const notificationRuleType = this.getNotificationRuleType(createdItem.userNotificationEventType);
        let ruleCount = new PositiveNumber(0);
        let incident = null;
        let alert = null;
        let alertEpisode = null;
        if (createdItem.triggeredByIncidentId) {
            incident = await IncidentService.findOneById({
                id: createdItem.triggeredByIncidentId,
                props: {
                    isRoot: true,
                },
                select: {
                    incidentSeverityId: true,
                },
            });
            // Check if there are any rules .
            ruleCount = await UserNotificationRuleService.countBy({
                query: {
                    userId: createdItem.userId,
                    projectId: createdItem.projectId,
                    ruleType: notificationRuleType,
                    incidentSeverityId: incident === null || incident === void 0 ? void 0 : incident.incidentSeverityId,
                },
                skip: 0,
                limit: LIMIT_PER_PROJECT,
                props: {
                    isRoot: true,
                },
            });
        }
        // get rule count for alerts.
        if (createdItem.triggeredByAlertId) {
            alert = await AlertService.findOneById({
                id: createdItem.triggeredByAlertId,
                props: {
                    isRoot: true,
                },
                select: {
                    alertSeverityId: true,
                },
            });
            ruleCount = await UserNotificationRuleService.countBy({
                query: {
                    userId: createdItem.userId,
                    projectId: createdItem.projectId,
                    ruleType: notificationRuleType,
                    alertSeverityId: alert === null || alert === void 0 ? void 0 : alert.alertSeverityId,
                },
                skip: 0,
                limit: LIMIT_PER_PROJECT,
                props: {
                    isRoot: true,
                },
            });
        }
        // get rule count for alert episodes.
        if (createdItem.triggeredByAlertEpisodeId) {
            alertEpisode = await AlertEpisodeService.findOneById({
                id: createdItem.triggeredByAlertEpisodeId,
                props: {
                    isRoot: true,
                },
                select: {
                    alertSeverityId: true,
                },
            });
            ruleCount = await UserNotificationRuleService.countBy({
                query: {
                    userId: createdItem.userId,
                    projectId: createdItem.projectId,
                    ruleType: notificationRuleType,
                    alertSeverityId: alertEpisode === null || alertEpisode === void 0 ? void 0 : alertEpisode.alertSeverityId,
                },
                skip: 0,
                limit: LIMIT_PER_PROJECT,
                props: {
                    isRoot: true,
                },
            });
        }
        // get rule count for incident episodes.
        let incidentEpisode = null;
        if (createdItem.triggeredByIncidentEpisodeId) {
            incidentEpisode = await IncidentEpisodeService.findOneById({
                id: createdItem.triggeredByIncidentEpisodeId,
                props: {
                    isRoot: true,
                },
                select: {
                    incidentSeverityId: true,
                },
            });
            ruleCount = await UserNotificationRuleService.countBy({
                query: {
                    userId: createdItem.userId,
                    projectId: createdItem.projectId,
                    ruleType: notificationRuleType,
                    incidentSeverityId: incidentEpisode === null || incidentEpisode === void 0 ? void 0 : incidentEpisode.incidentSeverityId,
                },
                skip: 0,
                limit: LIMIT_PER_PROJECT,
                props: {
                    isRoot: true,
                },
            });
        }
        if (ruleCount.toNumber() === 0) {
            // update this item to be processed.
            await this.updateOneById({
                id: createdItem.id,
                data: {
                    status: UserNotificationExecutionStatus.Error, // now the worker will pick this up and complete this or mark this as failed.
                    statusMessage: "No notification rules found for this user. User should add the rules in User Settings > On-Call Rules.",
                },
                props: {
                    isRoot: true,
                },
            });
            // update oncall timeline item as well.
            await OnCallDutyPolicyExecutionLogTimelineService.updateOneById({
                id: createdItem.onCallDutyPolicyExecutionLogTimelineId,
                data: {
                    status: OnCallDutyExecutionLogTimelineStatus.Error,
                    statusMessage: "No notification rules found for this user. User should add the rules in User Settings > On-Call Rules.",
                },
                props: {
                    isRoot: true,
                },
            });
            return createdItem;
        }
        /*
         * find immediate notification rule and alert the user.
         * Determine the alertSeverityId - can come from alert or alertEpisode
         * Determine the incidentSeverityId - can come from incident or incidentEpisode
         */
        const alertSeverityIdForQuery = alert && alert.alertSeverityId
            ? alert.alertSeverityId
            : alertEpisode && alertEpisode.alertSeverityId
                ? alertEpisode.alertSeverityId
                : undefined;
        const incidentSeverityIdForQuery = incident && incident.incidentSeverityId
            ? incident.incidentSeverityId
            : incidentEpisode && incidentEpisode.incidentSeverityId
                ? incidentEpisode.incidentSeverityId
                : undefined;
        const immediateNotificationRule = await UserNotificationRuleService.findBy({
            query: {
                userId: createdItem.userId,
                projectId: createdItem.projectId,
                notifyAfterMinutes: 0,
                ruleType: notificationRuleType,
                incidentSeverityId: incidentSeverityIdForQuery,
                alertSeverityId: alertSeverityIdForQuery,
            },
            select: {
                _id: true,
            },
            skip: 0,
            limit: LIMIT_PER_PROJECT,
            props: {
                isRoot: true,
            },
        });
        for (const immediateNotificationRuleItem of immediateNotificationRule) {
            await UserNotificationRuleService.executeNotificationRuleItem(immediateNotificationRuleItem.id, {
                userNotificationLogId: createdItem.id,
                projectId: createdItem.projectId,
                triggeredByIncidentId: createdItem.triggeredByIncidentId,
                triggeredByAlertId: createdItem.triggeredByAlertId,
                triggeredByAlertEpisodeId: createdItem.triggeredByAlertEpisodeId,
                triggeredByIncidentEpisodeId: createdItem.triggeredByIncidentEpisodeId,
                userNotificationEventType: createdItem.userNotificationEventType,
                onCallPolicyExecutionLogId: createdItem.onCallDutyPolicyExecutionLogId,
                onCallPolicyId: createdItem.onCallDutyPolicyId,
                onCallPolicyEscalationRuleId: createdItem.onCallDutyPolicyEscalationRuleId,
                userBelongsToTeamId: createdItem.userBelongsToTeamId,
                onCallDutyPolicyExecutionLogTimelineId: createdItem.onCallDutyPolicyExecutionLogTimelineId,
                onCallScheduleId: createdItem.onCallDutyScheduleId,
            });
        }
        // update this item to be processed.
        await this.updateOneById({
            id: createdItem.id,
            data: {
                status: UserNotificationExecutionStatus.Executing, // now the worker will pick this up and complete this or mark this as failed.
            },
            props: {
                isRoot: true,
            },
        });
        // update oncall timeline item as well.
        await OnCallDutyPolicyExecutionLogTimelineService.updateOneById({
            id: createdItem.onCallDutyPolicyExecutionLogTimelineId,
            data: {
                status: OnCallDutyExecutionLogTimelineStatus.NotificationSent,
                statusMessage: "Alert Sent",
            },
            props: {
                isRoot: true,
            },
        });
        return createdItem;
    }
    getNotificationRuleType(userNotificationEventType) {
        if (userNotificationEventType === UserNotificationEventType.IncidentCreated) {
            return NotificationRuleType.ON_CALL_EXECUTED_INCIDENT;
        }
        if (userNotificationEventType === UserNotificationEventType.AlertCreated) {
            return NotificationRuleType.ON_CALL_EXECUTED_ALERT;
        }
        if (userNotificationEventType ===
            UserNotificationEventType.AlertEpisodeCreated) {
            return NotificationRuleType.ON_CALL_EXECUTED_ALERT_EPISODE;
        }
        if (userNotificationEventType ===
            UserNotificationEventType.IncidentEpisodeCreated) {
            return NotificationRuleType.ON_CALL_EXECUTED_INCIDENT_EPISODE;
        }
        // Invalid user notification event type.
        throw new BadDataException("Invalid user notification event type.");
    }
}
__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, Array]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onUpdateSuccess", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Model]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onCreateSuccess", null);
export default new Service();
//# sourceMappingURL=UserOnCallLogService.js.map