/**
 * Rate Limit Monitor
 * 
 * Periodically checks rate limit metrics against configured thresholds
 * and triggers alerts when limits are exceeded.
 * 
 * Designed to run as a cron job every 5 minutes.
 */

import { createClient } from 'jsr:@supabase/supabase-js@2';
import { createEdgeFunction } from '../_shared/edgeFunctionWrapper.ts';
import { edgeLogger } from '../_shared/logger.ts';
import { getMetricsStats } from '../_shared/rateLimitMetrics.ts';

interface AlertConfig {
  id: string;
  metric_type: 'block_rate' | 'total_requests' | 'unique_ips' | 'function_specific';
  threshold_value: number;
  time_window_ms: number;
  function_name?: string;
  enabled: boolean;
}

interface AlertCheck {
  configId: string;
  metricType: string;
  metricValue: number;
  thresholdValue: number;
  timeWindowMs: number;
  functionName?: string;
  exceeded: boolean;
  message: string;
}

async function checkAlertConditions(configs: AlertConfig[]): Promise<AlertCheck[]> {
  const checks: AlertCheck[] = [];

  for (const config of configs) {
    if (!config.enabled) continue;

    const stats = getMetricsStats(config.time_window_ms);
    let metricValue = 0;
    let exceeded = false;
    let message = '';

    switch (config.metric_type) {
      case 'block_rate':
        metricValue = stats.blockRate;
        exceeded = metricValue > config.threshold_value;
        message = `Rate limit block rate (${(metricValue * 100).toFixed(1)}%) exceeded threshold (${(config.threshold_value * 100).toFixed(1)}%) in last ${config.time_window_ms / 1000}s. ${stats.blockedRequests} of ${stats.totalRequests} requests blocked.`;
        break;

      case 'total_requests':
        metricValue = stats.totalRequests;
        exceeded = metricValue > config.threshold_value;
        message = `Total requests (${metricValue}) exceeded threshold (${config.threshold_value}) in last ${config.time_window_ms / 1000}s.`;
        break;

      case 'unique_ips':
        metricValue = stats.uniqueIPs;
        exceeded = metricValue > config.threshold_value;
        message = `Unique IPs (${metricValue}) exceeded threshold (${config.threshold_value}) in last ${config.time_window_ms / 1000}s. Possible DDoS attack.`;
        break;

      case 'function_specific':
        // For function-specific alerts, we'd need to track metrics per function
        // This would require enhancing the metrics system
        console.log('Function-specific alerts not yet implemented');
        continue;
    }

    checks.push({
      configId: config.id,
      metricType: config.metric_type,
      metricValue,
      thresholdValue: config.threshold_value,
      timeWindowMs: config.time_window_ms,
      functionName: config.function_name,
      exceeded,
      message,
    });
  }

  return checks;
}

async function recordAlert(
  supabase: any,
  check: AlertCheck
): Promise<{ success: boolean; error?: string }> {
  try {
    const { error } = await supabase
      .from('rate_limit_alerts')
      .insert({
        config_id: check.configId,
        metric_type: check.metricType,
        metric_value: check.metricValue,
        threshold_value: check.thresholdValue,
        time_window_ms: check.timeWindowMs,
        function_name: check.functionName,
        alert_message: check.message,
      });

    if (error) {
      console.error('Failed to record alert:', error);
      return { success: false, error: error.message };
    }

    return { success: true };
  } catch (error) {
    console.error('Exception recording alert:', error);
    return { 
      success: false, 
      error: error instanceof Error ? error.message : 'Unknown error' 
    };
  }
}

async function sendNotification(
  supabase: any,
  check: AlertCheck
): Promise<{ success: boolean; error?: string }> {
  try {
    // Send notification to moderators via the moderator topic
    const { data, error } = await supabase.functions.invoke('trigger-notification', {
      body: {
        workflowId: 'rate-limit-alert',
        topicKey: 'moderators',
        payload: {
          message: check.message,
          metricType: check.metricType,
          metricValue: check.metricValue,
          thresholdValue: check.thresholdValue,
          functionName: check.functionName || 'all',
        },
        overrides: {
          email: {
            subject: '🚨 Rate Limit Alert',
          },
        },
      },
    });

    if (error) {
      console.error('Failed to send notification:', error);
      return { success: false, error: error.message };
    }

    return { success: true };
  } catch (error) {
    console.error('Exception sending notification:', error);
    return { 
      success: false, 
      error: error instanceof Error ? error.message : 'Unknown error' 
    };
  }
}

export default createEdgeFunction(
  {
    name: 'monitor-rate-limits',
    requireAuth: false,
  },
  async (req, context, supabase) => {
    const startTime = Date.now();
    edgeLogger.info('Rate limit monitor starting', { requestId: context.requestId });

    // Fetch enabled alert configurations
    const { data: configs, error: configError } = await supabase
      .from('rate_limit_alert_config')
      .select('*')
      .eq('enabled', true);

    if (configError) {
      edgeLogger.error('Failed to fetch alert configs', { 
        error: configError,
        requestId: context.requestId 
      });
      throw configError;
    }

    if (!configs || configs.length === 0) {
      edgeLogger.info('No enabled alert configurations found', { 
        requestId: context.requestId 
      });
      return new Response(
        JSON.stringify({ 
          success: true, 
          message: 'No enabled alert configurations',
          checked: 0
        }),
        { headers: { 'Content-Type': 'application/json' } }
      );
    }

    edgeLogger.info('Checking alert configurations', { 
      count: configs.length,
      requestId: context.requestId 
    });

    // Check all alert conditions
    const checks = await checkAlertConditions(configs);
    const exceededChecks = checks.filter(c => c.exceeded);

    edgeLogger.info('Threshold violations found', { 
      count: exceededChecks.length,
      requestId: context.requestId 
    });

    // Process exceeded thresholds
    const alertResults = [];
    for (const check of exceededChecks) {
      edgeLogger.info('Processing alert', { 
        message: check.message,
        requestId: context.requestId 
      });

      // Check if we've already sent a recent alert for this config
      const { data: recentAlerts } = await supabase
        .from('rate_limit_alerts')
        .select('created_at')
        .eq('config_id', check.configId)
        .is('resolved_at', null)
        .gte('created_at', new Date(Date.now() - 15 * 60 * 1000).toISOString()) // Last 15 minutes
        .order('created_at', { ascending: false })
        .limit(1);

      if (recentAlerts && recentAlerts.length > 0) {
        edgeLogger.info('Skipping alert - recent unresolved alert exists', { 
          configId: check.configId,
          requestId: context.requestId 
        });
        alertResults.push({
          configId: check.configId,
          skipped: true,
          reason: 'Recent alert exists',
        });
        continue;
      }

      // Record the alert
      const recordResult = await recordAlert(supabase, check);
      
      // Send notification
      const notifyResult = await sendNotification(supabase, check);

      alertResults.push({
        configId: check.configId,
        metricType: check.metricType,
        recorded: recordResult.success,
        notified: notifyResult.success,
        recordError: recordResult.error,
        notifyError: notifyResult.error,
      });
    }

    const duration = Date.now() - startTime;
    edgeLogger.info('Monitor completed', { 
      duration,
      requestId: context.requestId 
    });

    return new Response(
      JSON.stringify({
        success: true,
        checked: configs.length,
        exceeded: exceededChecks.length,
        alerts: alertResults,
        duration_ms: duration,
      }),
      { headers: { 'Content-Type': 'application/json' } }
    );
  }
);
