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 OnCallDutyPolicyExecutionLogService from "./OnCallDutyPolicyExecutionLogService";
import BadDataException from "../../Types/Exception/BadDataException";
import ObjectID from "../../Types/ObjectID";
import OnCallDutyPolicyStatus from "../../Types/OnCallDutyPolicy/OnCallDutyPolicyStatus";
import UserNotificationEventType from "../../Types/UserNotification/UserNotificationEventType";
import OnCallDutyPolicy from "../../Models/DatabaseModels/OnCallDutyPolicy";
import OnCallDutyPolicyExecutionLog from "../../Models/DatabaseModels/OnCallDutyPolicyExecutionLog";
import DatabaseConfig from "../DatabaseConfig";
import URL from "../../Types/API/URL";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import OnCallDutyPolicyScheduleService from "./OnCallDutyPolicyScheduleService";
import TeamService from "./TeamService";
import OnCallDutyPolicyEscalationRuleUserService from "./OnCallDutyPolicyEscalationRuleUserService";
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
import OnCallDutyPolicyEscalationRuleTeamService from "./OnCallDutyPolicyEscalationRuleTeamService";
import QueryHelper from "../Types/Database/QueryHelper";
import OnCallDutyPolicyEscalationRuleScheduleService from "./OnCallDutyPolicyEscalationRuleScheduleService";
import WorkspaceNotificationRuleService from "./WorkspaceNotificationRuleService";
import logger from "../Utils/Logger";
import OnCallDutyPolicyWorkspaceMessages from "../Utils/Workspace/WorkspaceMessages/OnCallDutyPolicy";
import OnCallDutyPolicyFeedService from "./OnCallDutyPolicyFeedService";
import { OnCallDutyPolicyFeedEventType } from "../../Models/DatabaseModels/OnCallDutyPolicyFeed";
import { Green500 } from "../../Types/BrandColors";
import OnCallDutyPolicyLabelRuleEngineService from "./OnCallDutyPolicyLabelRuleEngineService";
import OnCallDutyPolicyOwnerRuleEngineService from "./OnCallDutyPolicyOwnerRuleEngineService";
export class Service extends DatabaseService {
    constructor() {
        super(OnCallDutyPolicy);
    }
    async onCreateSuccess(_onCreate, createdItem) {
        var _a, _b, _c, _d;
        if (!createdItem.id) {
            throw new BadDataException("On Call Policy id not found.");
        }
        if (createdItem.projectId) {
            try {
                await OnCallDutyPolicyLabelRuleEngineService.applyRulesToOnCallDutyPolicy(createdItem);
                await OnCallDutyPolicyOwnerRuleEngineService.applyRulesToOnCallDutyPolicy(createdItem);
            }
            catch (error) {
                logger.error(`Error applying on-call duty policy rules in OnCallDutyPolicyService.onCreateSuccess: ${error}`, {
                    projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                    onCallDutyPolicyId: (_b = createdItem.id) === null || _b === void 0 ? void 0 : _b.toString(),
                });
            }
        }
        const onCallPolicy = await this.findOneById({
            id: createdItem.id,
            select: {
                projectId: true,
                name: true,
                description: true,
                labels: {
                    name: true,
                },
            },
            props: {
                isRoot: true,
            },
        });
        if (!onCallPolicy) {
            throw new BadDataException("On Call Policy not found.");
        }
        const createdByUserId = createdItem.createdByUserId || ((_c = createdItem.createdByUser) === null || _c === void 0 ? void 0 : _c.id);
        let feedInfoInMarkdown = `#### 📞 On Call Policy Created: 
              
**${onCallPolicy.name || "No name provided."}**:
    
${onCallPolicy.description || "No description provided."}
        
`;
        if ((onCallPolicy === null || onCallPolicy === void 0 ? void 0 : onCallPolicy.labels) && onCallPolicy.labels.length > 0) {
            feedInfoInMarkdown += `🏷️ **Labels**:\n`;
            for (const label of onCallPolicy.labels) {
                feedInfoInMarkdown += `- ${label.name}\n`;
            }
            feedInfoInMarkdown += `\n\n`;
        }
        // send message to workspaces - slack, teams,   etc.
        const workspaceResult = await OnCallDutyPolicyWorkspaceMessages.createChannelsAndInviteUsersToChannels({
            projectId: onCallPolicy.projectId,
            onCallDutyPolicyId: onCallPolicy.id,
            onCallDutyPolicyName: onCallPolicy.name,
        });
        if (workspaceResult && ((_d = workspaceResult.channelsCreated) === null || _d === void 0 ? void 0 : _d.length) > 0) {
            // update incident with these channels.
            await this.updateOneById({
                id: createdItem.id,
                data: {
                    postUpdatesToWorkspaceChannels: workspaceResult.channelsCreated || [],
                },
                props: {
                    isRoot: true,
                },
            });
        }
        const onCallDutyPolicyCreateMessageBlocks = await OnCallDutyPolicyWorkspaceMessages.getOnCallDutyPolicyCreateMessageBlocks({
            onCallDutyPolicyId: createdItem.id,
            projectId: createdItem.projectId,
        });
        await OnCallDutyPolicyFeedService.createOnCallDutyPolicyFeedItem({
            onCallDutyPolicyId: createdItem.id,
            projectId: createdItem.projectId,
            onCallDutyPolicyFeedEventType: OnCallDutyPolicyFeedEventType.OnCallDutyPolicyCreated,
            displayColor: Green500,
            feedInfoInMarkdown: feedInfoInMarkdown,
            userId: createdByUserId || undefined,
            workspaceNotification: {
                appendMessageBlocks: onCallDutyPolicyCreateMessageBlocks,
                sendWorkspaceNotification: true,
            },
        });
        return createdItem;
    }
    async onBeforeDelete(deleteBy) {
        if (deleteBy.query._id) {
            let projectId = deleteBy.query.projectId || deleteBy.props.tenantId;
            if (!projectId) {
                // fetch this onCallDutyPolicy from the database to get the projectId.
                const onCallDutyPolicy = await this.findOneById({
                    id: new ObjectID(deleteBy.query._id),
                    select: {
                        projectId: true,
                    },
                    props: {
                        isRoot: true,
                    },
                });
                if (!onCallDutyPolicy) {
                    throw new BadDataException("OnCallDutyPolicy not found.");
                }
                if (!onCallDutyPolicy.id) {
                    throw new BadDataException("OnCallDutyPolicy id not found.");
                }
                projectId = onCallDutyPolicy.projectId;
            }
            try {
                await WorkspaceNotificationRuleService.archiveWorkspaceChannels({
                    projectId: projectId,
                    notificationFor: {
                        onCallDutyPolicyId: new ObjectID(deleteBy.query._id),
                    },
                    sendMessageBeforeArchiving: {
                        _type: "WorkspacePayloadMarkdown",
                        text: `🗑️ This on-call policy is deleted. The channel is being archived.`,
                    },
                });
            }
            catch (error) {
                logger.error(`Error while archiving workspace channels for onCallDutyPolicy ${deleteBy.query._id}: ${error}`, { projectId: projectId === null || projectId === void 0 ? void 0 : projectId.toString() });
            }
        }
        return { deleteBy, carryForward: null };
    }
    async getWorkspaceChannelForOnCallDutyPolicy(data) {
        const onCallDutyPolicy = await this.findOneById({
            id: data.onCallDutyPolicyId,
            select: {
                postUpdatesToWorkspaceChannels: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (!onCallDutyPolicy) {
            throw new BadDataException("OnCallDutyPolicy not found.");
        }
        return (onCallDutyPolicy.postUpdatesToWorkspaceChannels || []).filter((channel) => {
            if (!data.workspaceType) {
                return true;
            }
            return channel.workspaceType === data.workspaceType;
        });
    }
    async getOnCallDutyPolicyLinkInDashboard(projectId, onCallDutyPolicyId) {
        const dashboardUrl = await DatabaseConfig.getDashboardUrl();
        return URL.fromString(dashboardUrl.toString()).addRoute(`/${projectId.toString()}/on-call-duty/policies/${onCallDutyPolicyId.toString()}`);
    }
    async getOnCallDutyPolicyName(data) {
        const { onCallDutyPolicyId } = data;
        const onCallDutyPolicy = await this.findOneById({
            id: onCallDutyPolicyId,
            select: {
                name: true,
            },
            props: {
                isRoot: true,
            },
        });
        return onCallDutyPolicy && onCallDutyPolicy.name
            ? onCallDutyPolicy.name.toString()
            : null;
    }
    async executePolicy(policyId, options) {
        // execute this policy
        if (UserNotificationEventType.IncidentCreated ===
            options.userNotificationEventType &&
            !options.triggeredByIncidentId) {
            throw new BadDataException("triggeredByIncidentId is required when userNotificationEventType is IncidentCreated");
        }
        if (UserNotificationEventType.AlertCreated ===
            options.userNotificationEventType &&
            !options.triggeredByAlertId) {
            throw new BadDataException("triggeredByAlertId is required when userNotificationEventType is AlertCreated");
        }
        if (UserNotificationEventType.AlertEpisodeCreated ===
            options.userNotificationEventType &&
            !options.triggeredByAlertEpisodeId) {
            throw new BadDataException("triggeredByAlertEpisodeId is required when userNotificationEventType is AlertEpisodeCreated");
        }
        if (UserNotificationEventType.IncidentEpisodeCreated ===
            options.userNotificationEventType &&
            !options.triggeredByIncidentEpisodeId) {
            throw new BadDataException("triggeredByIncidentEpisodeId is required when userNotificationEventType is IncidentEpisodeCreated");
        }
        const policy = await this.findOneById({
            id: policyId,
            select: {
                _id: true,
                projectId: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (!policy) {
            throw new BadDataException(`On-Call Duty Policy with id ${policyId.toString()} not found`);
        }
        // add policy log.
        const log = new OnCallDutyPolicyExecutionLog();
        log.projectId = policy.projectId;
        log.onCallDutyPolicyId = policyId;
        log.userNotificationEventType = options.userNotificationEventType;
        log.statusMessage = "Scheduled.";
        log.status = OnCallDutyPolicyStatus.Scheduled;
        if (options.triggeredByIncidentId) {
            log.triggeredByIncidentId = options.triggeredByIncidentId;
        }
        if (options.triggeredByAlertId) {
            log.triggeredByAlertId = options.triggeredByAlertId;
        }
        if (options.triggeredByAlertEpisodeId) {
            log.triggeredByAlertEpisodeId = options.triggeredByAlertEpisodeId;
        }
        if (options.triggeredByIncidentEpisodeId) {
            log.triggeredByIncidentEpisodeId = options.triggeredByIncidentEpisodeId;
        }
        await OnCallDutyPolicyExecutionLogService.create({
            data: log,
            props: {
                isRoot: true,
            },
        });
    }
    async getOnCallPoliciesWhereUserIsOnCallDuty(data) {
        // get all schedules where user is on call duty.
        const onCallSchedules = await OnCallDutyPolicyScheduleService.getOnCallSchedulesWhereUserIsOnCallDuty(data);
        const teams = await TeamService.getTeamsUserIsAPartOf({
            userId: data.userId,
            projectId: data.projectId,
        });
        // get escalationPolicies by user, team and schedule.
        const escalationRulesByUser = await OnCallDutyPolicyEscalationRuleUserService.findBy({
            query: {
                userId: data.userId,
                projectId: data.projectId,
            },
            select: {
                onCallDutyPolicyEscalationRule: {
                    name: true,
                    _id: true,
                    order: true,
                },
                onCallDutyPolicy: {
                    name: true,
                    _id: true,
                },
            },
            limit: LIMIT_PER_PROJECT,
            skip: 0,
            props: {
                isRoot: true,
            },
        });
        // do the same for teams.
        const escalationRulesByTeam = await OnCallDutyPolicyEscalationRuleTeamService.findBy({
            query: {
                teamId: QueryHelper.any(teams.map((team) => {
                    return team.id;
                })),
                projectId: data.projectId,
            },
            select: {
                onCallDutyPolicy: {
                    name: true,
                    _id: true,
                },
                onCallDutyPolicyEscalationRule: {
                    name: true,
                    _id: true,
                    order: true,
                },
                team: {
                    name: true,
                    _id: true,
                },
            },
            limit: LIMIT_PER_PROJECT,
            skip: 0,
            props: {
                isRoot: true,
            },
        });
        // do the same for schedules.
        const escalationRulesBySchedule = await OnCallDutyPolicyEscalationRuleScheduleService.findBy({
            query: {
                onCallDutyPolicyScheduleId: QueryHelper.any(onCallSchedules.map((schedule) => {
                    return schedule.id;
                })),
                projectId: data.projectId,
            },
            select: {
                onCallDutyPolicy: {
                    name: true,
                    _id: true,
                },
                onCallDutyPolicyEscalationRule: {
                    name: true,
                    _id: true,
                    order: true,
                },
                onCallDutyPolicySchedule: {
                    name: true,
                    _id: true,
                },
            },
            limit: LIMIT_PER_PROJECT,
            skip: 0,
            props: {
                isRoot: true,
            },
        });
        return {
            escalationRulesByUser: escalationRulesByUser,
            escalationRulesByTeam: escalationRulesByTeam,
            escalationRulesBySchedule: escalationRulesBySchedule,
        };
    }
}
__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]),
    __metadata("design:returntype", Promise)
], Service.prototype, "getWorkspaceChannelForOnCallDutyPolicy", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID,
        ObjectID]),
    __metadata("design:returntype", Promise)
], Service.prototype, "getOnCallDutyPolicyLinkInDashboard", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "getOnCallDutyPolicyName", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID, Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "executePolicy", null);
export default new Service();
//# sourceMappingURL=OnCallDutyPolicyService.js.map