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 SortOrder from "../../Types/BaseDatabase/SortOrder";
import DatabaseService from "./DatabaseService";
import Model from "../../Models/DatabaseModels/IncidentSlaRule";
import Incident from "../../Models/DatabaseModels/Incident";
import ObjectID from "../../Types/ObjectID";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import logger from "../Utils/Logger";
import { IsBillingEnabled } from "../EnvironmentConfig";
import MonitorService from "./MonitorService";
import IncidentService from "./IncidentService";
export class Service extends DatabaseService {
    constructor() {
        super(Model);
        if (IsBillingEnabled) {
            this.hardDeleteItemsOlderThanInDays("createdAt", 3 * 365); // 3 years
        }
    }
    async onBeforeCreate(createBy) {
        // Auto-assign order on creation
        if (!createBy.data.order) {
            const highestOrderRule = await this.findOneBy({
                query: {
                    projectId: createBy.data.projectId,
                },
                select: {
                    order: true,
                },
                sort: {
                    order: SortOrder.Descending,
                },
                props: {
                    isRoot: true,
                },
            });
            createBy.data.order = ((highestOrderRule === null || highestOrderRule === void 0 ? void 0 : highestOrderRule.order) || 0) + 1;
        }
        return {
            createBy,
            carryForward: null,
        };
    }
    async findMatchingRule(data) {
        var _a, _b, _c, _d, _e;
        logger.debug(`Finding matching SLA rule for incident ${data.incidentId} in project ${data.projectId}`, { projectId: (_a = data.projectId) === null || _a === void 0 ? void 0 : _a.toString() });
        // Get the incident if not provided
        let incident = data.incident || null;
        if (!incident) {
            incident = await IncidentService.findOneById({
                id: data.incidentId,
                select: {
                    projectId: true,
                    title: true,
                    description: true,
                    incidentSeverityId: true,
                    monitors: {
                        _id: true,
                        labels: {
                            _id: true,
                        },
                    },
                    labels: {
                        _id: true,
                    },
                },
                props: {
                    isRoot: true,
                },
            });
        }
        if (!incident) {
            logger.warn(`Incident ${data.incidentId} not found`, {
                projectId: (_b = data.projectId) === null || _b === void 0 ? void 0 : _b.toString(),
            });
            return null;
        }
        // Get all enabled rules sorted by order
        const rules = await this.findBy({
            query: {
                projectId: data.projectId,
                isEnabled: true,
            },
            sort: {
                order: SortOrder.Ascending,
            },
            select: {
                _id: true,
                name: true,
                order: true,
                responseTimeInMinutes: true,
                resolutionTimeInMinutes: true,
                atRiskThresholdInPercentage: true,
                internalNoteReminderIntervalInMinutes: true,
                publicNoteReminderIntervalInMinutes: true,
                internalNoteReminderTemplate: true,
                publicNoteReminderTemplate: true,
                monitors: {
                    _id: true,
                },
                incidentSeverities: {
                    _id: true,
                },
                incidentLabels: {
                    _id: true,
                },
                monitorLabels: {
                    _id: true,
                },
                incidentTitlePattern: true,
                incidentDescriptionPattern: true,
            },
            limit: 100,
            skip: 0,
            props: {
                isRoot: true,
            },
        });
        if (rules.length === 0) {
            logger.debug(`No enabled SLA rules found for project ${data.projectId}`, {
                projectId: (_c = data.projectId) === null || _c === void 0 ? void 0 : _c.toString(),
            });
            return null;
        }
        // Find first matching rule
        for (const rule of rules) {
            const matches = await this.doesIncidentMatchRule(incident, rule);
            if (matches) {
                logger.debug(`Incident ${data.incidentId} matches SLA rule ${rule.name || rule.id}`, { projectId: (_d = data.projectId) === null || _d === void 0 ? void 0 : _d.toString() });
                return rule;
            }
        }
        logger.debug(`Incident ${data.incidentId} did not match any SLA rules`, {
            projectId: (_e = data.projectId) === null || _e === void 0 ? void 0 : _e.toString(),
        });
        return null;
    }
    async doesIncidentMatchRule(incident, rule) {
        var _a, _b, _c, _d;
        logger.debug(`Checking if incident ${incident.id} matches SLA rule ${rule.name || rule.id}`, { projectId: (_a = incident.projectId) === null || _a === void 0 ? void 0 : _a.toString() });
        // Check monitor IDs - if monitors are specified, incident must have at least one of them
        if (rule.monitors && rule.monitors.length > 0) {
            if (!incident.monitors || incident.monitors.length === 0) {
                return false;
            }
            const ruleMonitorIds = rule.monitors.map((m) => {
                var _a;
                return ((_a = m.id) === null || _a === void 0 ? void 0 : _a.toString()) || "";
            });
            const incidentMonitorIds = incident.monitors.map((m) => {
                var _a, _b;
                return ((_a = m.id) === null || _a === void 0 ? void 0 : _a.toString()) || ((_b = m._id) === null || _b === void 0 ? void 0 : _b.toString()) || "";
            });
            const hasMatchingMonitor = ruleMonitorIds.some((monitorId) => {
                return incidentMonitorIds.includes(monitorId);
            });
            if (!hasMatchingMonitor) {
                return false;
            }
        }
        // Check incident severity IDs - if severities are specified, incident must have one of them
        if (rule.incidentSeverities && rule.incidentSeverities.length > 0) {
            if (!incident.incidentSeverityId) {
                return false;
            }
            const severityIds = rule.incidentSeverities.map((s) => {
                var _a;
                return ((_a = s.id) === null || _a === void 0 ? void 0 : _a.toString()) || "";
            });
            const incidentSeverityIdStr = incident.incidentSeverityId.toString();
            if (!severityIds.includes(incidentSeverityIdStr)) {
                return false;
            }
        }
        // Check incident label IDs - if incident labels are specified, incident must have at least one of them
        if (rule.incidentLabels && rule.incidentLabels.length > 0) {
            if (!incident.labels || incident.labels.length === 0) {
                return false;
            }
            const ruleLabelIds = rule.incidentLabels.map((l) => {
                var _a;
                return ((_a = l.id) === null || _a === void 0 ? void 0 : _a.toString()) || "";
            });
            const incidentLabelIds = incident.labels.map((l) => {
                var _a, _b;
                return ((_a = l.id) === null || _a === void 0 ? void 0 : _a.toString()) || ((_b = l._id) === null || _b === void 0 ? void 0 : _b.toString()) || "";
            });
            const hasMatchingLabel = ruleLabelIds.some((labelId) => {
                return incidentLabelIds.includes(labelId);
            });
            if (!hasMatchingLabel) {
                return false;
            }
        }
        // Check monitor labels - incident's monitors must have at least one matching label
        if (rule.monitorLabels && rule.monitorLabels.length > 0) {
            if (!incident.monitors || incident.monitors.length === 0) {
                return false;
            }
            const ruleMonitorLabelIds = rule.monitorLabels.map((l) => {
                var _a;
                return ((_a = l.id) === null || _a === void 0 ? void 0 : _a.toString()) || "";
            });
            // Get labels from incident's monitors
            let hasMatchingMonitorLabel = false;
            for (const incidentMonitor of incident.monitors) {
                // Load monitor labels if not already loaded
                let monitorLabels = incidentMonitor.labels;
                if (!monitorLabels) {
                    const monitorId = incidentMonitor.id
                        ? incidentMonitor.id
                        : incidentMonitor._id
                            ? new ObjectID(incidentMonitor._id.toString())
                            : undefined;
                    if (monitorId) {
                        const monitor = await MonitorService.findOneById({
                            id: monitorId,
                            select: {
                                labels: {
                                    _id: true,
                                },
                            },
                            props: {
                                isRoot: true,
                            },
                        });
                        monitorLabels = monitor === null || monitor === void 0 ? void 0 : monitor.labels;
                    }
                }
                if (monitorLabels && monitorLabels.length > 0) {
                    const monitorLabelIds = monitorLabels.map((l) => {
                        var _a, _b;
                        return ((_a = l.id) === null || _a === void 0 ? void 0 : _a.toString()) || ((_b = l._id) === null || _b === void 0 ? void 0 : _b.toString()) || "";
                    });
                    hasMatchingMonitorLabel = ruleMonitorLabelIds.some((labelId) => {
                        return monitorLabelIds.includes(labelId);
                    });
                    if (hasMatchingMonitorLabel) {
                        break;
                    }
                }
            }
            if (!hasMatchingMonitorLabel) {
                return false;
            }
        }
        // Check incident title pattern (regex)
        if (rule.incidentTitlePattern) {
            if (!incident.title) {
                return false;
            }
            try {
                const regex = new RegExp(rule.incidentTitlePattern, "i");
                if (!regex.test(incident.title)) {
                    return false;
                }
            }
            catch (_e) {
                logger.warn(`Invalid regex pattern in SLA rule ${rule.id}: ${rule.incidentTitlePattern}`, { projectId: (_b = incident.projectId) === null || _b === void 0 ? void 0 : _b.toString() });
                return false;
            }
        }
        // Check incident description pattern (regex)
        if (rule.incidentDescriptionPattern) {
            if (!incident.description) {
                return false;
            }
            try {
                const regex = new RegExp(rule.incidentDescriptionPattern, "i");
                if (!regex.test(incident.description)) {
                    return false;
                }
            }
            catch (_f) {
                logger.warn(`Invalid regex pattern in SLA rule ${rule.id}: ${rule.incidentDescriptionPattern}`, { projectId: (_c = incident.projectId) === null || _c === void 0 ? void 0 : _c.toString() });
                return false;
            }
        }
        // If no criteria specified (all fields empty), rule matches all incidents
        logger.debug(`SLA rule ${rule.name || rule.id} matched incident ${incident.id} (all criteria passed)`, { projectId: (_d = incident.projectId) === null || _d === void 0 ? void 0 : _d.toString() });
        return true;
    }
}
__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]),
    __metadata("design:returntype", Promise)
], Service.prototype, "findMatchingRule", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Incident,
        Model]),
    __metadata("design:returntype", Promise)
], Service.prototype, "doesIncidentMatchRule", null);
export default new Service();
//# sourceMappingURL=IncidentSlaRuleService.js.map