// @lifecycle canonical - Collects performance metrics for MCP server.
/**
 * Performance Monitoring System
 *
 * Comprehensive performance tracking and optimization for the MCP server
 * Focuses on execution metrics, memory usage, and system health monitoring
 */

import * as os from 'os';

import { Logger } from '../../logging/index.js';
// REMOVED: ExecutionCoordinator - modular chain system removed

export interface PerformanceMetrics {
  timestamp: number;

  // Memory metrics
  memory: {
    heapUsed: number;
    heapTotal: number;
    external: number;
    rss: number;
  };

  // Execution metrics
  execution: {
    totalExecutions: number;
    averageExecutionTime: number;
    successRate: number;
    activeExecutions: number;
  };

  // System metrics
  system: {
    uptime: number;
    cpuUsage: number[]; // [user percentage, system percentage]
    loadAverage: number[];
  };

  // Chain-specific metrics
  chains: {
    activeChains: number;
    averageChainLength: number;
    chainSuccessRate: number;
    averageChainExecutionTime: number;
  };
}

export interface PerformanceThresholds {
  memoryThreshold: number; // MB
  executionTimeThreshold: number; // ms
  successRateThreshold: number; // percentage
  chainExecutionTimeThreshold: number; // ms
}

export interface PerformanceAlert {
  level: 'warning' | 'error' | 'critical';
  category: 'memory' | 'execution' | 'chains' | 'system';
  message: string;
  timestamp: number;
  metrics?: Partial<PerformanceMetrics>;
  recommendation?: string;
}

/**
 * Performance monitoring and optimization system
 */
export class PerformanceMonitor {
  private logger: Logger;
  // REMOVED: executionCoordinator - modular chain system removed

  // Performance tracking
  private metricsHistory: PerformanceMetrics[] = [];
  private maxHistorySize = 1000; // Keep last 1000 measurements
  private monitoringInterval: NodeJS.Timeout | undefined;
  private alertingCallbacks: ((alert: PerformanceAlert) => void)[] = [];

  // Performance thresholds
  private thresholds: PerformanceThresholds = {
    memoryThreshold: 512, // MB
    executionTimeThreshold: 5000, // 5 seconds
    successRateThreshold: 95, // 95%
    chainExecutionTimeThreshold: 30000, // 30 seconds
  };

  // CPU tracking for delta calculation
  private previousCpuUsage: NodeJS.CpuUsage | null = null;
  private previousCpuTime = 0;

  // Optimization state
  private optimizationScheduled = false;
  private lastOptimization = 0;
  private optimizationInterval = 300000; // 5 minutes

  constructor(logger: Logger, thresholds?: Partial<PerformanceThresholds>) {
    this.logger = logger;

    if (thresholds) {
      this.thresholds = { ...this.thresholds, ...thresholds };
    }
  }

  // REMOVED: setExecutionCoordinator - ExecutionCoordinator removed

  /**
   * Check if we're running in a test environment
   */
  private isTestEnvironment(): boolean {
    const env = process.env;
    return (
      env['NODE_ENV'] === 'test' ||
      process.argv.includes('--suppress-debug') ||
      process.argv.includes('--test-mode') ||
      // Detect GitHub Actions CI environment
      env['GITHUB_ACTIONS'] === 'true' ||
      env['CI'] === 'true' ||
      // Detect common test runner patterns
      process.argv.some(
        (arg) => arg.includes('test') || arg.includes('jest') || arg.includes('mocha')
      ) ||
      // Detect if called from integration test scripts
      (process.argv[1]?.includes('tests/scripts/') ?? false)
    );
  }

  /**
   * Start performance monitoring
   * SUPPRESSED in test environments to prevent hanging processes
   */
  startMonitoring(intervalMs: number = 30000): void {
    // Default: 30 seconds
    if (this.monitoringInterval) {
      this.stopMonitoring();
    }

    // Skip performance monitoring in test environments to prevent hanging processes
    if (this.isTestEnvironment()) {
      this.logger.debug('Performance monitoring suppressed in test environment');
      return;
    }

    this.logger.info(`Starting performance monitoring (interval: ${intervalMs}ms)`);

    // Take initial measurement
    this.collectMetrics();

    // Set up regular monitoring
    this.monitoringInterval = setInterval(() => {
      this.collectMetrics();
      this.checkThresholds();
      this.scheduleOptimization();
    }, intervalMs);
  }

  /**
   * Stop performance monitoring
   */
  stopMonitoring(): void {
    if (this.monitoringInterval) {
      clearInterval(this.monitoringInterval);
      this.monitoringInterval = undefined;
      this.logger.info('Performance monitoring stopped');
    }
  }

  /**
   * Collect current performance metrics
   */
  collectMetrics(): PerformanceMetrics {
    const timestamp = Date.now();
    const memoryUsage = process.memoryUsage();
    const currentCpuUsage = process.cpuUsage();

    // Calculate CPU percentage from deltas
    let cpuPercentage = [0, 0]; // [user%, system%]
    if (this.previousCpuUsage && this.previousCpuTime) {
      const timeDelta = timestamp - this.previousCpuTime; // milliseconds
      const userDelta = currentCpuUsage.user - this.previousCpuUsage.user; // microseconds
      const systemDelta = currentCpuUsage.system - this.previousCpuUsage.system; // microseconds

      if (timeDelta > 0) {
        // Convert to percentages (microseconds to milliseconds, then percentage)
        const userPercent = (userDelta / 1000 / timeDelta) * 100;
        const systemPercent = (systemDelta / 1000 / timeDelta) * 100;
        cpuPercentage = [Math.min(userPercent, 100), Math.min(systemPercent, 100)];
      }
    }

    // Store current values for next calculation
    this.previousCpuUsage = currentCpuUsage;
    this.previousCpuTime = timestamp;

    // Get execution metrics if available
    let executionMetrics = {
      totalExecutions: 0,
      averageExecutionTime: 0,
      successRate: 100,
      activeExecutions: 0,
    };

    // REMOVED: ExecutionCoordinator metrics - execution handled by PromptExecutor
    // Default execution metrics since ExecutionCoordinator removed

    const metrics: PerformanceMetrics = {
      timestamp,
      memory: {
        heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024), // MB
        heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024), // MB
        external: Math.round(memoryUsage.external / 1024 / 1024), // MB
        rss: Math.round(memoryUsage.rss / 1024 / 1024), // MB
      },
      execution: executionMetrics,
      system: {
        uptime: Math.round(process.uptime()),
        cpuUsage: cpuPercentage, // CPU percentage [user%, system%]
        loadAverage: process.platform !== 'win32' ? os.loadavg() : [0, 0, 0],
      },
      chains: this.calculateChainMetrics(),
    };

    // Store metrics with history management
    this.metricsHistory.push(metrics);
    if (this.metricsHistory.length > this.maxHistorySize) {
      this.metricsHistory.shift();
    }

    this.logger.debug(
      `Performance metrics collected - Memory: ${metrics.memory.heapUsed}MB, Executions: ${metrics.execution.totalExecutions}`
    );

    return metrics;
  }

  /**
   * Get performance metrics history
   */
  getMetricsHistory(count?: number): PerformanceMetrics[] {
    if (count && count < this.metricsHistory.length) {
      return this.metricsHistory.slice(-count);
    }
    return [...this.metricsHistory];
  }

  /**
   * Get latest performance metrics
   */
  getLatestMetrics(): PerformanceMetrics | undefined {
    return this.metricsHistory[this.metricsHistory.length - 1];
  }

  /**
   * Register alerting callback
   */
  onAlert(callback: (alert: PerformanceAlert) => void): void {
    this.alertingCallbacks.push(callback);
  }

  /**
   * Get performance summary over time period
   */
  getPerformanceSummary(periodMs: number = 3600000):
    | {
        // Default: 1 hour
        averageMemory: number;
        peakMemory: number;
        averageExecutionTime: number;
        totalExecutions: number;
        successRate: number;
        alertsGenerated: number;
      }
    | undefined {
    const cutoffTime = Date.now() - periodMs;
    const relevantMetrics = this.metricsHistory.filter((m) => m.timestamp >= cutoffTime);

    if (relevantMetrics.length === 0) {
      return undefined;
    }

    const avgMemory =
      relevantMetrics.reduce((sum, m) => sum + m.memory.heapUsed, 0) / relevantMetrics.length;
    const peakMemory = Math.max(...relevantMetrics.map((m) => m.memory.heapUsed));

    const latestMetrics = relevantMetrics[relevantMetrics.length - 1];
    const earliestMetrics = relevantMetrics[0];

    if (!latestMetrics || !earliestMetrics) {
      return undefined;
    }

    const totalExecutions =
      latestMetrics.execution.totalExecutions - earliestMetrics.execution.totalExecutions;

    return {
      averageMemory: Math.round(avgMemory),
      peakMemory,
      averageExecutionTime: latestMetrics.execution.averageExecutionTime,
      totalExecutions,
      successRate: latestMetrics.execution.successRate,
      alertsGenerated: 0, // Could be implemented with alert history
    };
  }

  /**
   * Force performance optimization
   */
  async optimizePerformance(): Promise<{
    memoryFreed: number;
    optimizationsApplied: string[];
  }> {
    const beforeMemory = process.memoryUsage().heapUsed;
    const optimizations: string[] = [];

    this.logger.info('Starting performance optimization');

    // 1. Trigger garbage collection if available
    if (global.gc) {
      global.gc();
      optimizations.push('Garbage collection executed');
    }

    // REMOVED: Execution history cleanup - ExecutionCoordinator removed

    // 3. Trim metrics history if needed
    if (this.metricsHistory.length > this.maxHistorySize * 0.8) {
      const trimCount = Math.floor(this.metricsHistory.length * 0.2);
      this.metricsHistory.splice(0, trimCount);
      optimizations.push(`Metrics history trimmed (${trimCount} entries)`);
    }

    const afterMemory = process.memoryUsage().heapUsed;
    const memoryFreed = Math.max(0, beforeMemory - afterMemory);

    this.lastOptimization = Date.now();
    this.optimizationScheduled = false;

    this.logger.info(
      `Performance optimization completed - ${optimizations.length} optimizations applied, ${Math.round(memoryFreed / 1024 / 1024)}MB freed`
    );

    return {
      memoryFreed: Math.round(memoryFreed / 1024 / 1024), // MB
      optimizationsApplied: optimizations,
    };
  }

  /**
   * Calculate chain-specific metrics
   */
  private calculateChainMetrics(): PerformanceMetrics['chains'] {
    // REMOVED: ExecutionCoordinator chain metrics - using defaults
    // Chain metrics now tracked by PromptExecutor if needed
    return {
      activeChains: 0,
      averageChainLength: 0,
      chainSuccessRate: 100,
      averageChainExecutionTime: 0,
    };
  }

  /**
   * Check performance thresholds and generate alerts
   */
  private checkThresholds(): void {
    const latest = this.getLatestMetrics();
    if (!latest) return;

    const alerts: PerformanceAlert[] = [];

    // Memory threshold check
    if (latest.memory.heapUsed > this.thresholds.memoryThreshold) {
      alerts.push({
        level:
          latest.memory.heapUsed > this.thresholds.memoryThreshold * 1.5 ? 'critical' : 'warning',
        category: 'memory',
        message: `High memory usage: ${latest.memory.heapUsed}MB (threshold: ${this.thresholds.memoryThreshold}MB)`,
        timestamp: latest.timestamp,
        metrics: { memory: latest.memory },
        recommendation:
          'Consider running performance optimization or reducing execution concurrency',
      });
    }

    // Execution time threshold check
    if (latest.execution.averageExecutionTime > this.thresholds.executionTimeThreshold) {
      alerts.push({
        level: 'warning',
        category: 'execution',
        message: `Slow execution times: ${latest.execution.averageExecutionTime}ms average (threshold: ${this.thresholds.executionTimeThreshold}ms)`,
        timestamp: latest.timestamp,
        metrics: { execution: latest.execution },
        recommendation: 'Review prompt complexity and chain configurations',
      });
    }

    // Success rate threshold check
    if (latest.execution.successRate < this.thresholds.successRateThreshold) {
      alerts.push({
        level: 'error',
        category: 'execution',
        message: `Low success rate: ${latest.execution.successRate.toFixed(1)}% (threshold: ${this.thresholds.successRateThreshold}%)`,
        timestamp: latest.timestamp,
        metrics: { execution: latest.execution },
        recommendation: 'Investigate execution failures and improve error handling',
      });
    }

    // Chain execution time threshold check
    if (latest.chains.averageChainExecutionTime > this.thresholds.chainExecutionTimeThreshold) {
      alerts.push({
        level: 'warning',
        category: 'chains',
        message: `Slow chain execution: ${latest.chains.averageChainExecutionTime}ms average (threshold: ${this.thresholds.chainExecutionTimeThreshold}ms)`,
        timestamp: latest.timestamp,
        metrics: { chains: latest.chains },
        recommendation: 'Optimize chain steps and reduce chain complexity',
      });
    }

    // Send alerts
    alerts.forEach((alert) => {
      this.logger.warn(`Performance alert [${alert.level}]: ${alert.message}`);
      this.alertingCallbacks.forEach((callback) => callback(alert));
    });
  }

  /**
   * Schedule performance optimization if needed
   */
  private scheduleOptimization(): void {
    if (this.optimizationScheduled) return;

    const timeSinceLastOptimization = Date.now() - this.lastOptimization;
    const latest = this.getLatestMetrics();

    if (!latest) return;

    // Schedule optimization if:
    // 1. It's been long enough since last optimization
    // 2. Memory usage is high
    // 3. Execution history is large
    const shouldOptimize =
      timeSinceLastOptimization > this.optimizationInterval ||
      latest.memory.heapUsed > this.thresholds.memoryThreshold * 0.8;
    // REMOVED: Execution history check - ExecutionCoordinator removed

    if (shouldOptimize) {
      this.optimizationScheduled = true;

      // Schedule optimization in next tick to avoid blocking current operations
      setImmediate(() => {
        this.optimizePerformance().catch((error) => {
          this.logger.error('Performance optimization failed:', error);
          this.optimizationScheduled = false;
        });
      });
    }
  }
}

/**
 * Factory function to create a performance monitor
 */
export function createPerformanceMonitor(
  logger: Logger,
  thresholds?: Partial<PerformanceThresholds>
): PerformanceMonitor {
  return new PerformanceMonitor(logger, thresholds);
}
