import { EventEmitter } from 'events';

export interface SuppressionRule {
  id: string;
  name: string;
  description?: string;
  enabled: boolean;
  alertIds: string[];
  suppressionType: 'time_window' | 'maintenance' | 'known_issue' | 'custom';
  startTime: Date;
  endTime: Date;
  reason: string;
  createdBy: string;
  createdAt: Date;
  updatedAt: Date;
  metadata?: Record<string, any>;
}

export interface SuppressionEvent {
  id: string;
  ruleId: string;
  alertId: string;
  suppressedAt: Date;
  wouldHaveFired: boolean;
  reason: string;
}

export interface SuppressionStats {
  totalRules: number;
  activeRules: number;
  totalSuppressed: number;
  suppressionsByType: Record<string, number>;
  suppressionsByAlert: Record<string, number>;
}

class AlertSuppressionSystem extends EventEmitter {
  private suppressionRules = new Map<string, SuppressionRule>();
  private suppressionEvents: SuppressionEvent[] = [];
  private maxEvents = 50000;

  /**
   * Create suppression rule
   */
  createSuppressionRule(rule: Omit<SuppressionRule, 'id' | 'createdAt' | 'updatedAt'>): SuppressionRule {
    const id = `supp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    const fullRule: SuppressionRule = {
      ...rule,
      id,
      createdAt: new Date(),
      updatedAt: new Date(),
    };

    this.suppressionRules.set(id, fullRule);
    this.emit('rule:created', fullRule);
    return fullRule;
  }

  /**
   * Update suppression rule
   */
  updateSuppressionRule(ruleId: string, updates: Partial<SuppressionRule>): SuppressionRule | null {
    const rule = this.suppressionRules.get(ruleId);
    if (!rule) return null;

    const updated: SuppressionRule = {
      ...rule,
      ...updates,
      updatedAt: new Date(),
    };

    this.suppressionRules.set(ruleId, updated);
    this.emit('rule:updated', updated);
    return updated;
  }

  /**
   * Delete suppression rule
   */
  deleteSuppressionRule(ruleId: string): boolean {
    const deleted = this.suppressionRules.delete(ruleId);
    if (deleted) {
      this.emit('rule:deleted', ruleId);
    }
    return deleted;
  }

  /**
   * Get suppression rule
   */
  getSuppressionRule(ruleId: string): SuppressionRule | null {
    return this.suppressionRules.get(ruleId) || null;
  }

  /**
   * List all suppression rules
   */
  listSuppressionRules(alertId?: string): SuppressionRule[] {
    const rules = Array.from(this.suppressionRules.values());
    return alertId ? rules.filter(r => r.alertIds.includes(alertId)) : rules;
  }

  /**
   * List active suppression rules
   */
  listActiveSuppressionRules(): SuppressionRule[] {
    const now = new Date();
    return Array.from(this.suppressionRules.values()).filter(
      r => r.enabled && r.startTime <= now && r.endTime >= now
    );
  }

  /**
   * Check if alert should be suppressed
   */
  shouldSuppressAlert(alertId: string): { suppressed: boolean; ruleId?: string; reason?: string } {
    const now = new Date();

    for (const rule of this.suppressionRules.values()) {
      if (!rule.enabled) continue;
      if (!rule.alertIds.includes(alertId)) continue;
      if (rule.startTime > now || rule.endTime < now) continue;

      return {
        suppressed: true,
        ruleId: rule.id,
        reason: rule.reason,
      };
    }

    return { suppressed: false };
  }

  /**
   * Record suppression event
   */
  recordSuppressionEvent(event: Omit<SuppressionEvent, 'id' | 'suppressedAt'>): SuppressionEvent {
    const fullEvent: SuppressionEvent = {
      ...event,
      id: `suppev_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      suppressedAt: new Date(),
    };

    this.suppressionEvents.push(fullEvent);

    // Trim old events if exceeding max
    if (this.suppressionEvents.length > this.maxEvents) {
      this.suppressionEvents = this.suppressionEvents.slice(-this.maxEvents);
    }

    this.emit('event:recorded', fullEvent);
    return fullEvent;
  }

  /**
   * Get suppression events for alert
   */
  getSuppressionEventsForAlert(alertId: string): SuppressionEvent[] {
    return this.suppressionEvents.filter(e => e.alertId === alertId);
  }

  /**
   * Get suppression events for rule
   */
  getSuppressionEventsForRule(ruleId: string): SuppressionEvent[] {
    return this.suppressionEvents.filter(e => e.ruleId === ruleId);
  }

  /**
   * Get suppression statistics
   */
  getSuppressionStats(): SuppressionStats {
    const rules = Array.from(this.suppressionRules.values());
    const now = new Date();
    const activeRules = rules.filter(r => r.enabled && r.startTime <= now && r.endTime >= now);

    const suppressionsByType: Record<string, number> = {};
    const suppressionsByAlert: Record<string, number> = {};

    this.suppressionEvents.forEach(e => {
      suppressionsByType[this.suppressionRules.get(e.ruleId)?.suppressionType || 'unknown'] =
        (suppressionsByType[this.suppressionRules.get(e.ruleId)?.suppressionType || 'unknown'] || 0) + 1;
      suppressionsByAlert[e.alertId] = (suppressionsByAlert[e.alertId] || 0) + 1;
    });

    return {
      totalRules: rules.length,
      activeRules: activeRules.length,
      totalSuppressed: this.suppressionEvents.length,
      suppressionsByType,
      suppressionsByAlert,
    };
  }

  /**
   * Get suppression timeline
   */
  getSuppressionTimeline(
    startDate: Date,
    endDate: Date
  ): Array<{ date: Date; suppressed: number; alerts: string[] }> {
    const timeline: Map<string, { suppressed: number; alerts: Set<string> }> = new Map();

    this.suppressionEvents
      .filter(e => e.suppressedAt >= startDate && e.suppressedAt <= endDate)
      .forEach(e => {
        const dateKey = e.suppressedAt.toISOString().split('T')[0];
        const entry = timeline.get(dateKey) || { suppressed: 0, alerts: new Set<string>() };
        entry.suppressed += 1;
        entry.alerts.add(e.alertId);
        timeline.set(dateKey, entry);
      });

    return Array.from(timeline.entries()).map(([dateStr, data]) => ({
      date: new Date(dateStr),
      suppressed: data.suppressed,
      alerts: Array.from(data.alerts),
    }));
  }

  /**
   * Create maintenance window
   */
  createMaintenanceWindow(
    name: string,
    startTime: Date,
    endTime: Date,
    alertIds: string[] = []
  ): SuppressionRule {
    return this.createSuppressionRule({
      name,
      description: `Maintenance window: ${name}`,
      enabled: true,
      alertIds: alertIds.length > 0 ? alertIds : [],
      suppressionType: 'maintenance',
      startTime,
      endTime,
      reason: `Scheduled maintenance: ${name}`,
      createdBy: 'system',
    });
  }

  /**
   * Create known issue suppression
   */
  createKnownIssueSuppression(
    name: string,
    alertIds: string[],
    durationHours: number,
    reason: string,
    createdBy: string
  ): SuppressionRule {
    const startTime = new Date();
    const endTime = new Date(startTime.getTime() + durationHours * 60 * 60 * 1000);

    return this.createSuppressionRule({
      name,
      description: `Known issue: ${reason}`,
      enabled: true,
      alertIds,
      suppressionType: 'known_issue',
      startTime,
      endTime,
      reason,
      createdBy,
    });
  }

  /**
   * Export suppression report
   */
  exportSuppressionReport(startDate: Date, endDate: Date): string {
    const events = this.suppressionEvents.filter(e => e.suppressedAt >= startDate && e.suppressedAt <= endDate);

    const headers = ['Alert ID', 'Rule ID', 'Suppressed At', 'Would Have Fired', 'Reason'];
    const rows = events.map(e => [e.alertId, e.ruleId, e.suppressedAt.toISOString(), e.wouldHaveFired, e.reason]);

    const csv = [headers, ...rows].map(row => row.map(cell => `"${cell}"`).join(',')).join('\n');
    return csv;
  }

  /**
   * Cleanup expired suppression rules
   */
  cleanupExpiredRules(): number {
    const now = new Date();
    let cleaned = 0;

    for (const [ruleId, rule] of this.suppressionRules.entries()) {
      if (rule.endTime < now) {
        this.suppressionRules.delete(ruleId);
        cleaned++;
      }
    }

    if (cleaned > 0) {
      this.emit('rules:cleaned', { cleaned, timestamp: now });
    }

    return cleaned;
  }
}

export const alertSuppressionSystem = new AlertSuppressionSystem();
