/**
 * 性能监控系统
 * @file performance-monitor.js
 * @description 全面的系统性能监控工具，包括数据库、API和系统资源监控
 */
const { EventEmitter } = require('events');
const fs = require('fs');
const path = require('path');
const os = require('os');
const logger = require('./logger');
const dbMonitor = require('./db-monitor');
const queryOptimizer = require('./query-optimizer');
const { getPoolStatus } = require('../config/database-pool');

// 性能监控事件发射器
class PerformanceEventEmitter extends EventEmitter {}
const perfEvents = new PerformanceEventEmitter();

// 性能监控系统
class PerformanceMonitor {
  constructor() {
    this.isMonitoring = false;
    this.monitoringInterval = 60000; // 默认监控间隔为1分钟
    this.metricsHistory = {
      database: [],
      api: [],
      system: [],
      memory: []
    };
    this.historyLimit = 100; // 历史记录限制
    this.alertThresholds = {
      database: {
        connectionPoolUtilization: 80, // 连接池利用率阈值（百分比）
        slowQueryCount: 5,            // 慢查询数量阈值
        errorRate: 5                  // 错误率阈值（百分比）
      },
      api: {
        responseTime: 500,            // API响应时间阈值（毫秒）
        errorRate: 5,                 // API错误率阈值（百分比）
        requestRate: 1000             // 每分钟请求数阈值
      },
      system: {
        cpuUsage: 80,                 // CPU使用率阈值（百分比）
        memoryUsage: 80,              // 内存使用率阈值（百分比）
        diskUsage: 80                 // 磁盘使用率阈值（百分比）
      }
    };
    
    // 日志配置
    this.logPath = path.join(process.cwd(), 'logs', 'performance');
    this.ensureLogDirectory();
    
    // API请求统计
    this.apiStats = {
      totalRequests: 0,
      totalErrors: 0,
      endpoints: new Map(), // 按端点统计
      responseTimes: [],
      lastReset: new Date()
    };
    
    // 初始化数据库监控
    this.initDatabaseMonitoring();
  }
  
  // 确保日志目录存在
  ensureLogDirectory() {
    if (!fs.existsSync(this.logPath)) {
      fs.mkdirSync(this.logPath, { recursive: true });
    }
  }
  
  // 初始化数据库监控
  initDatabaseMonitoring() {
    // 监听数据库事件
    dbMonitor.on('statusChange', (status) => {
      this.recordDatabaseMetrics(status);
      perfEvents.emit('databaseStatus', status);
    });
    
    dbMonitor.on('error', (error) => {
      this.logError('database', error);
      perfEvents.emit('databaseError', error);
    });
    
    dbMonitor.on('slowQuery', (query) => {
      perfEvents.emit('slowQuery', query);
    });
  }
  
  // 开始监控
  startMonitoring(interval = this.monitoringInterval) {
    if (this.isMonitoring) {
      return { success: false, message: '监控已经在运行中' };
    }
    
    this.monitoringInterval = interval;
    this.isMonitoring = true;
    
    // 启动数据库监控
    dbMonitor.startMonitoring(interval);
    
    // 启动系统资源监控
    this.monitoringTimer = setInterval(() => {
      this.collectSystemMetrics();
    }, interval);
    
    logger.info(`性能监控已启动，监控间隔: ${interval}ms`);
    perfEvents.emit('monitoringStarted', { interval });
    
    return { success: true, message: `性能监控已启动，监控间隔: ${interval}ms` };
  }
  
  // 停止监控
  stopMonitoring() {
    if (!this.isMonitoring) {
      return { success: false, message: '监控未在运行' };
    }
    
    // 停止数据库监控
    dbMonitor.stopMonitoring();
    
    // 停止系统资源监控
    clearInterval(this.monitoringTimer);
    
    this.isMonitoring = false;
    logger.info('性能监控已停止');
    perfEvents.emit('monitoringStopped');
    
    return { success: true, message: '性能监控已停止' };
  }
  
  // 收集系统指标
  collectSystemMetrics() {
    try {
      // 获取CPU使用情况
      const cpuUsage = this.getCpuUsage();
      
      // 获取内存使用情况
      const memoryUsage = this.getMemoryUsage();
      
      // 获取磁盘使用情况
      const diskUsage = this.getDiskUsage();
      
      // 记录系统指标
      this.recordSystemMetrics({ cpuUsage, memoryUsage, diskUsage });
      
      // 检查是否需要发出警报
      this.checkSystemAlerts({ cpuUsage, memoryUsage, diskUsage });
      
      return { cpuUsage, memoryUsage, diskUsage };
    } catch (error) {
      this.logError('system', error);
      return { error: error.message };
    }
  }
  
  // 获取CPU使用情况
  getCpuUsage() {
    try {
      const cpus = os.cpus();
      let totalIdle = 0;
      let totalTick = 0;
      
      cpus.forEach(cpu => {
        for (const type in cpu.times) {
          totalTick += cpu.times[type];
        }
        totalIdle += cpu.times.idle;
      });
      
      const idle = totalIdle / cpus.length;
      const total = totalTick / cpus.length;
      const usage = 100 - (idle / total * 100);
      
      return {
        usage: parseFloat(usage.toFixed(2)),
        cores: cpus.length,
        model: cpus[0].model,
        speed: cpus[0].speed
      };
    } catch (error) {
      logger.error('获取CPU使用情况失败:', error);
      return { usage: 0, error: error.message };
    }
  }
  
  // 获取内存使用情况
  getMemoryUsage() {
    try {
      const totalMemory = os.totalmem();
      const freeMemory = os.freemem();
      const usedMemory = totalMemory - freeMemory;
      const usage = (usedMemory / totalMemory) * 100;
      
      return {
        total: totalMemory,
        free: freeMemory,
        used: usedMemory,
        usage: parseFloat(usage.toFixed(2))
      };
    } catch (error) {
      logger.error('获取内存使用情况失败:', error);
      return { usage: 0, error: error.message };
    }
  }
  
  // 获取磁盘使用情况（简化版，实际生产环境可能需要使用第三方库）
  getDiskUsage() {
    // 注意：这是一个简化的实现，实际生产环境可能需要使用第三方库如diskusage
    try {
      // 在实际生产环境中，这里应该使用适当的库来获取磁盘使用情况
      // 这里返回一个模拟值
      return {
        total: 1000000000, // 1GB
        free: 500000000,   // 500MB
        used: 500000000,   // 500MB
        usage: 50.0        // 50%
      };
    } catch (error) {
      logger.error('获取磁盘使用情况失败:', error);
      return { usage: 0, error: error.message };
    }
  }
  
  // 记录API请求
  recordApiRequest(req, res, startTime) {
    const duration = Date.now() - startTime;
    const endpoint = `${req.method} ${req.path}`;
    const statusCode = res.statusCode;
    const isError = statusCode >= 400;
    
    // 更新总体统计
    this.apiStats.totalRequests++;
    if (isError) this.apiStats.totalErrors++;
    this.apiStats.responseTimes.push(duration);
    
    // 限制响应时间数组大小
    if (this.apiStats.responseTimes.length > 1000) {
      this.apiStats.responseTimes.shift();
    }
    
    // 更新端点统计
    if (!this.apiStats.endpoints.has(endpoint)) {
      this.apiStats.endpoints.set(endpoint, {
        count: 0,
        errors: 0,
        totalDuration: 0,
        avgDuration: 0,
        minDuration: duration,
        maxDuration: duration
      });
    }
    
    const endpointStats = this.apiStats.endpoints.get(endpoint);
    endpointStats.count++;
    if (isError) endpointStats.errors++;
    endpointStats.totalDuration += duration;
    endpointStats.avgDuration = endpointStats.totalDuration / endpointStats.count;
    endpointStats.minDuration = Math.min(endpointStats.minDuration, duration);
    endpointStats.maxDuration = Math.max(endpointStats.maxDuration, duration);
    
    // 记录API指标
    this.recordApiMetrics({
      endpoint,
      statusCode,
      duration,
      timestamp: new Date(),
      isError
    });
    
    // 检查是否需要发出警报
    if (duration > this.alertThresholds.api.responseTime) {
      perfEvents.emit('slowApiRequest', {
        endpoint,
        duration,
        threshold: this.alertThresholds.api.responseTime
      });
    }
    
    return {
      endpoint,
      statusCode,
      duration,
      isError
    };
  }
  
  // 记录数据库指标
  recordDatabaseMetrics(metrics) {
    this.metricsHistory.database.push({
      ...metrics,
      timestamp: new Date()
    });
    
    // 限制历史记录大小
    if (this.metricsHistory.database.length > this.historyLimit) {
      this.metricsHistory.database.shift();
    }
    
    // 记录到文件
    this.logStatus('database', metrics);
  }
  
  // 记录API指标
  recordApiMetrics(metrics) {
    this.metricsHistory.api.push(metrics);
    
    // 限制历史记录大小
    if (this.metricsHistory.api.length > this.historyLimit) {
      this.metricsHistory.api.shift();
    }
  }
  
  // 记录系统指标
  recordSystemMetrics(metrics) {
    this.metricsHistory.system.push({
      ...metrics,
      timestamp: new Date()
    });
    
    // 限制历史记录大小
    if (this.metricsHistory.system.length > this.historyLimit) {
      this.metricsHistory.system.shift();
    }
    
    // 记录到文件
    this.logStatus('system', metrics);
  }
  
  // 检查系统警报
  checkSystemAlerts(metrics) {
    // 检查CPU使用率
    if (metrics.cpuUsage && metrics.cpuUsage.usage > this.alertThresholds.system.cpuUsage) {
      perfEvents.emit('highCpuUsage', {
        usage: metrics.cpuUsage.usage,
        threshold: this.alertThresholds.system.cpuUsage
      });
    }
    
    // 检查内存使用率
    if (metrics.memoryUsage && metrics.memoryUsage.usage > this.alertThresholds.system.memoryUsage) {
      perfEvents.emit('highMemoryUsage', {
        usage: metrics.memoryUsage.usage,
        threshold: this.alertThresholds.system.memoryUsage
      });
    }
    
    // 检查磁盘使用率
    if (metrics.diskUsage && metrics.diskUsage.usage > this.alertThresholds.system.diskUsage) {
      perfEvents.emit('highDiskUsage', {
        usage: metrics.diskUsage.usage,
        threshold: this.alertThresholds.system.diskUsage
      });
    }
  }
  
  // 记录状态日志
  logStatus(type, data) {
    try {
      const logFile = path.join(this.logPath, `${type}-${new Date().toISOString().split('T')[0]}.log`);
      const logData = JSON.stringify({
        timestamp: new Date().toISOString(),
        data
      });
      
      fs.appendFileSync(logFile, logData + '\n');
    } catch (error) {
      logger.error(`记录${type}状态日志失败:`, error);
    }
  }
  
  // 记录错误日志
  logError(type, error) {
    try {
      const logFile = path.join(this.logPath, `${type}-error-${new Date().toISOString().split('T')[0]}.log`);
      const logData = JSON.stringify({
        timestamp: new Date().toISOString(),
        error: error.message,
        stack: error.stack
      });
      
      fs.appendFileSync(logFile, logData + '\n');
      logger.error(`${type}错误:`, error);
    } catch (logError) {
      logger.error(`记录${type}错误日志失败:`, logError);
    }
  }
  
  // 获取API统计信息
  getApiStats() {
    const responseTimes = this.apiStats.responseTimes;
    const avgResponseTime = responseTimes.length > 0
      ? responseTimes.reduce((sum, time) => sum + time, 0) / responseTimes.length
      : 0;
    
    // 计算错误率
    const errorRate = this.apiStats.totalRequests > 0
      ? (this.apiStats.totalErrors / this.apiStats.totalRequests) * 100
      : 0;
    
    // 计算每分钟请求数
    const minutesSinceReset = (new Date() - this.apiStats.lastReset) / (1000 * 60);
    const requestsPerMinute = minutesSinceReset > 0
      ? this.apiStats.totalRequests / minutesSinceReset
      : 0;
    
    return {
      totalRequests: this.apiStats.totalRequests,
      totalErrors: this.apiStats.totalErrors,
      errorRate: parseFloat(errorRate.toFixed(2)),
      avgResponseTime: parseFloat(avgResponseTime.toFixed(2)),
      requestsPerMinute: parseFloat(requestsPerMinute.toFixed(2)),
      endpoints: Array.from(this.apiStats.endpoints.entries()).map(([endpoint, stats]) => ({
        endpoint,
        ...stats,
        errorRate: stats.count > 0 ? (stats.errors / stats.count) * 100 : 0
      })),
      since: this.apiStats.lastReset
    };
  }
  
  // 重置API统计信息
  resetApiStats() {
    this.apiStats = {
      totalRequests: 0,
      totalErrors: 0,
      endpoints: new Map(),
      responseTimes: [],
      lastReset: new Date()
    };
    
    return { success: true, message: 'API统计信息已重置' };
  }
  
  // 获取数据库性能指标
  async getDatabaseMetrics() {
    try {
      // 获取连接池状态
      const poolStatus = await getPoolStatus();
      
      // 获取慢查询
      const slowQueries = queryOptimizer.getSlowQueries();
      
      // 获取查询模式统计
      const queryPatterns = queryOptimizer.getQueryPatternStats();
      
      return {
        poolStatus,
        slowQueries,
        queryPatterns,
        history: this.metricsHistory.database
      };
    } catch (error) {
      this.logError('database', error);
      return { error: error.message };
    }
  }
  
  // 获取系统性能指标
  getSystemMetrics() {
    try {
      return {
        current: {
          cpu: this.getCpuUsage(),
          memory: this.getMemoryUsage(),
          disk: this.getDiskUsage()
        },
        history: this.metricsHistory.system
      };
    } catch (error) {
      this.logError('system', error);
      return { error: error.message };
    }
  }
  
  // 获取所有性能指标
  async getAllMetrics() {
    try {
      const [databaseMetrics, apiStats, systemMetrics] = await Promise.all([
        this.getDatabaseMetrics(),
        this.getApiStats(),
        this.getSystemMetrics()
      ]);
      
      return {
        database: databaseMetrics,
        api: apiStats,
        system: systemMetrics,
        timestamp: new Date()
      };
    } catch (error) {
      logger.error('获取所有性能指标失败:', error);
      return { error: error.message };
    }
  }
  
  // 设置警报阈值
  setAlertThresholds(thresholds) {
    if (thresholds.database) {
      this.alertThresholds.database = {
        ...this.alertThresholds.database,
        ...thresholds.database
      };
    }
    
    if (thresholds.api) {
      this.alertThresholds.api = {
        ...this.alertThresholds.api,
        ...thresholds.api
      };
    }
    
    if (thresholds.system) {
      this.alertThresholds.system = {
        ...this.alertThresholds.system,
        ...thresholds.system
      };
    }
    
    return { success: true, thresholds: this.alertThresholds };
  }
  
  // 获取警报阈值
  getAlertThresholds() {
    return this.alertThresholds;
  }
  
  // 设置监控间隔
  setMonitoringInterval(interval) {
    if (this.isMonitoring) {
      this.stopMonitoring();
      this.startMonitoring(interval);
    } else {
      this.monitoringInterval = interval;
    }
    
    return { success: true, interval };
  }
  
  // 获取监控状态
  getMonitoringStatus() {
    return {
      isMonitoring: this.isMonitoring,
      interval: this.monitoringInterval,
      startedAt: this.startedAt
    };
  }
}

// 创建性能监控实例
const performanceMonitor = new PerformanceMonitor();

// 创建Express中间件
function performanceMonitorMiddleware(req, res, next) {
  const startTime = Date.now();
  
  // 在请求结束时记录性能指标
  res.on('finish', () => {
    performanceMonitor.recordApiRequest(req, res, startTime);
  });
  
  next();
}

module.exports = {
  performanceMonitor,
  performanceMonitorMiddleware,
  events: perfEvents
};