import { Server as HTTPServer } from 'http';
import { Server as SocketIOServer, Socket } from 'socket.io';

export interface AuditLogEntry {
  id: string;
  timestamp: number;
  adminId: number;
  adminName: string;
  action: string;
  resourceType: string;
  resourceId: string;
  resourceName: string;
  status: 'success' | 'failure';
  ipAddress: string;
}

class AuditLogStreamingManager {
  private io: SocketIOServer;
  private subscribers: Set<string> = new Set();
  private auditLogHistory: AuditLogEntry[] = [];
  private maxHistorySize = 100;

  constructor(httpServer: HTTPServer) {
    this.io = new SocketIOServer(httpServer, {
      cors: {
        origin: process.env.FRONTEND_URL || '*',
        credentials: true,
      },
      transports: ['websocket', 'polling'],
    });

    this.setupEventHandlers();
  }

  private setupEventHandlers() {
    this.io.on('connection', (socket: Socket) => {
      console.log(`[AuditLogStreaming] Client connected: ${socket.id}`);

      socket.on('subscribe', (data: { channel: string }) => {
        if (data.channel === 'audit-log') {
          this.subscribers.add(socket.id);
          console.log(`[AuditLogStreaming] Client ${socket.id} subscribed`);

          // Send current audit log history
          socket.emit('entries-batch', {
            data: this.auditLogHistory,
            total: this.auditLogHistory.length,
          });
        }
      });

      socket.on('filter', (data: { filters: Record<string, any> }) => {
        // Filter audit logs based on criteria
        const filtered = this.filterAuditLogs(data.filters);
        socket.emit('entries-batch', {
          data: filtered,
          total: filtered.length,
        });
      });

      socket.on('disconnect', () => {
        this.subscribers.delete(socket.id);
        console.log(`[AuditLogStreaming] Client ${socket.id} disconnected`);
      });
    });
  }

  private filterAuditLogs(filters: Record<string, any>): AuditLogEntry[] {
    return this.auditLogHistory.filter((log) => {
      if (filters.action && log.action !== filters.action) return false;
      if (filters.resourceType && log.resourceType !== filters.resourceType) return false;
      if (filters.status && log.status !== filters.status) return false;
      if (filters.adminId && log.adminId !== filters.adminId) return false;
      return true;
    });
  }

  public addAuditLogEntry(entry: AuditLogEntry) {
    this.auditLogHistory.unshift(entry);

    if (this.auditLogHistory.length > this.maxHistorySize) {
      this.auditLogHistory.pop();
    }

    // Broadcast to all subscribers
    this.io.emit('new-entry', { data: entry });
  }

  public getAuditLogHistory(): AuditLogEntry[] {
    return this.auditLogHistory;
  }

  public getConnectedCount(): number {
    return this.subscribers.size;
  }
}

let auditLogStreamingManager: AuditLogStreamingManager;

export function initializeAuditLogStreaming(httpServer: HTTPServer): AuditLogStreamingManager {
  if (!auditLogStreamingManager) {
    auditLogStreamingManager = new AuditLogStreamingManager(httpServer);
  }
  return auditLogStreamingManager;
}

export function getAuditLogStreamingManager(): AuditLogStreamingManager {
  if (!auditLogStreamingManager) {
    throw new Error('AuditLogStreamingManager not initialized');
  }
  return auditLogStreamingManager;
}
