/**
 * PagerDuty Alert Channel
 *
 * Sends security alerts to PagerDuty via Events API v2.
 * Supports incident creation, acknowledgment, and resolution.
 *
 * @packageDocumentation
 * @module security/alerting/channels/pagerduty
 */
import { createLogger } from '../../../common/logger.js';
import { AlertChannel, AlertSeverity, } from '../types.js';
import { HttpAlertChannel } from './http-base.js';
const logger = createLogger({ component: 'pagerduty-alert-channel' });
// =============================================================================
// Constants
// =============================================================================
const DEFAULT_API_URL = 'https://events.pagerduty.com/v2/enqueue';
const DEFAULT_TIMEOUT = 10000;
const DEFAULT_MAX_RETRIES = 3;
/**
 * Map our severity levels to PagerDuty severity
 */
const SEVERITY_MAPPING = {
    [AlertSeverity.CRITICAL]: 'critical',
    [AlertSeverity.HIGH]: 'error',
    [AlertSeverity.MEDIUM]: 'warning',
    [AlertSeverity.LOW]: 'info',
    [AlertSeverity.INFO]: 'info',
};
// =============================================================================
// PagerDutyAlertChannel Class
// =============================================================================
/**
 * PagerDuty Events API integration for security alerts
 */
export class PagerDutyAlertChannel extends HttpAlertChannel {
    channelType = AlertChannel.PAGERDUTY;
    channelName = 'PagerDuty';
    logger = logger;
    routingKey;
    apiUrl;
    serviceName;
    component;
    group;
    classValue;
    constructor(config) {
        super({
            timeout: config.timeout ?? DEFAULT_TIMEOUT,
            maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,
        });
        if (!config.routingKey) {
            throw new Error('PagerDuty routing key is required');
        }
        this.routingKey = config.routingKey;
        this.apiUrl = config.apiUrl ?? DEFAULT_API_URL;
        this.serviceName = config.serviceName ?? 'Security Alert System';
        this.component = config.component ?? 'security';
        this.group = config.group ?? 'security-alerts';
        this.classValue = config.class ?? 'security-incident';
        logger.info('PagerDutyAlertChannel initialized');
    }
    /**
     * Send an alert to PagerDuty (trigger an incident)
     */
    async sendInternal(alert) {
        return this.sendEvent(alert, 'trigger');
    }
    /**
     * Acknowledge an alert in PagerDuty
     */
    async acknowledge(alert) {
        const startTime = Date.now();
        let retryCount = 0;
        let lastError = null;
        while (retryCount <= this.maxRetries) {
            try {
                const result = await this.sendEvent(alert, 'acknowledge');
                this.logger.info({
                    alertId: alert.id,
                    messageId: result.messageId,
                    action: 'acknowledge',
                    retryCount,
                    durationMs: Date.now() - startTime,
                }, 'Alert acknowledged in PagerDuty');
                return this.createSuccessResult(result.messageId, retryCount);
            }
            catch (error) {
                lastError = error instanceof Error ? error : new Error(String(error));
                retryCount++;
                if (retryCount <= this.maxRetries) {
                    const delay = this.calculateBackoff(retryCount);
                    await this.sleep(delay);
                }
            }
        }
        return this.createFailureResult(lastError?.message ?? 'Unknown error', retryCount);
    }
    /**
     * Resolve an alert in PagerDuty
     */
    async resolve(alert) {
        const startTime = Date.now();
        let retryCount = 0;
        let lastError = null;
        while (retryCount <= this.maxRetries) {
            try {
                const result = await this.sendEvent(alert, 'resolve');
                this.logger.info({
                    alertId: alert.id,
                    messageId: result.messageId,
                    action: 'resolve',
                    retryCount,
                    durationMs: Date.now() - startTime,
                }, 'Alert resolved in PagerDuty');
                return this.createSuccessResult(result.messageId, retryCount);
            }
            catch (error) {
                lastError = error instanceof Error ? error : new Error(String(error));
                retryCount++;
                if (retryCount <= this.maxRetries) {
                    const delay = this.calculateBackoff(retryCount);
                    await this.sleep(delay);
                }
            }
        }
        return this.createFailureResult(lastError?.message ?? 'Unknown error', retryCount);
    }
    /**
     * Send an event to PagerDuty
     */
    async sendEvent(alert, action) {
        const payload = this.formatPayload(alert, action);
        const response = await this.httpRequestOrThrow({
            url: this.apiUrl,
            method: 'POST',
            body: payload,
        });
        return { messageId: response.data.dedup_key };
    }
    /**
     * Format alert as PagerDuty payload
     */
    formatPayload(alert, action) {
        const payload = {
            routing_key: this.routingKey,
            event_action: action,
            dedup_key: alert.fingerprint, // Use fingerprint for deduplication
        };
        // Only include full payload for trigger action
        if (action === 'trigger') {
            const customDetails = {
                alert_id: alert.id,
                alert_type: alert.type,
                source: alert.source,
                fingerprint: alert.fingerprint,
            };
            // Add context details
            if (alert.context.userId) {
                customDetails.user_id = alert.context.userId;
            }
            if (alert.context.ipAddress) {
                customDetails.ip_address = alert.context.ipAddress;
            }
            if (alert.context.tenantId) {
                customDetails.tenant_id = alert.context.tenantId;
            }
            if (alert.context.resource) {
                customDetails.resource = alert.context.resource;
            }
            if (alert.context.location) {
                customDetails.location = alert.context.location;
            }
            if (alert.context.userAgent) {
                customDetails.user_agent = alert.context.userAgent;
            }
            if (alert.context.requestId) {
                customDetails.request_id = alert.context.requestId;
            }
            if (alert.context.sessionId) {
                customDetails.session_id = alert.context.sessionId;
            }
            // Add suggested actions
            if (alert.suggestedActions && alert.suggestedActions.length > 0) {
                customDetails.suggested_actions = alert.suggestedActions;
            }
            // Add tags
            if (alert.tags && alert.tags.length > 0) {
                customDetails.tags = alert.tags;
            }
            // Add additional metadata
            if (alert.context.metadata) {
                customDetails.metadata = alert.context.metadata;
            }
            payload.payload = {
                summary: `[${alert.severity.toUpperCase()}] ${alert.title}: ${alert.message.slice(0, 200)}`,
                source: this.serviceName,
                severity: SEVERITY_MAPPING[alert.severity],
                timestamp: alert.timestamp.toISOString(),
                component: this.component,
                group: this.group,
                class: this.classValue,
                custom_details: customDetails,
            };
        }
        return payload;
    }
    /**
     * Test the PagerDuty connection
     */
    async test() {
        try {
            // Send a test event that triggers and immediately resolves
            const testAlert = {
                id: 'test-' + Date.now(),
                severity: AlertSeverity.INFO,
                type: 'custom',
                title: 'Security Alert System Test',
                message: 'This is a test message from the security alerting system.',
                context: {},
                timestamp: new Date(),
                fingerprint: `test-connection-${Date.now()}`,
                source: this.serviceName,
                acknowledged: false,
                resolved: false,
            };
            // Trigger test event
            const result = await this.send(testAlert);
            if (result.success) {
                // Immediately resolve it
                await this.resolve(testAlert);
                logger.info('PagerDuty connection test successful');
                return true;
            }
            return false;
        }
        catch (error) {
            logger.error({ error }, 'PagerDuty connection test failed');
            return false;
        }
    }
}
/**
 * Create a new PagerDuty alert channel
 */
export function createPagerDutyChannel(config) {
    return new PagerDutyAlertChannel(config);
}
//# sourceMappingURL=pagerduty.js.map