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 Alert from "../../Models/DatabaseModels/Alert";
import Incident from "../../Models/DatabaseModels/Incident";
import RunbookExecution from "../../Models/DatabaseModels/RunbookExecution";
import ScheduledMaintenance from "../../Models/DatabaseModels/ScheduledMaintenance";
import ObjectID from "../../Types/ObjectID";
import RunbookExecutionStatus from "../../Types/Runbook/RunbookExecutionStatus";
import RunbookRuleTriggerEntity from "../../Types/Runbook/RunbookRuleTriggerEntity";
import RunbookStepExecutionStatus from "../../Types/Runbook/RunbookStepExecutionStatus";
import RunbookExecutionService from "./RunbookExecutionService";
import RunbookRuleService from "./RunbookRuleService";
import RunbookService from "./RunbookService";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import logger from "../Utils/Logger";
class RunbookRuleEngineServiceClass {
    constructor() {
        // Lazily-set queue hook so Common doesn't depend on App/FeatureSet.
        this.enqueue = null;
    }
    registerExecutionEnqueuer(fn) {
        this.enqueue = fn;
    }
    async applyRulesToIncident(incident) {
        if (!incident.id || !incident.projectId) {
            return;
        }
        await this.applyRules({
            projectId: incident.projectId,
            triggerEntityType: RunbookRuleTriggerEntity.Incident,
            title: incident.title,
            description: incident.description,
            linkage: { incidentId: incident.id },
        });
    }
    async applyRulesToAlert(alert) {
        if (!alert.id || !alert.projectId) {
            return;
        }
        await this.applyRules({
            projectId: alert.projectId,
            triggerEntityType: RunbookRuleTriggerEntity.Alert,
            title: alert.title,
            description: alert.description,
            linkage: { alertId: alert.id },
        });
    }
    async applyRulesToScheduledMaintenance(event) {
        if (!event.id || !event.projectId) {
            return;
        }
        await this.applyRules({
            projectId: event.projectId,
            triggerEntityType: RunbookRuleTriggerEntity.ScheduledMaintenance,
            title: event.title,
            description: event.description,
            linkage: { scheduledMaintenanceId: event.id },
        });
    }
    async applyRules(data) {
        var _a;
        try {
            const rules = await RunbookRuleService.findBy({
                query: {
                    projectId: data.projectId,
                    isEnabled: true,
                    triggerEntityType: data.triggerEntityType,
                },
                props: { isRoot: true },
                select: {
                    _id: true,
                    name: true,
                    titlePattern: true,
                    descriptionPattern: true,
                    runbooks: { _id: true },
                },
                limit: 100,
                skip: 0,
            });
            if (rules.length === 0) {
                return;
            }
            const runbookIdsToStart = new Set();
            const matchedRuleNames = [];
            for (const rule of rules) {
                if (!this.matches(rule, data.title, data.description)) {
                    continue;
                }
                const runbookIds = (rule.runbooks || [])
                    .map((rb) => {
                    var _a;
                    return ((_a = rb.id) === null || _a === void 0 ? void 0 : _a.toString()) || "";
                })
                    .filter((id) => {
                    return id !== "";
                });
                if (runbookIds.length === 0) {
                    continue;
                }
                for (const id of runbookIds) {
                    runbookIdsToStart.add(id);
                }
                if (rule.name) {
                    matchedRuleNames.push(rule.name);
                }
            }
            if (runbookIdsToStart.size === 0) {
                return;
            }
            for (const runbookIdStr of runbookIdsToStart) {
                await this.startRunbookFor({
                    projectId: data.projectId,
                    runbookId: new ObjectID(runbookIdStr),
                    linkage: data.linkage,
                });
            }
            logger.debug(`RunbookRuleEngine: started ${runbookIdsToStart.size} runbook(s) for ${data.triggerEntityType}`, {
                projectId: data.projectId.toString(),
                matchedRules: matchedRuleNames.join(", "),
            });
        }
        catch (error) {
            logger.error(`Error applying runbook rules: ${error}`, {
                projectId: (_a = data.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
                triggerEntityType: data.triggerEntityType,
            });
        }
    }
    matches(rule, title, description) {
        if (rule.titlePattern) {
            if (!title || !this.testRegex(rule.titlePattern, title, rule)) {
                return false;
            }
        }
        if (rule.descriptionPattern) {
            if (!description ||
                !this.testRegex(rule.descriptionPattern, description, rule)) {
                return false;
            }
        }
        return true;
    }
    testRegex(pattern, value, rule) {
        try {
            const regex = new RegExp(pattern, "i");
            return regex.test(value);
        }
        catch (_a) {
            logger.warn(`Invalid regex in runbook rule ${rule.id}: ${pattern}`);
            return false;
        }
    }
    async startRunbookFor(data) {
        var _a, _b;
        const runbook = await RunbookService.findOneById({
            id: data.runbookId,
            select: {
                _id: true,
                projectId: true,
                name: true,
                steps: true,
                isEnabled: true,
            },
            props: { isRoot: true },
        });
        if (!runbook) {
            return null;
        }
        if (((_a = runbook.projectId) === null || _a === void 0 ? void 0 : _a.toString()) !== data.projectId.toString()) {
            return null;
        }
        if (runbook.isEnabled === false) {
            return null;
        }
        const steps = runbook.steps || [];
        if (steps.length === 0) {
            return null;
        }
        const stepExecutions = steps
            .slice()
            .sort((a, b) => {
            return a.order - b.order;
        })
            .map((step) => {
            return {
                step,
                status: RunbookStepExecutionStatus.Pending,
            };
        });
        const execution = new RunbookExecution();
        execution.projectId = runbook.projectId;
        execution.runbookId = new ObjectID(runbook._id);
        execution.runbookNameSnapshot = runbook.name || "Runbook";
        execution.status = RunbookExecutionStatus.Scheduled;
        execution.stepExecutions = stepExecutions;
        if (data.linkage.incidentId) {
            execution.incidentId = data.linkage.incidentId;
        }
        if (data.linkage.alertId) {
            execution.alertId = data.linkage.alertId;
        }
        if (data.linkage.scheduledMaintenanceId) {
            execution.scheduledMaintenanceId = data.linkage.scheduledMaintenanceId;
        }
        if (data.triggeredByUserId) {
            execution.triggeredByUserId = data.triggeredByUserId;
        }
        const created = await RunbookExecutionService.create({
            data: execution,
            props: { isRoot: true },
        });
        if (this.enqueue) {
            try {
                await this.enqueue({
                    runbookExecutionId: new ObjectID(created._id),
                });
            }
            catch (err) {
                logger.error(`RunbookRuleEngine: failed to enqueue runbook execution: ${err}`, {
                    runbookExecutionId: (_b = created._id) === null || _b === void 0 ? void 0 : _b.toString(),
                });
            }
        }
        else {
            logger.warn("RunbookRuleEngine: enqueue hook not registered; execution created but not started.");
        }
        return created;
    }
}
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Incident]),
    __metadata("design:returntype", Promise)
], RunbookRuleEngineServiceClass.prototype, "applyRulesToIncident", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Alert]),
    __metadata("design:returntype", Promise)
], RunbookRuleEngineServiceClass.prototype, "applyRulesToAlert", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ScheduledMaintenance]),
    __metadata("design:returntype", Promise)
], RunbookRuleEngineServiceClass.prototype, "applyRulesToScheduledMaintenance", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], RunbookRuleEngineServiceClass.prototype, "applyRules", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], RunbookRuleEngineServiceClass.prototype, "startRunbookFor", null);
const RunbookRuleEngineService = new RunbookRuleEngineServiceClass();
export default RunbookRuleEngineService;
//# sourceMappingURL=RunbookRuleEngineService.js.map