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 { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
import ScheduledMaintenanceService from "../../Services/ScheduledMaintenanceService";
import CaptureSpan from "../Telemetry/CaptureSpan";
import SeriesResourceLabels from "./SeriesResourceLabels";
/*
 * Per-series counterpart to the whole-monitor
 * `disableActiveMonitoringBecauseOfScheduledMaintenanceEvent` flag.
 *
 * A grouped metric monitor (group-by `host.name`, say) evaluates its
 * criteria once per series and creates one incident/alert per breaching
 * series. The whole-monitor flag is all-or-nothing: it only fires when
 * the *monitor itself* is attached to a maintenance event, and it would
 * silence every series. That leaves a gap — attaching only some of the
 * underlying resources (10 of 100 hosts) to a maintenance window did
 * nothing, because nothing maps an attached host back to the series it
 * owns.
 *
 * This util closes that gap: it returns the fingerprints of the series
 * whose resource is under an ongoing maintenance window, so the
 * incident/alert creation loops can skip exactly those series while the
 * other 90 hosts keep alerting. It covers every resource type a
 * maintenance event can attach to AND a series can identify: Host,
 * DockerHost, KubernetesCluster, and Service.
 */
export default class MonitorMaintenanceSuppression {
    /*
     * Resolve the per-series suppression set for one project. Returns an
     * empty set on the common paths — no per-series matches, or no
     * ongoing maintenance touching any resource — so callers pay at most
     * one query and nothing when there is no maintenance.
     */
    static async getSuppressedSeriesFingerprints(input) {
        if (!input.matchesPerSeries || input.matchesPerSeries.length === 0) {
            return new Set();
        }
        const maintained = await this.getResourcesUnderOngoingMaintenance(input.projectId);
        if (!this.hasAnyMaintainedResource(maintained)) {
            return new Set();
        }
        return this.getSuppressedFingerprintsForMaintainedResources({
            matchesPerSeries: input.matchesPerSeries,
            maintained,
        });
    }
    /*
     * Pure matching step, split out from the query so it can be unit
     * tested without a database. For each series, pull the resource
     * identifiers out of its labels and suppress the series if any of
     * them is under maintenance.
     */
    static getSuppressedFingerprintsForMaintainedResources(input) {
        const suppressed = new Set();
        for (const series of input.matchesPerSeries) {
            if (!series.fingerprint || !series.labels) {
                continue;
            }
            const refs = SeriesResourceLabels.extractResourceRefs(series.labels);
            const isUnderMaintenance = this.intersects(refs.hostIds, input.maintained.hosts.ids) ||
                this.intersects(refs.hostNames, input.maintained.hosts.names) ||
                this.intersects(refs.dockerHostIds, input.maintained.dockerHosts.ids) ||
                this.intersects(refs.dockerHostNames, input.maintained.dockerHosts.names) ||
                this.intersects(refs.kubernetesClusterIds, input.maintained.kubernetesClusters.ids) ||
                this.intersects(refs.kubernetesClusterNames, input.maintained.kubernetesClusters.names) ||
                this.intersects(refs.serviceIds, input.maintained.services.ids) ||
                this.intersects(refs.serviceNames, input.maintained.services.names);
            if (isUnderMaintenance) {
                suppressed.add(series.fingerprint);
            }
        }
        return suppressed;
    }
    static intersects(values, set) {
        for (const value of values) {
            if (set.has(value)) {
                return true;
            }
        }
        return false;
    }
    static hasAnyMaintainedResource(maintained) {
        return (maintained.hosts.ids.size > 0 ||
            maintained.hosts.names.size > 0 ||
            maintained.dockerHosts.ids.size > 0 ||
            maintained.dockerHosts.names.size > 0 ||
            maintained.kubernetesClusters.ids.size > 0 ||
            maintained.kubernetesClusters.names.size > 0 ||
            maintained.services.ids.size > 0 ||
            maintained.services.names.size > 0);
    }
    /*
     * Collect the ids + identifiers of every Host / DockerHost /
     * KubernetesCluster / Service attached to an ongoing maintenance event
     * in this project. Monitors attached to the event are intentionally
     * not collected here — those are already handled upstream by the
     * whole-monitor disable flag, which short-circuits evaluation before
     * we ever reach per-series creation.
     */
    static async getResourcesUnderOngoingMaintenance(projectId) {
        const maintained = {
            hosts: { ids: new Set(), names: new Set() },
            dockerHosts: { ids: new Set(), names: new Set() },
            kubernetesClusters: { ids: new Set(), names: new Set() },
            services: { ids: new Set(), names: new Set() },
        };
        const ongoingEvents = await ScheduledMaintenanceService.findBy({
            query: {
                projectId: projectId,
                currentScheduledMaintenanceState: {
                    isOngoingState: true,
                },
            },
            select: {
                _id: true,
                hosts: { _id: true, hostIdentifier: true },
                dockerHosts: { _id: true, hostIdentifier: true },
                kubernetesClusters: { _id: true, clusterIdentifier: true },
                services: { _id: true, name: true },
            },
            skip: 0,
            limit: LIMIT_PER_PROJECT,
            props: {
                isRoot: true,
            },
        });
        for (const event of ongoingEvents) {
            for (const host of event.hosts || []) {
                this.addKey(maintained.hosts, host._id, host.hostIdentifier);
            }
            for (const dockerHost of event.dockerHosts || []) {
                this.addKey(maintained.dockerHosts, dockerHost._id, dockerHost.hostIdentifier);
            }
            for (const cluster of event.kubernetesClusters || []) {
                this.addKey(maintained.kubernetesClusters, cluster._id, cluster.clusterIdentifier);
            }
            for (const service of event.services || []) {
                this.addKey(maintained.services, service._id, service.name);
            }
        }
        return maintained;
    }
    static addKey(keySet, id, name) {
        if (id) {
            keySet.ids.add(String(id));
        }
        if (name) {
            keySet.names.add(name);
        }
    }
}
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], MonitorMaintenanceSuppression, "getSuppressedSeriesFingerprints", null);
//# sourceMappingURL=MonitorMaintenanceSuppression.js.map