/**
 * Health Alert Service
 * Monitors health endpoints and triggers alerts on degradation
 *
 * Features:
 * - Configurable thresholds for warning/critical severity levels
 * - Cooldown-based deduplication to prevent alert storms
 * - Extensible alert channel interface (log-only for now, webhook/email ready)
 * - Structured JSON output via existing logger
 * - Recovery detection when components return to operational state
 */

import { logger } from '../logger';
import type { HealthStatus, SystemHealth, HealthCheckResult } from '../types/health';

// ============================================================================
// Types
// ============================================================================

export type AlertSeverity = 'warning' | 'critical' | 'recovery';

export interface AlertConfig {
  /** How long to wait before re-alerting for the same component (ms) */
  cooldownPeriod: number;
  /** Thresholds for different alert levels */
  thresholds: {
    /** Alert after N degraded components */
    degradedCountWarning: number;
    /** Critical alert after N down components */
    downCountCritical: number;
    /** Alert if response time exceeds N ms */
    responseTimeWarning: number;
    /** Critical alert if response time exceeds N ms */
    responseTimeCritical: number;
  };
}

export interface HealthAlert {
  /** Severity level of the alert */
  severity: AlertSeverity;
  /** Component that triggered the alert */
  component: string;
  /** Human-readable alert message */
  message: string;
  /** ISO timestamp when alert was generated */
  timestamp: string;
  /** Additional metrics/context */
  metrics?: Record<string, unknown>;
}

/**
 * Interface for alert channels (log, webhook, email, etc.)
 * Implement this interface to add new notification channels
 */
export interface AlertChannel {
  /** Channel name for identification */
  name: string;
  /** Send an alert through this channel */
  send(alert: HealthAlert): Promise<void>;
}

// ============================================================================
// Default Configuration
// ============================================================================

const DEFAULT_CONFIG: AlertConfig = {
  cooldownPeriod: 5 * 60 * 1000, // 5 minutes
  thresholds: {
    degradedCountWarning: 1,
    downCountCritical: 1,
    responseTimeWarning: 2000, // 2 seconds
    responseTimeCritical: 5000, // 5 seconds
  },
};

// ============================================================================
// Built-in Alert Channels
// ============================================================================

/**
 * Log-only alert channel using structured logger
 */
class LogAlertChannel implements AlertChannel {
  name = 'log';

  async send(alert: HealthAlert): Promise<void> {
    const scopedLogger = logger.scope('HealthAlert');
    const logMeta = {
      component: alert.component,
      severity: alert.severity,
      alertTimestamp: alert.timestamp,
      ...alert.metrics,
    };

    switch (alert.severity) {
      case 'critical':
        scopedLogger.error(alert.message, undefined, logMeta);
        break;
      case 'warning':
        scopedLogger.warn(alert.message, logMeta);
        break;
      case 'recovery':
        scopedLogger.info(alert.message, logMeta);
        break;
    }
  }
}

// ============================================================================
// Health Alert Service
// ============================================================================

export class HealthAlertService {
  /** Tracks last alert time per component to enforce cooldown */
  private lastAlerts: Map<string, Date> = new Map();

  /** Tracks previous status per component for recovery detection */
  private previousStatus: Map<string, HealthStatus> = new Map();

  /** Service configuration */
  private config: AlertConfig;

  /** Registered alert channels */
  private channels: AlertChannel[] = [];

  constructor(config?: Partial<AlertConfig>) {
    this.config = {
      ...DEFAULT_CONFIG,
      ...config,
      thresholds: {
        ...DEFAULT_CONFIG.thresholds,
        ...config?.thresholds,
      },
    };

    // Register default log channel
    this.channels.push(new LogAlertChannel());
  }

  /**
   * Register an additional alert channel
   */
  registerChannel(channel: AlertChannel): void {
    this.channels.push(channel);
    logger.info(`Registered alert channel: ${channel.name}`);
  }

  /**
   * Evaluate system health and generate alerts for any degradations
   * @param health - Current system health snapshot
   * @returns Array of generated alerts
   */
  async evaluateHealth(health: SystemHealth): Promise<HealthAlert[]> {
    const alerts: HealthAlert[] = [];
    const now = new Date();

    // Count degraded and down components
    let degradedCount = 0;
    let downCount = 0;

    for (const component of health.components) {
      if (component.status === 'degraded') degradedCount++;
      if (component.status === 'down') downCount++;
    }

    // Check individual components
    for (const component of health.components) {
      const componentKey = this.getComponentKey(component.name, component.status);
      const previousComponentStatus = this.previousStatus.get(component.name);

      // Check for recovery
      if (
        previousComponentStatus &&
        previousComponentStatus !== 'operational' &&
        component.status === 'operational'
      ) {
        const recoveryAlert = this.createRecoveryAlert(component);
        if (this.shouldAlert(componentKey)) {
          alerts.push(recoveryAlert);
          this.lastAlerts.set(componentKey, now);
        }
      }

      // Check for degradation
      if (component.status === 'degraded') {
        if (this.shouldAlert(componentKey)) {
          alerts.push(this.createDegradedAlert(component));
          this.lastAlerts.set(componentKey, now);
        }
      }

      // Check for down status (critical)
      if (component.status === 'down') {
        if (this.shouldAlert(componentKey)) {
          alerts.push(this.createDownAlert(component));
          this.lastAlerts.set(componentKey, now);
        }
      }

      // Check response time thresholds
      if (component.status === 'operational') {
        const responseTimeAlert = this.checkResponseTime(component);
        if (responseTimeAlert && this.shouldAlert(`${component.name}:response_time`)) {
          alerts.push(responseTimeAlert);
          this.lastAlerts.set(`${component.name}:response_time`, now);
        }
      }

      // Update previous status
      this.previousStatus.set(component.name, component.status);
    }

    // Check aggregate thresholds
    if (degradedCount >= this.config.thresholds.degradedCountWarning) {
      const aggregateKey = 'aggregate:degraded';
      if (this.shouldAlert(aggregateKey)) {
        alerts.push(this.createAggregateAlert('warning', degradedCount, 'degraded'));
        this.lastAlerts.set(aggregateKey, now);
      }
    }

    if (downCount >= this.config.thresholds.downCountCritical) {
      const aggregateKey = 'aggregate:down';
      if (this.shouldAlert(aggregateKey)) {
        alerts.push(this.createAggregateAlert('critical', downCount, 'down'));
        this.lastAlerts.set(aggregateKey, now);
      }
    }

    // Send all alerts through registered channels
    await this.sendAlerts(alerts);

    return alerts;
  }

  /**
   * Check if we should send an alert (respects cooldown period)
   */
  private shouldAlert(componentKey: string): boolean {
    const lastAlert = this.lastAlerts.get(componentKey);
    if (!lastAlert) return true;

    const elapsed = Date.now() - lastAlert.getTime();
    return elapsed >= this.config.cooldownPeriod;
  }

  /**
   * Generate a unique key for tracking alerts per component/status
   */
  private getComponentKey(componentName: string, status: HealthStatus): string {
    return `${componentName}:${status}`;
  }

  /**
   * Create alert for degraded component
   */
  private createDegradedAlert(component: HealthCheckResult): HealthAlert {
    return {
      severity: 'warning',
      component: component.name,
      message: `Component ${component.name} is degraded: ${component.message || 'No details available'}`,
      timestamp: new Date().toISOString(),
      metrics: {
        status: component.status,
        responseTime: component.responseTime,
        lastChecked: component.lastChecked,
        ...component.details,
      },
    };
  }

  /**
   * Create alert for down component
   */
  private createDownAlert(component: HealthCheckResult): HealthAlert {
    return {
      severity: 'critical',
      component: component.name,
      message: `Component ${component.name} is DOWN: ${component.message || 'No details available'}`,
      timestamp: new Date().toISOString(),
      metrics: {
        status: component.status,
        responseTime: component.responseTime,
        lastChecked: component.lastChecked,
        ...component.details,
      },
    };
  }

  /**
   * Create recovery alert when component returns to operational
   */
  private createRecoveryAlert(component: HealthCheckResult): HealthAlert {
    return {
      severity: 'recovery',
      component: component.name,
      message: `Component ${component.name} has recovered and is now operational`,
      timestamp: new Date().toISOString(),
      metrics: {
        status: component.status,
        responseTime: component.responseTime,
        lastChecked: component.lastChecked,
      },
    };
  }

  /**
   * Check if response time exceeds thresholds
   */
  private checkResponseTime(component: HealthCheckResult): HealthAlert | null {
    const { responseTimeWarning, responseTimeCritical } = this.config.thresholds;

    if (component.responseTime >= responseTimeCritical) {
      return {
        severity: 'critical',
        component: component.name,
        message: `Component ${component.name} response time critical: ${component.responseTime}ms (threshold: ${responseTimeCritical}ms)`,
        timestamp: new Date().toISOString(),
        metrics: {
          responseTime: component.responseTime,
          threshold: responseTimeCritical,
          status: component.status,
        },
      };
    }

    if (component.responseTime >= responseTimeWarning) {
      return {
        severity: 'warning',
        component: component.name,
        message: `Component ${component.name} response time slow: ${component.responseTime}ms (threshold: ${responseTimeWarning}ms)`,
        timestamp: new Date().toISOString(),
        metrics: {
          responseTime: component.responseTime,
          threshold: responseTimeWarning,
          status: component.status,
        },
      };
    }

    return null;
  }

  /**
   * Create aggregate alert for multiple failing components
   */
  private createAggregateAlert(
    severity: 'warning' | 'critical',
    count: number,
    statusType: 'degraded' | 'down'
  ): HealthAlert {
    return {
      severity,
      component: 'system',
      message: `${count} component(s) are ${statusType}`,
      timestamp: new Date().toISOString(),
      metrics: {
        [`${statusType}Count`]: count,
        threshold:
          statusType === 'down'
            ? this.config.thresholds.downCountCritical
            : this.config.thresholds.degradedCountWarning,
      },
    };
  }

  /**
   * Send alert through all registered channels
   */
  async sendAlert(alert: HealthAlert): Promise<void> {
    await Promise.all(
      this.channels.map(async (channel) => {
        try {
          await channel.send(alert);
        } catch (error) {
          logger.error(`Failed to send alert via ${channel.name}`, error, {
            alert: alert.message,
            component: alert.component,
          });
        }
      })
    );
  }

  /**
   * Send multiple alerts through all channels
   */
  private async sendAlerts(alerts: HealthAlert[]): Promise<void> {
    for (const alert of alerts) {
      await this.sendAlert(alert);
    }
  }

  /**
   * Clear alert history (useful for testing)
   */
  clearHistory(): void {
    this.lastAlerts.clear();
    this.previousStatus.clear();
  }

  /**
   * Get current configuration
   */
  getConfig(): AlertConfig {
    return { ...this.config };
  }

  /**
   * Update configuration at runtime
   */
  updateConfig(config: Partial<AlertConfig>): void {
    this.config = {
      ...this.config,
      ...config,
      thresholds: {
        ...this.config.thresholds,
        ...config?.thresholds,
      },
    };
    logger.info('Health alert configuration updated', {
      cooldownPeriod: this.config.cooldownPeriod,
      thresholds: this.config.thresholds,
    });
  }
}

// ============================================================================
// Singleton Export
// ============================================================================

// ============================================================================
// Web Vitals Alert Types and Service
// ============================================================================

export interface WebVitalsAlertParams {
  vitalName: 'LCP' | 'TTFB';
  alertLevel: 'warning' | 'critical';
  currentP90: number;
  threshold: number;
  sampleCount: number;
  timestamp: string;
}

export interface WebVitalsStats {
  vitalName: string;
  sampleCount: number;
  avg: number;
  p90: number;
  alertLevel?: 'ok' | 'warning' | 'critical';
}

/**
 * Extended Health Alert Service with Web Vitals Support
 */
class ExtendedHealthAlertService extends HealthAlertService {
  /** Tracks last web vitals alert time per vital to enforce cooldown */
  private lastWebVitalsAlerts: Map<string, Date> = new Map();

  /** Web vitals alert cooldown (15 minutes) */
  private webVitalsCooldown = 15 * 60 * 1000;

  /**
   * Send web vitals alert when performance regresses
   */
  async sendWebVitalsAlert(params: WebVitalsAlertParams): Promise<void> {
    const alertKey = `webvitals:${params.vitalName}:${params.alertLevel}`;

    // Check cooldown
    const lastAlert = this.lastWebVitalsAlerts.get(alertKey);
    if (lastAlert) {
      const elapsed = Date.now() - lastAlert.getTime();
      if (elapsed < this.webVitalsCooldown) {
        logger.debug('Web vitals alert skipped (cooldown)', {
          vitalName: params.vitalName,
          alertLevel: params.alertLevel,
          remainingCooldown: this.webVitalsCooldown - elapsed,
        });
        return;
      }
    }

    const alert: HealthAlert = {
      severity: params.alertLevel,
      component: `webvitals:${params.vitalName}`,
      message: `Web Vital ${params.vitalName} p90 is ${params.alertLevel}: ${params.currentP90.toFixed(0)}ms (threshold: ${params.threshold}ms)`,
      timestamp: params.timestamp,
      metrics: {
        vitalName: params.vitalName,
        currentP90: params.currentP90,
        threshold: params.threshold,
        sampleCount: params.sampleCount,
      },
    };

    // Update cooldown tracker
    this.lastWebVitalsAlerts.set(alertKey, new Date());

    // Send through all channels
    await this.sendAlert(alert);

    // Also send email notification if critical
    if (params.alertLevel === 'critical') {
      await this.sendWebVitalsCriticalEmail(params);
    }
  }

  /**
   * Send critical web vitals alert email to admins
   */
  private async sendWebVitalsCriticalEmail(params: WebVitalsAlertParams): Promise<void> {
    const adminEmail = process.env.ADMIN_ALERT_EMAIL;
    if (!adminEmail) {
      logger.debug('No ADMIN_ALERT_EMAIL configured, skipping email alert');
      return;
    }

    // Import email function dynamically to avoid circular dependency
    try {
      const { sendEmail } = await import('@/lib/email');

      const subject = `🚨 Critical: ${params.vitalName} Performance Degradation`;
      const html = `
        <div style="font-family: sans-serif; max-width: 600px; margin: 0 auto;">
          <h2 style="color: #dc2626;">🚨 Web Vitals Alert: ${params.vitalName}</h2>
          <p>A critical performance degradation has been detected.</p>
          <table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
            <tr style="background: #fef2f2;">
              <td style="padding: 10px; border: 1px solid #fca5a5;"><strong>Metric</strong></td>
              <td style="padding: 10px; border: 1px solid #fca5a5;">${params.vitalName}</td>
            </tr>
            <tr>
              <td style="padding: 10px; border: 1px solid #fca5a5;"><strong>Current p90</strong></td>
              <td style="padding: 10px; border: 1px solid #fca5a5; color: #dc2626; font-weight: bold;">${params.currentP90.toFixed(0)}ms</td>
            </tr>
            <tr>
              <td style="padding: 10px; border: 1px solid #fca5a5;"><strong>Threshold</strong></td>
              <td style="padding: 10px; border: 1px solid #fca5a5;">${params.threshold}ms</td>
            </tr>
            <tr>
              <td style="padding: 10px; border: 1px solid #fca5a5;"><strong>Sample Count</strong></td>
              <td style="padding: 10px; border: 1px solid #fca5a5;">${params.sampleCount}</td>
            </tr>
            <tr>
              <td style="padding: 10px; border: 1px solid #fca5a5;"><strong>Timestamp</strong></td>
              <td style="padding: 10px; border: 1px solid #fca5a5;">${params.timestamp}</td>
            </tr>
          </table>
          <p style="color: #666; font-size: 12px;">
            This alert was generated automatically by the Mawidi health monitoring system.
          </p>
        </div>
      `;
      const text = `
Web Vitals Alert: ${params.vitalName}

A critical performance degradation has been detected.

Metric: ${params.vitalName}
Current p90: ${params.currentP90.toFixed(0)}ms
Threshold: ${params.threshold}ms
Sample Count: ${params.sampleCount}
Timestamp: ${params.timestamp}

This alert was generated automatically by the Mawidi health monitoring system.
      `.trim();

      await sendEmail(adminEmail, { subject, html, text });
      logger.info('Critical web vitals alert email sent', { adminEmail, vitalName: params.vitalName });
    } catch (error) {
      logger.error('Failed to send critical web vitals alert email', error);
    }
  }

  /**
   * Clear web vitals alert history
   */
  clearWebVitalsHistory(): void {
    this.lastWebVitalsAlerts.clear();
  }

  /**
   * Send DLQ SLA alert when items exceed the 24-hour review threshold
   */
  async sendDlqSlaAlert(params: {
    exceedingSla: number;
    archived: number;
    timestamp: string;
  }): Promise<void> {
    const alertKey = 'dlq:sla';

    // Check cooldown (1 hour for DLQ alerts)
    const dlqAlertCooldown = 60 * 60 * 1000;
    const lastAlert = this.lastWebVitalsAlerts.get(alertKey);
    if (lastAlert) {
      const elapsed = Date.now() - lastAlert.getTime();
      if (elapsed < dlqAlertCooldown) {
        logger.debug('DLQ SLA alert skipped (cooldown)', {
          exceedingSla: params.exceedingSla,
          remainingCooldown: dlqAlertCooldown - elapsed,
        });
        return;
      }
    }

    const severity = params.exceedingSla > 10 ? 'critical' : 'warning';

    const alert: HealthAlert = {
      severity,
      component: 'dlq:sla',
      message: `DLQ SLA Alert: ${params.exceedingSla} item(s) have been unreviewed for over 24 hours`,
      timestamp: params.timestamp,
      metrics: {
        exceedingSla: params.exceedingSla,
        archived: params.archived,
        reviewSlaHours: 24,
      },
    };

    // Update cooldown tracker
    this.lastWebVitalsAlerts.set(alertKey, new Date());

    // Send through all channels
    await this.sendAlert(alert);

    // Send email notification for critical
    if (severity === 'critical') {
      await this.sendDlqSlaCriticalEmail(params);
    }
  }

  /**
   * Send critical DLQ SLA alert email to admins
   */
  private async sendDlqSlaCriticalEmail(params: {
    exceedingSla: number;
    archived: number;
    timestamp: string;
  }): Promise<void> {
    const adminEmail = process.env.ADMIN_ALERT_EMAIL;
    if (!adminEmail) {
      logger.debug('No ADMIN_ALERT_EMAIL configured, skipping DLQ SLA email alert');
      return;
    }

    try {
      const { sendEmail } = await import('@/lib/email');

      const subject = `DLQ SLA Alert: ${params.exceedingSla} items pending review`;
      const html = `
        <div style="font-family: sans-serif; max-width: 600px; margin: 0 auto;">
          <h2 style="color: #ca8a04;">DLQ SLA Alert</h2>
          <p>The following DLQ items have exceeded the 24-hour review SLA and require immediate attention.</p>
          <table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
            <tr style="background: #fefce8;">
              <td style="padding: 10px; border: 1px solid #fde68a;"><strong>Items Exceeding SLA</strong></td>
              <td style="padding: 10px; border: 1px solid #fde68a; color: #ca8a04; font-weight: bold;">${params.exceedingSla}</td>
            </tr>
            <tr>
              <td style="padding: 10px; border: 1px solid #fde68a;"><strong>SLA Threshold</strong></td>
              <td style="padding: 10px; border: 1px solid #fde68a;">24 hours</td>
            </tr>
            <tr>
              <td style="padding: 10px; border: 1px solid #fde68a;"><strong>Items Archived Today</strong></td>
              <td style="padding: 10px; border: 1px solid #fde68a;">${params.archived}</td>
            </tr>
            <tr>
              <td style="padding: 10px; border: 1px solid #fde68a;"><strong>Timestamp</strong></td>
              <td style="padding: 10px; border: 1px solid #fde68a;">${params.timestamp}</td>
            </tr>
          </table>
          <h3>Recommended Actions</h3>
          <ol>
            <li>Review the pending DLQ items in the Staff Dashboard</li>
            <li>Check for recurring error patterns that need systemic fixes</li>
            <li>Replay items that can be safely retried</li>
            <li>Mark items as reviewed with resolution notes</li>
          </ol>
          <p style="margin-top: 20px;">
            <a href="${process.env.NEXT_PUBLIC_BASE_URL || 'https://mawidi.ai'}/staff/dashboard/admin"
               style="background: #0070f3; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px;">
              Review DLQ Items
            </a>
          </p>
          <p style="color: #666; font-size: 12px; margin-top: 30px;">
            This alert was generated automatically by the Mawidi DLQ monitoring system.
          </p>
        </div>
      `;
      const text = `
DLQ SLA Alert

The following DLQ items have exceeded the 24-hour review SLA and require immediate attention.

Items Exceeding SLA: ${params.exceedingSla}
SLA Threshold: 24 hours
Items Archived Today: ${params.archived}
Timestamp: ${params.timestamp}

Recommended Actions:
1. Review the pending DLQ items in the Staff Dashboard
2. Check for recurring error patterns that need systemic fixes
3. Replay items that can be safely retried
4. Mark items as reviewed with resolution notes

Review DLQ Items: ${process.env.NEXT_PUBLIC_BASE_URL || 'https://mawidi.ai'}/staff/dashboard/admin

This alert was generated automatically by the Mawidi DLQ monitoring system.
      `.trim();

      await sendEmail(adminEmail, { subject, html, text });
      logger.info('DLQ SLA alert email sent', { adminEmail, exceedingSla: params.exceedingSla });
    } catch (error) {
      logger.error('Failed to send DLQ SLA alert email', error);
    }
  }
}

export const healthAlertService = new ExtendedHealthAlertService();
export const healthAlertsService = healthAlertService; // Alias for compatibility
