/**
 * Real-Time Monitoring Service
 * Provides WebSocket-based real-time updates for admin dashboard
 */

import { EventEmitter } from 'events';

export type MonitoringEventType =
  | 'withdrawal_request'
  | 'withdrawal_approved'
  | 'withdrawal_rejected'
  | 'withdrawal_completed'
  | 'fraud_alert'
  | 'high_value_transaction'
  | 'payment_received'
  | 'refund_processed'
  | 'system_alert';

export interface MonitoringEvent {
  id: string;
  type: MonitoringEventType;
  timestamp: Date;
  severity: 'low' | 'medium' | 'high' | 'critical';
  title: string;
  message: string;
  data: Record<string, any>;
  acknowledged: boolean;
  acknowledgedBy?: number;
  acknowledgedAt?: Date;
}

export interface RealtimeMetrics {
  totalRevenue: number;
  totalTransactions: number;
  averageTransactionValue: number;
  pendingWithdrawals: number;
  pendingWithdrawalAmount: number;
  flaggedTransactions: number;
  activeUsers: number;
  lastUpdated: Date;
}

export interface AdminSession {
  sessionId: string;
  adminId: number;
  adminEmail: string;
  connectedAt: Date;
  lastActivity: Date;
  isActive: boolean;
}

/**
 * Real-Time Monitoring Service
 */
export class RealtimeMonitoringService extends EventEmitter {
  private events: Map<string, MonitoringEvent> = new Map();
  private metrics: RealtimeMetrics = {
    totalRevenue: 0,
    totalTransactions: 0,
    averageTransactionValue: 0,
    pendingWithdrawals: 0,
    pendingWithdrawalAmount: 0,
    flaggedTransactions: 0,
    activeUsers: 0,
    lastUpdated: new Date(),
  };
  private adminSessions: Map<string, AdminSession> = new Map();
  private eventHistory: MonitoringEvent[] = [];
  private maxHistorySize: number = 1000;

  constructor() {
    super();
    this.startMetricsUpdate();
  }

  /**
   * Record a monitoring event
   */
  recordEvent(
    type: MonitoringEventType,
    title: string,
    message: string,
    data: Record<string, any>,
    severity: 'low' | 'medium' | 'high' | 'critical' = 'medium'
  ): MonitoringEvent {
    const event: MonitoringEvent = {
      id: `event_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      type,
      timestamp: new Date(),
      severity,
      title,
      message,
      data,
      acknowledged: false,
    };

    // Store event
    this.events.set(event.id, event);
    this.eventHistory.push(event);

    // Maintain history size
    if (this.eventHistory.length > this.maxHistorySize) {
      this.eventHistory.shift();
    }

    // Emit event for WebSocket broadcast
    this.emit('event', event);

    // Log critical events
    if (severity === 'critical') {
      console.error(`[CRITICAL] ${title}: ${message}`, data);
    }

    return event;
  }

  /**
   * Acknowledge an event
   */
  acknowledgeEvent(eventId: string, adminId: number): boolean {
    const event = this.events.get(eventId);
    if (!event) return false;

    event.acknowledged = true;
    event.acknowledgedBy = adminId;
    event.acknowledgedAt = new Date();

    this.emit('event_acknowledged', { eventId, adminId });
    return true;
  }

  /**
   * Get unacknowledged events
   */
  getUnacknowledgedEvents(): MonitoringEvent[] {
    return Array.from(this.events.values()).filter((e) => !e.acknowledged);
  }

  /**
   * Get events by type
   */
  getEventsByType(type: MonitoringEventType): MonitoringEvent[] {
    return Array.from(this.events.values()).filter((e) => e.type === type);
  }

  /**
   * Get events by severity
   */
  getEventsBySeverity(severity: 'low' | 'medium' | 'high' | 'critical'): MonitoringEvent[] {
    return Array.from(this.events.values()).filter((e) => e.severity === severity);
  }

  /**
   * Get recent events
   */
  getRecentEvents(limit: number = 50): MonitoringEvent[] {
    return this.eventHistory.slice(-limit).reverse();
  }

  /**
   * Update metrics
   */
  updateMetrics(updates: Partial<RealtimeMetrics>): void {
    this.metrics = {
      ...this.metrics,
      ...updates,
      lastUpdated: new Date(),
    };

    this.emit('metrics_updated', this.metrics);
  }

  /**
   * Get current metrics
   */
  getMetrics(): RealtimeMetrics {
    return { ...this.metrics };
  }

  /**
   * Register admin session
   */
  registerAdminSession(adminId: number, adminEmail: string): AdminSession {
    const sessionId = `session_${adminId}_${Date.now()}`;
    const session: AdminSession = {
      sessionId,
      adminId,
      adminEmail,
      connectedAt: new Date(),
      lastActivity: new Date(),
      isActive: true,
    };

    this.adminSessions.set(sessionId, session);
    this.emit('admin_connected', session);

    return session;
  }

  /**
   * Update admin session activity
   */
  updateAdminActivity(sessionId: string): boolean {
    const session = this.adminSessions.get(sessionId);
    if (!session) return false;

    session.lastActivity = new Date();
    return true;
  }

  /**
   * Unregister admin session
   */
  unregisterAdminSession(sessionId: string): boolean {
    const session = this.adminSessions.get(sessionId);
    if (!session) return false;

    session.isActive = false;
    this.adminSessions.delete(sessionId);
    this.emit('admin_disconnected', session);

    return true;
  }

  /**
   * Get active admin sessions
   */
  getActiveAdminSessions(): AdminSession[] {
    return Array.from(this.adminSessions.values()).filter((s) => s.isActive);
  }

  /**
   * Broadcast event to all connected admins
   */
  broadcastEvent(event: MonitoringEvent): void {
    this.emit('broadcast_event', event);
  }

  /**
   * Broadcast metrics to all connected admins
   */
  broadcastMetrics(): void {
    this.emit('broadcast_metrics', this.metrics);
  }

  /**
   * Start periodic metrics update
   */
  private startMetricsUpdate(): void {
    setInterval(() => {
      this.broadcastMetrics();
    }, 5000); // Update every 5 seconds
  }

  /**
   * Clear old events
   */
  clearOldEvents(olderThanHours: number = 24): number {
    const cutoffTime = new Date(Date.now() - olderThanHours * 60 * 60 * 1000);
    let count = 0;

    for (const [id, event] of this.events.entries()) {
      if (event.timestamp < cutoffTime && event.acknowledged) {
        this.events.delete(id);
        count++;
      }
    }

    return count;
  }

  /**
   * Get statistics
   */
  getStatistics(): {
    totalEvents: number;
    unacknowledgedEvents: number;
    criticalEvents: number;
    highSeverityEvents: number;
    activeAdmins: number;
    eventsByType: Record<MonitoringEventType, number>;
    eventsBySeverity: Record<string, number>;
  } {
    const allEvents = Array.from(this.events.values());
    const unacknowledged = allEvents.filter((e) => !e.acknowledged);
    const critical = allEvents.filter((e) => e.severity === 'critical');
    const high = allEvents.filter((e) => e.severity === 'high');

    const eventsByType: Record<MonitoringEventType, number> = {
      withdrawal_request: 0,
      withdrawal_approved: 0,
      withdrawal_rejected: 0,
      withdrawal_completed: 0,
      fraud_alert: 0,
      high_value_transaction: 0,
      payment_received: 0,
      refund_processed: 0,
      system_alert: 0,
    };

    const eventsBySeverity: Record<string, number> = {
      low: 0,
      medium: 0,
      high: 0,
      critical: 0,
    };

    allEvents.forEach((e) => {
      eventsByType[e.type]++;
      eventsBySeverity[e.severity]++;
    });

    return {
      totalEvents: allEvents.length,
      unacknowledgedEvents: unacknowledged.length,
      criticalEvents: critical.length,
      highSeverityEvents: high.length,
      activeAdmins: this.getActiveAdminSessions().length,
      eventsByType,
      eventsBySeverity,
    };
  }
}

/**
 * Global monitoring service instance
 */
let monitoringService: RealtimeMonitoringService | null = null;

/**
 * Get or create monitoring service
 */
export function getMonitoringService(): RealtimeMonitoringService {
  if (!monitoringService) {
    monitoringService = new RealtimeMonitoringService();
  }
  return monitoringService;
}

/**
 * Record withdrawal event
 */
export function recordWithdrawalEvent(
  type: 'withdrawal_request' | 'withdrawal_approved' | 'withdrawal_rejected' | 'withdrawal_completed',
  playerId: number,
  playerName: string,
  amount: number,
  currency: string,
  withdrawalId: string
): MonitoringEvent {
  const service = getMonitoringService();
  const titles: Record<string, string> = {
    withdrawal_request: 'New Withdrawal Request',
    withdrawal_approved: 'Withdrawal Approved',
    withdrawal_rejected: 'Withdrawal Rejected',
    withdrawal_completed: 'Withdrawal Completed',
  };

  const severities: Record<string, 'low' | 'medium' | 'high' | 'critical'> = {
    withdrawal_request: 'medium',
    withdrawal_approved: 'low',
    withdrawal_rejected: 'low',
    withdrawal_completed: 'low',
  };

  return service.recordEvent(
    type,
    titles[type],
    `${playerName} requested withdrawal of ${amount} ${currency}`,
    {
      playerId,
      playerName,
      amount,
      currency,
      withdrawalId,
    },
    severities[type]
  );
}

/**
 * Record fraud alert event
 */
export function recordFraudAlertEvent(
  playerId: number,
  playerName: string,
  transactionId: string,
  amount: number,
  riskLevel: string,
  indicators: string[]
): MonitoringEvent {
  const service = getMonitoringService();
  const severityMap: Record<string, 'low' | 'medium' | 'high' | 'critical'> = {
    low: 'low',
    medium: 'medium',
    high: 'high',
    critical: 'critical',
  };

  return service.recordEvent(
    'fraud_alert',
    `Fraud Alert - ${riskLevel.toUpperCase()}`,
    `High-risk transaction detected for ${playerName}`,
    {
      playerId,
      playerName,
      transactionId,
      amount,
      riskLevel,
      indicators,
    },
    severityMap[riskLevel] || 'high'
  );
}

/**
 * Record payment event
 */
export function recordPaymentEvent(
  playerId: number,
  playerName: string,
  amount: number,
  gcAmount: number,
  scBonus: number,
  transactionId: string
): MonitoringEvent {
  const service = getMonitoringService();
  return service.recordEvent(
    'payment_received',
    'Payment Received',
    `${playerName} purchased ${gcAmount} Gold Coins`,
    {
      playerId,
      playerName,
      amount,
      gcAmount,
      scBonus,
      transactionId,
    },
    'low'
  );
}

/**
 * Record high-value transaction event
 */
export function recordHighValueTransactionEvent(
  playerId: number,
  playerName: string,
  amount: number,
  transactionId: string,
  threshold: number
): MonitoringEvent {
  const service = getMonitoringService();
  return service.recordEvent(
    'high_value_transaction',
    'High-Value Transaction',
    `${playerName} made a high-value purchase of $${amount}`,
    {
      playerId,
      playerName,
      amount,
      transactionId,
      threshold,
    },
    'medium'
  );
}
