/**
 * Alert Trigger Service
 * Monitors metrics and automatically triggers alerts when thresholds are breached
 */

import type { AlertLog, AlertTemplate } from '../db.alerts.schema.ts';
import { alertDeliveryService } from './alertDeliveryService.ts';
import { alertPersistenceService } from './alertPersistenceService.ts';
import { websocketMonitoringService } from './websocketMonitoring.ts';
import * as forecastingService from './revenueForecastingService.ts';

interface AlertThreshold {
  metric: string;
  operator: 'gt' | 'lt' | 'eq' | 'gte' | 'lte';
  value: number;
  severity: 'critical' | 'warning' | 'info';
}

interface MetricSnapshot {
  timestamp: number;
  metric: string;
  value: number;
  team?: string;
}

export class AlertTriggerService {
  private static thresholds: Map<string, AlertThreshold> = new Map([
    [
      'latency_critical',
      {
        metric: 'websocket_latency',
        operator: 'gt',
        value: 500,
        severity: 'critical',
      },
    ],
    [
      'latency_warning',
      {
        metric: 'websocket_latency',
        operator: 'gt',
        value: 300,
        severity: 'warning',
      },
    ],
    [
      'delivery_failure',
      {
        metric: 'delivery_success_rate',
        operator: 'lt',
        value: 0.9,
        severity: 'warning',
      },
    ],
    [
      'forecast_accuracy_degrading',
      {
        metric: 'forecast_accuracy',
        operator: 'lt',
        value: 0.85,
        severity: 'warning',
      },
    ],
    [
      'connection_drop',
      {
        metric: 'active_connections',
        operator: 'lt',
        value: 100,
        severity: 'info',
      },
    ],
  ]);

  private static activeAlerts: Map<string, AlertLog> = new Map();

  /**
   * Check metrics against thresholds and trigger alerts
   */
  static async checkMetrics(): Promise<AlertLog[]> {
    const triggeredAlerts: AlertLog[] = [];

    // Get current metrics
    const metrics = await this.collectMetrics();

    // Check each metric against thresholds
    for (const [alertType, threshold] of this.thresholds) {
      const metric = metrics.find((m) => m.metric === threshold.metric);
      if (!metric) continue;

      const breached = this.evaluateThreshold(metric.value, threshold);
      if (breached) {
        const alert = await this.createAlert(alertType, threshold, metric);
        if (alert) {
          triggeredAlerts.push(alert);
        }
      }
    }

    return triggeredAlerts;
  }

  /**
   * Collect current metrics from all services
   */
  private static async collectMetrics(): Promise<MetricSnapshot[]> {
    const metrics: MetricSnapshot[] = [];

    try {
      // Get WebSocket metrics
      const wsMetrics = websocketMonitoringService.getMetrics();
      metrics.push({
        timestamp: Date.now(),
        metric: 'websocket_latency',
        value: wsMetrics.averageLatency,
      });

      metrics.push({
        timestamp: Date.now(),
        metric: 'active_connections',
        value: wsMetrics.activeConnections,
      });

      // Get delivery metrics
      const deliveryStats = alertDeliveryService.getDeliveryStats();
      metrics.push({
        timestamp: Date.now(),
        metric: 'delivery_success_rate',
        value: deliveryStats.successRate,
      });

      // Get forecast metrics
      const forecastMetrics = forecastingService.getForecastAccuracyMetrics?.();
      metrics.push({
        timestamp: Date.now(),
        metric: 'forecast_accuracy',
        value: forecastMetrics.accuracy,
      });
    } catch (error) {
      console.error('Error collecting metrics:', error);
    }

    return metrics;
  }

  /**
   * Evaluate if metric breaches threshold
   */
  private static evaluateThreshold(value: number, threshold: AlertThreshold): boolean {
    switch (threshold.operator) {
      case 'gt':
        return value > threshold.value;
      case 'lt':
        return value < threshold.value;
      case 'gte':
        return value >= threshold.value;
      case 'lte':
        return value <= threshold.value;
      case 'eq':
        return value === threshold.value;
      default:
        return false;
    }
  }

  /**
   * Create and trigger alert
   */
  private static async createAlert(
    alertType: string,
    threshold: AlertThreshold,
    metric: MetricSnapshot
  ): Promise<AlertLog | null> {
    // Check if alert already active
    if (this.activeAlerts.has(alertType)) {
      return null; // Alert already triggered
    }

    const alert: AlertLog = {
      id: `alert-${alertType}-${Date.now()}`,
      alertType,
      severity: threshold.severity,
      message: `${alertType}: ${threshold.metric} = ${metric.value.toFixed(2)} (threshold: ${threshold.value})`,
      status: 'active',
      team: metric.team,
      escalationCount: 0,
      createdAt: Date.now(),
      updatedAt: Date.now(),
    } as AlertLog;

    // Save alert
    await alertPersistenceService.logAlert(alert);

    // Get template and send
    const template = await alertPersistenceService.getTemplate(alertType);
    if (template) {
      await alertDeliveryService.sendAlert(alert, template);
    }

    // Track active alert
    this.activeAlerts.set(alertType, alert);

    return alert;
  }

  /**
   * Resolve alert
   */
  static async resolveAlert(alertId: string): Promise<boolean> {
    try {
      const alert = await alertPersistenceService.getAlert(alertId);
      if (!alert) return false;

      await alertPersistenceService.updateAlertStatus(alertId, 'resolved', Date.now());
      this.activeAlerts.delete(alert.alertType);

      return true;
    } catch (error) {
      console.error('Error resolving alert:', error);
      return false;
    }
  }

  /**
   * Acknowledge alert
   */
  static async acknowledgeAlert(alertId: string): Promise<boolean> {
    try {
      await alertPersistenceService.updateAlertStatus(alertId, 'acknowledged', Date.now());
      return true;
    } catch (error) {
      console.error('Error acknowledging alert:', error);
      return false;
    }
  }

  /**
   * Get active alerts
   */
  static getActiveAlerts(): AlertLog[] {
    return Array.from(this.activeAlerts.values());
  }

  /**
   * Update threshold
   */
  static updateThreshold(alertType: string, threshold: AlertThreshold): void {
    this.thresholds.set(alertType, threshold);
  }

  /**
   * Get all thresholds
   */
  static getThresholds(): Record<string, AlertThreshold> {
    const result: Record<string, AlertThreshold> = {};
    for (const [key, value] of this.thresholds) {
      result[key] = value;
    }
    return result;
  }

  /**
   * Start periodic metric checking
   */
  static startMonitoring(intervalMs: number = 60000): NodeJS.Timer {
    return setInterval(async () => {
      try {
        await this.checkMetrics();
      } catch (error) {
        console.error('Error in alert trigger monitoring:', error);
      }
    }, intervalMs);
  }
}

export const alertTriggerService = AlertTriggerService;
