/**
 * Event Emitter for Memory Events
 *
 * Broadcasts memory changes to connected WebSocket clients
 * for real-time visualization updates.
 */
import { EventEmitter } from 'events';
import { getDatabase } from '../database/init.js';
// Global event emitter for memory events
class MemoryEventEmitter extends EventEmitter {
    emit(event, data) {
        const payload = {
            type: event,
            timestamp: new Date().toISOString(),
            data,
        };
        return super.emit('memory_event', payload);
    }
    onMemoryEvent(callback) {
        this.on('memory_event', callback);
    }
    offMemoryEvent(callback) {
        this.off('memory_event', callback);
    }
}
// Singleton instance
export const memoryEvents = new MemoryEventEmitter();
// Helper functions to emit events
export function emitMemoryCreated(memory, entityIds = []) {
    memoryEvents.emit('memory_created', { memory, entity_ids: entityIds });
}
export function emitMemoryAccessed(memory, newSalience, entityIds = []) {
    memoryEvents.emit('memory_accessed', {
        memoryId: memory.id,
        memory,
        newSalience,
        entity_ids: entityIds,
    });
}
export function emitMemoryUpdated(memory) {
    memoryEvents.emit('memory_updated', { memory });
}
export function emitMemoryDeleted(memoryId, title) {
    memoryEvents.emit('memory_deleted', { memoryId, title });
}
export function emitConsolidation(result, promotedMemories = [], deletedMemories = []) {
    memoryEvents.emit('consolidation_complete', {
        ...result,
        promotedMemories,
        deletedMemories,
    });
}
export function emitDecayTick(updates) {
    memoryEvents.emit('decay_tick', { updates });
}
// Phase 4: Worker event emitters
export function emitWorkerLightTick(data) {
    memoryEvents.emit('worker_light_tick', {
        ...data,
        timestamp: data.timestamp.toISOString(),
    });
}
export function emitWorkerMediumTick(data) {
    memoryEvents.emit('worker_medium_tick', {
        ...data,
        timestamp: data.timestamp.toISOString(),
    });
}
export function emitLinkDiscovered(data) {
    memoryEvents.emit('link_discovered', data);
}
export function emitDefenceEvent(data) {
    memoryEvents.emit('defence_event', data);
}
export function emitPredictiveConsolidation(data) {
    memoryEvents.emit('predictive_consolidation', data);
}
// Kill switch event emitters
export function emitKillSwitchActivated(data) {
    memoryEvents.emit('kill_switch_activated', data);
    persistEvent('kill_switch_activated', data);
}
export function emitKillSwitchDeactivated(data) {
    memoryEvents.emit('kill_switch_deactivated', data);
    persistEvent('kill_switch_deactivated', data);
}
// ============================================================================
// Cross-Process IPC via Database
// ============================================================================
/**
 * Persist event to database for cross-process IPC.
 * Called by MCP server when tools are invoked.
 * The API server polls for these events and broadcasts to WebSocket clients.
 */
export function persistEvent(type, data) {
    try {
        const db = getDatabase();
        const stmt = db.prepare(`
      INSERT INTO events (type, data, timestamp)
      VALUES (?, ?, ?)
    `);
        stmt.run(type, data ? JSON.stringify(data) : null, new Date().toISOString());
    }
    catch (error) {
        // Log but don't throw - event persistence is best-effort
        console.error('[Events] Failed to persist event:', error);
    }
}
/**
 * Get unprocessed events from database.
 * Called by API server to poll for new events from MCP process.
 */
export function getUnprocessedEvents(limit = 100) {
    try {
        const db = getDatabase();
        const stmt = db.prepare(`
      SELECT id, type, data, timestamp
      FROM events
      WHERE processed = 0
      ORDER BY id ASC
      LIMIT ?
    `);
        const rows = stmt.all(limit);
        return rows.map(row => ({
            id: row.id,
            type: row.type,
            data: row.data ? JSON.parse(row.data) : null,
            timestamp: row.timestamp,
        }));
    }
    catch (error) {
        console.error('[Events] Failed to get events:', error);
        return [];
    }
}
/**
 * Mark events as processed after broadcasting.
 */
export function markEventsProcessed(ids) {
    if (ids.length === 0)
        return;
    try {
        const db = getDatabase();
        const placeholders = ids.map(() => '?').join(',');
        db.prepare(`UPDATE events SET processed = 1 WHERE id IN (${placeholders})`).run(...ids);
    }
    catch (error) {
        console.error('[Events] Failed to mark events processed:', error);
    }
}
/**
 * Cleanup old processed events (keep last 24 hours).
 * Called periodically by API server.
 */
export function cleanupOldEvents() {
    try {
        const db = getDatabase();
        const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
        const result = db.prepare(`DELETE FROM events WHERE processed = 1 AND timestamp < ?`).run(cutoff);
        if (result.changes > 0) {
            console.log(`[Events] Cleaned up ${result.changes} old events`);
        }
    }
    catch (error) {
        console.error('[Events] Failed to cleanup events:', error);
    }
}
