export interface SecurityEvent {
  id: string;
  type: 'xss_attempt' | 'csrf_violation' | 'injection_attempt' | 'rate_limit_exceeded' | 'auth_failure' | 'suspicious_activity';
  severity: 'low' | 'medium' | 'high' | 'critical';
  timestamp: Date;
  source: {
    ip?: string;
    userAgent?: string;
    userId?: string;
    sessionId?: string;
  };
  details: Record<string, any>;
  blocked: boolean;
}

export interface SecurityMetrics {
  totalEvents: number;
  blockedEvents: number;
  eventsByType: Record<string, number>;
  eventsBySeverity: Record<string, number>;
  topSources: Array<{ ip: string; count: number }>;
  timeRange: {
    start: Date;
    end: Date;
  };
}

export interface RuntimeMonitorOptions {
  enableLogging?: boolean;
  logLevel?: 'debug' | 'info' | 'warn' | 'error';
  maxEvents?: number;
  alertThresholds?: {
    critical: number;
    high: number;
    medium: number;
  };
  onAlert?: (event: SecurityEvent) => void;
  onMetricsUpdate?: (metrics: SecurityMetrics) => void;
}

export class RuntimeSecurityMonitor {
  private events: SecurityEvent[] = [];
  private options: RuntimeMonitorOptions;
  private alertCounts: Record<string, number> = {};
  private startTime: Date;

  constructor(options: RuntimeMonitorOptions = {}) {
    this.options = {
      enableLogging: true,
      logLevel: 'warn',
      maxEvents: 10000,
      alertThresholds: {
        critical: 1,
        high: 5,
        medium: 10,
      },
      ...options,
    };
    this.startTime = new Date();
  }

  recordEvent(event: Omit<SecurityEvent, 'id' | 'timestamp'>): void {
    const securityEvent: SecurityEvent = {
      id: this.generateEventId(),
      timestamp: new Date(),
      ...event,
    };

    this.events.push(securityEvent);

    // Maintain max events limit
    if (this.events.length > this.options.maxEvents!) {
      this.events.shift();
    }

    // Log event if enabled
    if (this.options.enableLogging) {
      this.logEvent(securityEvent);
    }

    // Check alert thresholds
    this.checkAlertThresholds(securityEvent);

    // Update metrics
    if (this.options.onMetricsUpdate) {
      this.options.onMetricsUpdate(this.getMetrics());
    }
  }

  recordXSSAttempt(details: {
    payload: string;
    source: SecurityEvent['source'];
    blocked: boolean;
    context?: string;
  }): void {
    this.recordEvent({
      type: 'xss_attempt',
      severity: 'high',
      source: details.source,
      details: {
        payload: details.payload,
        context: details.context,
      },
      blocked: details.blocked,
    });
  }

  recordCSRFViolation(details: {
    expectedToken?: string;
    receivedToken?: string;
    source: SecurityEvent['source'];
    endpoint: string;
  }): void {
    this.recordEvent({
      type: 'csrf_violation',
      severity: 'high',
      source: details.source,
      details: {
        endpoint: details.endpoint,
        hasExpectedToken: !!details.expectedToken,
        hasReceivedToken: !!details.receivedToken,
      },
      blocked: true,
    });
  }

  recordInjectionAttempt(details: {
    type: 'sql' | 'nosql' | 'ldap' | 'command';
    payload: string;
    source: SecurityEvent['source'];
    blocked: boolean;
    query?: string;
  }): void {
    this.recordEvent({
      type: 'injection_attempt',
      severity: 'critical',
      source: details.source,
      details: {
        injectionType: details.type,
        payload: details.payload,
        query: details.query,
      },
      blocked: details.blocked,
    });
  }

  recordRateLimitExceeded(details: {
    limit: number;
    current: number;
    window: string;
    source: SecurityEvent['source'];
    endpoint?: string;
  }): void {
    this.recordEvent({
      type: 'rate_limit_exceeded',
      severity: 'medium',
      source: details.source,
      details: {
        limit: details.limit,
        current: details.current,
        window: details.window,
        endpoint: details.endpoint,
      },
      blocked: true,
    });
  }

  recordAuthFailure(details: {
    reason: 'invalid_credentials' | 'account_locked' | 'token_expired' | 'insufficient_permissions';
    source: SecurityEvent['source'];
    username?: string;
    endpoint?: string;
  }): void {
    this.recordEvent({
      type: 'auth_failure',
      severity: details.reason === 'insufficient_permissions' ? 'medium' : 'high',
      source: details.source,
      details: {
        reason: details.reason,
        username: details.username,
        endpoint: details.endpoint,
      },
      blocked: true,
    });
  }

  recordSuspiciousActivity(details: {
    activity: string;
    riskScore: number;
    source: SecurityEvent['source'];
    context?: Record<string, any>;
  }): void {
    const severity = details.riskScore >= 80 ? 'critical' :
                    details.riskScore >= 60 ? 'high' :
                    details.riskScore >= 40 ? 'medium' : 'low';

    this.recordEvent({
      type: 'suspicious_activity',
      severity,
      source: details.source,
      details: {
        activity: details.activity,
        riskScore: details.riskScore,
        context: details.context,
      },
      blocked: details.riskScore >= 80,
    });
  }

  getMetrics(): SecurityMetrics {
    const now = new Date();
    const eventsByType: Record<string, number> = {};
    const eventsBySeverity: Record<string, number> = {};
    const sourceIpCounts: Record<string, number> = {};

    let totalEvents = 0;
    let blockedEvents = 0;

    this.events.forEach(event => {
      totalEvents++;
      if (event.blocked) blockedEvents++;

      eventsByType[event.type] = (eventsByType[event.type] || 0) + 1;
      eventsBySeverity[event.severity] = (eventsBySeverity[event.severity] || 0) + 1;

      if (event.source.ip) {
        sourceIpCounts[event.source.ip] = (sourceIpCounts[event.source.ip] || 0) + 1;
      }
    });

    const topSources = Object.entries(sourceIpCounts)
      .map(([ip, count]) => ({ ip, count }))
      .sort((a, b) => b.count - a.count)
      .slice(0, 10);

    return {
      totalEvents,
      blockedEvents,
      eventsByType,
      eventsBySeverity,
      topSources,
      timeRange: {
        start: this.startTime,
        end: now,
      },
    };
  }

  getEvents(filter?: {
    type?: SecurityEvent['type'];
    severity?: SecurityEvent['severity'];
    since?: Date;
    limit?: number;
  }): SecurityEvent[] {
    let filteredEvents = [...this.events];

    if (filter?.type) {
      filteredEvents = filteredEvents.filter(e => e.type === filter.type);
    }

    if (filter?.severity) {
      filteredEvents = filteredEvents.filter(e => e.severity === filter.severity);
    }

    if (filter?.since) {
      filteredEvents = filteredEvents.filter(e => e.timestamp >= filter.since!);
    }

    if (filter?.limit) {
      filteredEvents = filteredEvents.slice(-filter.limit);
    }

    return filteredEvents.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
  }

  clearEvents(): void {
    this.events = [];
    this.alertCounts = {};
  }

  exportEvents(format: 'json' | 'csv' = 'json'): string {
    if (format === 'csv') {
      const headers = ['id', 'type', 'severity', 'timestamp', 'blocked', 'source_ip', 'user_agent', 'details'];
      const rows = this.events.map(event => [
        event.id,
        event.type,
        event.severity,
        event.timestamp.toISOString(),
        event.blocked.toString(),
        event.source.ip || '',
        event.source.userAgent || '',
        JSON.stringify(event.details),
      ]);

      return [headers, ...rows].map(row => row.join(',')).join('\n');
    }

    return JSON.stringify(this.events, null, 2);
  }

  private generateEventId(): string {
    return `sec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  private logEvent(event: SecurityEvent): void {
    const logLevel = this.getLogLevel(event.severity);
    if (!this.shouldLog(logLevel)) return;

    const message = `Security Event [${event.type}]: ${event.severity.toUpperCase()} - ${JSON.stringify(event.details)}`;

    switch (logLevel) {
      case 'error':
        console.error(message);
        break;
      case 'warn':
        console.warn(message);
        break;
      case 'info':
        console.info(message);
        break;
      case 'debug':
        console.debug(message);
        break;
    }
  }

  private getLogLevel(severity: SecurityEvent['severity']): 'debug' | 'info' | 'warn' | 'error' {
    switch (severity) {
      case 'critical': return 'error';
      case 'high': return 'error';
      case 'medium': return 'warn';
      case 'low': return 'info';
      default: return 'debug';
    }
  }

  private shouldLog(level: 'debug' | 'info' | 'warn' | 'error'): boolean {
    const levels = ['debug', 'info', 'warn', 'error'];
    const currentLevelIndex = levels.indexOf(this.options.logLevel!);
    const eventLevelIndex = levels.indexOf(level);
    return eventLevelIndex >= currentLevelIndex;
  }

  private checkAlertThresholds(event: SecurityEvent): void {
    const thresholds = this.options.alertThresholds!;
    const threshold = event.severity === 'low' ? undefined : thresholds[event.severity as keyof typeof thresholds];
    if (!threshold) return;

    const key = `${event.severity}_${event.type}`;
    this.alertCounts[key] = (this.alertCounts[key] || 0) + 1;

    if (this.alertCounts[key] >= threshold && this.options.onAlert) {
      this.options.onAlert(event);
    }
  }
}

// Singleton instance for global use
export const runtimeMonitor = new RuntimeSecurityMonitor();
