/**
 * WebSocket Monitoring and Alerting Service
 * Tracks real-time connection health, delivery failures, and performance metrics
 */

export interface ConnectionMetrics {
  timestamp: Date;
  activeConnections: number;
  activityFeedConnections: number;
  revenueForecastConnections: number;
  messagesSent: number;
  messagesReceived: number;
  averageLatency: number;
  errorCount: number;
}

export interface DeliveryAlert {
  type: 'email_failure' | 'sms_failure' | 'forecast_error';
  severity: 'low' | 'medium' | 'high' | 'critical';
  message: string;
  timestamp: Date;
  details?: any;
}

export interface ForecastAccuracyAlert {
  modelType: string;
  accuracy: number;
  threshold: number;
  drift: number;
  timestamp: Date;
  recommendation: string;
}

class WebSocketMonitoringService {
  private metrics: ConnectionMetrics[] = [];
  private alerts: DeliveryAlert[] = [];
  private accuracyAlerts: ForecastAccuracyAlert[] = [];
  private maxMetricsHistory = 1440; // 24 hours of 1-minute metrics

  /**
   * Record connection metrics
   */
  recordMetrics(data: Omit<ConnectionMetrics, 'timestamp'>) {
    const metrics: ConnectionMetrics = {
      ...data,
      timestamp: new Date(),
    };

    this.metrics.push(metrics);

    // Keep only last 24 hours of metrics
    if (this.metrics.length > this.maxMetricsHistory) {
      this.metrics = this.metrics.slice(-this.maxMetricsHistory);
    }

    console.log('[WebSocket Monitoring] Metrics recorded:', {
      activeConnections: metrics.activeConnections,
      messagesSent: metrics.messagesSent,
      averageLatency: `${metrics.averageLatency}ms`,
    });
  }

  /**
   * Record delivery alert
   */
  recordDeliveryAlert(alert: Omit<DeliveryAlert, 'timestamp'>) {
    const fullAlert: DeliveryAlert = {
      ...alert,
      timestamp: new Date(),
    };

    this.alerts.push(fullAlert);

    // Log alert based on severity
    const logLevel = alert.severity === 'critical' ? 'error' : 'warn';
    console[logLevel as 'error' | 'warn']('[WebSocket Monitoring] Delivery Alert:', {
      type: alert.type,
      severity: alert.severity,
      message: alert.message,
    });

    // Trigger notification for critical alerts
    if (alert.severity === 'critical') {
      this.triggerCriticalAlert(fullAlert);
    }
  }

  /**
   * Record forecast accuracy alert
   */
  recordAccuracyAlert(alert: Omit<ForecastAccuracyAlert, 'timestamp'>) {
    const fullAlert: ForecastAccuracyAlert = {
      ...alert,
      timestamp: new Date(),
    };

    this.accuracyAlerts.push(fullAlert);

    console.warn('[WebSocket Monitoring] Forecast Accuracy Alert:', {
      modelType: alert.modelType,
      accuracy: `${alert.accuracy}%`,
      drift: `${alert.drift}%`,
      recommendation: alert.recommendation,
    });
  }

  /**
   * Get connection metrics for time range
   */
  getMetrics(hours: number = 24): ConnectionMetrics[] {
    const cutoffTime = new Date(Date.now() - hours * 60 * 60 * 1000);
    return this.metrics.filter((m) => m.timestamp >= cutoffTime);
  }

  /**
   * Get average connection count
   */
  getAverageConnections(hours: number = 24): number {
    const metrics = this.getMetrics(hours);
    if (metrics.length === 0) return 0;

    const sum = metrics.reduce((acc, m) => acc + m.activeConnections, 0);
    return Math.round(sum / metrics.length);
  }

  /**
   * Get peak connection count
   */
  getPeakConnections(hours: number = 24): number {
    const metrics = this.getMetrics(hours);
    if (metrics.length === 0) return 0;

    return Math.max(...metrics.map((m) => m.activeConnections));
  }

  /**
   * Get average latency
   */
  getAverageLatency(hours: number = 24): number {
    const metrics = this.getMetrics(hours);
    if (metrics.length === 0) return 0;

    const sum = metrics.reduce((acc, m) => acc + m.averageLatency, 0);
    return Math.round(sum / metrics.length);
  }

  /**
   * Get delivery failure rate
   */
  getDeliveryFailureRate(hours: number = 24): {
    emailFailures: number;
    smsFailures: number;
    totalFailures: number;
  } {
    const cutoffTime = new Date(Date.now() - hours * 60 * 60 * 1000);
    const recentAlerts = this.alerts.filter((a) => a.timestamp >= cutoffTime);

    return {
      emailFailures: recentAlerts.filter((a) => a.type === 'email_failure').length,
      smsFailures: recentAlerts.filter((a) => a.type === 'sms_failure').length,
      totalFailures: recentAlerts.length,
    };
  }

  /**
   * Get forecast accuracy summary
   */
  getForecastAccuracySummary(hours: number = 24): {
    modelType: string;
    currentAccuracy: number;
    avgAccuracy: number;
    trend: 'improving' | 'stable' | 'degrading';
  }[] {
    const cutoffTime = new Date(Date.now() - hours * 60 * 60 * 1000);
    const recentAlerts = this.accuracyAlerts.filter((a) => a.timestamp >= cutoffTime);

    const grouped = new Map<string, ForecastAccuracyAlert[]>();
    for (const alert of recentAlerts) {
      if (!grouped.has(alert.modelType)) {
        grouped.set(alert.modelType, []);
      }
      grouped.get(alert.modelType)!.push(alert);
    }

    return Array.from(grouped.entries()).map(([modelType, alerts]) => {
      const accuracies = alerts.map((a) => a.accuracy);
      const currentAccuracy = accuracies[accuracies.length - 1] || 0;
      const avgAccuracy = Math.round(accuracies.reduce((a, b) => a + b, 0) / accuracies.length);

      let trend: 'improving' | 'stable' | 'degrading' = 'stable';
      if (accuracies.length > 1) {
        const firstHalf = accuracies.slice(0, Math.floor(accuracies.length / 2));
        const secondHalf = accuracies.slice(Math.floor(accuracies.length / 2));
        const firstAvg = firstHalf.reduce((a, b) => a + b, 0) / firstHalf.length;
        const secondAvg = secondHalf.reduce((a, b) => a + b, 0) / secondHalf.length;

        if (secondAvg > firstAvg + 2) trend = 'improving';
        else if (secondAvg < firstAvg - 2) trend = 'degrading';
      }

      return {
        modelType,
        currentAccuracy,
        avgAccuracy,
        trend,
      };
    });
  }

  /**
   * Get health status
   */
  getHealthStatus(): {
    status: 'healthy' | 'degraded' | 'critical';
    issues: string[];
    recommendations: string[];
  } {
    const issues: string[] = [];
    const recommendations: string[] = [];

    // Check recent metrics
    const recentMetrics = this.getMetrics(1);
    if (recentMetrics.length > 0) {
      const latest = recentMetrics[recentMetrics.length - 1];

      if (latest.averageLatency > 1000) {
        issues.push('High WebSocket latency detected');
        recommendations.push('Check network conditions and server load');
      }

      if (latest.errorCount > 10) {
        issues.push('High error rate in WebSocket connections');
        recommendations.push('Review server logs and connection handling');
      }
    }

    // Check delivery failures
    const failureRate = this.getDeliveryFailureRate(1);
    if (failureRate.emailFailures > 5) {
      issues.push('Email delivery failures detected');
      recommendations.push('Verify Brevo API credentials and rate limits');
    }

    if (failureRate.smsFailures > 5) {
      issues.push('SMS delivery failures detected');
      recommendations.push('Verify Twilio API credentials and account balance');
    }

    // Check forecast accuracy
    const accuracySummary = this.getForecastAccuracySummary(1);
    for (const model of accuracySummary) {
      if (model.currentAccuracy < 70) {
        issues.push(`${model.modelType} forecast accuracy below threshold`);
        recommendations.push(`Retrain ${model.modelType} model with recent data`);
      }

      if (model.trend === 'degrading') {
        issues.push(`${model.modelType} forecast accuracy degrading`);
        recommendations.push(`Review ${model.modelType} model performance and retrain if needed`);
      }
    }

    let status: 'healthy' | 'degraded' | 'critical' = 'healthy';
    if (issues.length > 0) status = 'degraded';
    if (issues.length > 3 || failureRate.totalFailures > 20) status = 'critical';

    return {
      status,
      issues,
      recommendations,
    };
  }

  /**
   * Trigger critical alert notification
   */
  private triggerCriticalAlert(alert: DeliveryAlert) {
    // In production, this would send to monitoring service (e.g., PagerDuty, Slack)
    console.error('[CRITICAL ALERT]', {
      type: alert.type,
      message: alert.message,
      timestamp: alert.timestamp.toISOString(),
      details: alert.details,
    });
  }

  /**
   * Clear old data
   */
  cleanup() {
    const oneWeekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);

    this.metrics = this.metrics.filter((m) => m.timestamp >= oneWeekAgo);
    this.alerts = this.alerts.filter((a) => a.timestamp >= oneWeekAgo);
    this.accuracyAlerts = this.accuracyAlerts.filter((a) => a.timestamp >= oneWeekAgo);

    console.log('[WebSocket Monitoring] Cleanup completed');
  }
}

export const websocketMonitoringService = new WebSocketMonitoringService();

// Run cleanup every 24 hours
setInterval(() => {
  websocketMonitoringService.cleanup();
}, 24 * 60 * 60 * 1000);
