"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.auditLogger = exports.AuditLogger = void 0;
const directus_client_1 = require("../../scripts/utils/directus-client");
const events_1 = require("events");
// Import Directus SDK functions
const directusSdk = require('@directus/sdk');
const createItem = directusSdk.createItem;
const readItems = directusSdk.readItems;
const aggregate = directusSdk.aggregate;
/**
 * Audit Logger Service
 * Comprehensive audit logging for all system activities
 */
class AuditLogger extends events_1.EventEmitter {
    constructor() {
        super();
        this.buffer = [];
        this.bufferSize = 100;
        this.flushInterval = null;
        this.flushIntervalMs = 5000;
        this.enabled = true;
        this.initializeClient();
        this.startBufferFlush();
    }
    async initializeClient() {
        this.client = await (0, directus_client_1.getAuthenticatedClient)();
    }
    /**
     * Start buffer flush interval
     */
    startBufferFlush() {
        this.flushInterval = setInterval(async () => {
            if (this.buffer.length > 0) {
                await this.flush();
            }
        }, this.flushIntervalMs);
    }
    /**
     * Stop buffer flush interval
     */
    stopBufferFlush() {
        if (this.flushInterval) {
            clearInterval(this.flushInterval);
            this.flushInterval = null;
        }
    }
    /**
     * Log an audit entry
     */
    async log(entry) {
        if (!this.enabled)
            return;
        const logEntry = {
            ...entry,
            timestamp: new Date().toISOString()
        };
        // Add to buffer
        this.buffer.push(logEntry);
        // Emit event for real-time monitoring
        this.emit('log', logEntry);
        // Check if buffer should be flushed
        if (this.buffer.length >= this.bufferSize) {
            await this.flush();
        }
        // Log critical events immediately
        if (entry.severity === 'critical') {
            await this.flush();
        }
    }
    /**
     * Log task action
     */
    async logTaskAction(taskId, action, actorId, details, changes) {
        await this.log({
            entity_type: 'task',
            entity_id: taskId,
            action,
            actor_id: actorId,
            actor_type: actorId ? 'user' : 'system',
            details,
            changes,
            severity: 'info'
        });
    }
    /**
     * Log workflow transition
     */
    async logWorkflowTransition(taskId, fromStatus, toStatus, triggeredBy, metadata) {
        await this.log({
            entity_type: 'workflow',
            entity_id: taskId,
            action: 'status_transition',
            actor_type: 'system',
            details: {
                from_status: fromStatus,
                to_status: toStatus,
                triggered_by: triggeredBy,
                ...metadata
            },
            severity: 'info',
            tags: ['workflow', 'transition']
        });
    }
    /**
     * Log webhook activity
     */
    async logWebhookActivity(webhookId, action, success, details) {
        await this.log({
            entity_type: 'webhook',
            entity_id: webhookId,
            action,
            actor_type: 'system',
            details: {
                success,
                ...details
            },
            severity: success ? 'info' : 'warning',
            tags: ['webhook']
        });
    }
    /**
     * Log error
     */
    async logError(entityType, entityId, error, context) {
        await this.log({
            entity_type: entityType,
            entity_id: entityId,
            action: 'error',
            actor_type: 'system',
            details: {
                error_message: error.message,
                error_stack: error.stack,
                ...context
            },
            severity: 'error',
            tags: ['error']
        });
    }
    /**
     * Log security event
     */
    async logSecurityEvent(action, actorId, success, details) {
        await this.log({
            entity_type: 'system',
            entity_id: 'security',
            action,
            actor_id: actorId,
            actor_type: 'user',
            details: {
                success,
                ...details
            },
            severity: success ? 'info' : 'warning',
            tags: ['security']
        });
    }
    /**
     * Flush buffer to database
     */
    async flush() {
        if (this.buffer.length === 0)
            return;
        if (!this.client)
            await this.initializeClient();
        const entries = [...this.buffer];
        this.buffer = [];
        try {
            // Batch insert audit logs
            await this.client.request(createItem('audit_logs', entries));
            console.log(`Flushed ${entries.length} audit log entries`);
        }
        catch (error) {
            console.error('Failed to flush audit logs:', error);
            // Re-add entries to buffer for retry
            this.buffer.unshift(...entries);
            // Emit error event
            this.emit('flushError', error);
        }
    }
    /**
     * Query audit logs
     */
    async query(options = {}) {
        if (!this.client)
            await this.initializeClient();
        // Build filter
        const filter = {};
        if (options.entityType) {
            filter.entity_type = { _eq: options.entityType };
        }
        if (options.entityId) {
            filter.entity_id = { _eq: options.entityId };
        }
        if (options.actorId) {
            filter.actor_id = { _eq: options.actorId };
        }
        if (options.action) {
            filter.action = { _eq: options.action };
        }
        if (options.severity) {
            filter.severity = { _eq: options.severity };
        }
        if (options.startDate) {
            filter.timestamp = {
                ...filter.timestamp,
                _gte: options.startDate.toISOString()
            };
        }
        if (options.endDate) {
            filter.timestamp = {
                ...filter.timestamp,
                _lte: options.endDate.toISOString()
            };
        }
        if (options.tags && options.tags.length > 0) {
            filter.tags = { _contains: options.tags };
        }
        try {
            const logs = await this.client.request(readItems('audit_logs', {
                filter,
                limit: options.limit || 100,
                offset: options.offset || 0,
                sort: options.sort || ['-timestamp']
            }));
            return logs;
        }
        catch (error) {
            throw new Error(`Failed to query audit logs: ${error.message}`);
        }
    }
    /**
     * Get audit statistics
     */
    async getStatistics(startDate, endDate) {
        if (!this.client)
            await this.initializeClient();
        const filter = {};
        if (startDate) {
            filter.timestamp = {
                ...filter.timestamp,
                _gte: startDate.toISOString()
            };
        }
        if (endDate) {
            filter.timestamp = {
                ...filter.timestamp,
                _lte: endDate.toISOString()
            };
        }
        try {
            // Get aggregated statistics
            const stats = await this.client.request(aggregate('audit_logs', {
                aggregate: {
                    count: '*',
                    countDistinct: ['entity_type', 'action', 'severity', 'actor_id']
                },
                groupBy: ['entity_type', 'action', 'severity'],
                filter
            }));
            // Get time range
            const timeRange = await this.client.request(aggregate('audit_logs', {
                aggregate: {
                    min: ['timestamp'],
                    max: ['timestamp']
                },
                filter
            }));
            // Process and format statistics
            const statistics = {
                totalLogs: stats[0]?.count || 0,
                byEntityType: {},
                byAction: {},
                bySeverity: {},
                byActor: {},
                timeRange: {
                    start: timeRange[0]?.timestamp_min || '',
                    end: timeRange[0]?.timestamp_max || ''
                }
            };
            // Group statistics
            stats.forEach((stat) => {
                if (stat.entity_type) {
                    statistics.byEntityType[stat.entity_type] =
                        (statistics.byEntityType[stat.entity_type] || 0) + stat.count;
                }
                if (stat.action) {
                    statistics.byAction[stat.action] =
                        (statistics.byAction[stat.action] || 0) + stat.count;
                }
                if (stat.severity) {
                    statistics.bySeverity[stat.severity] =
                        (statistics.bySeverity[stat.severity] || 0) + stat.count;
                }
            });
            return statistics;
        }
        catch (error) {
            throw new Error(`Failed to get audit statistics: ${error.message}`);
        }
    }
    /**
     * Get audit timeline
     */
    async getTimeline(entityId, entityType) {
        const options = {
            entityId,
            entityType,
            sort: 'timestamp'
        };
        return await this.query(options);
    }
    /**
     * Archive old audit logs
     */
    async archiveOldLogs(daysToKeep = 90) {
        if (!this.client)
            await this.initializeClient();
        const cutoffDate = new Date();
        cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);
        try {
            // Get logs to archive
            const oldLogs = await this.client.request(readItems('audit_logs', {
                filter: {
                    timestamp: { _lt: cutoffDate.toISOString() }
                }
            }));
            if (oldLogs.length === 0) {
                console.log('No audit logs to archive');
                return 0;
            }
            // Archive to separate collection or external storage
            await this.client.request(createItem('audit_logs_archive', oldLogs));
            // Delete archived logs
            const logIds = oldLogs.map((log) => log.id);
            for (const id of logIds) {
                await this.client.request(deleteItem('audit_logs', id));
            }
            console.log(`Archived ${oldLogs.length} audit logs`);
            return oldLogs.length;
        }
        catch (error) {
            throw new Error(`Failed to archive audit logs: ${error.message}`);
        }
    }
    /**
     * Export audit logs
     */
    async exportLogs(options, format = 'json') {
        const logs = await this.query(options);
        if (format === 'json') {
            return JSON.stringify(logs, null, 2);
        }
        // CSV format
        if (logs.length === 0)
            return '';
        const headers = Object.keys(logs[0]).join(',');
        const rows = logs.map(log => {
            return Object.values(log).map(value => {
                if (typeof value === 'object') {
                    return JSON.stringify(value);
                }
                return value;
            }).join(',');
        });
        return [headers, ...rows].join('\n');
    }
    /**
     * Enable or disable audit logging
     */
    setEnabled(enabled) {
        this.enabled = enabled;
        console.log(`Audit logging ${enabled ? 'enabled' : 'disabled'}`);
    }
    /**
     * Clean up service
     */
    async cleanup() {
        // Flush remaining logs
        await this.flush();
        // Stop flush interval
        this.stopBufferFlush();
        // Clear buffer
        this.buffer = [];
        // Remove all listeners
        this.removeAllListeners();
    }
}
exports.AuditLogger = AuditLogger;
// Export singleton instance
exports.auditLogger = new AuditLogger();
//# sourceMappingURL=auditLogger.js.map