import { logger } from '../../utils/logger';
import http from 'http';
import https from 'https';

export interface LoadTestConfig {
  targetUrl: string;
  concurrentUsers: number;
  duration: number; // seconds
  rampUpTime: number; // seconds
  requestsPerSecond?: number;
  payload?: any;
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
  headers?: Record<string, string>;
}

export interface LoadTestResult {
  totalRequests: number;
  successfulRequests: number;
  failedRequests: number;
  avgResponseTime: number;
  minResponseTime: number;
  maxResponseTime: number;
  p50ResponseTime: number;
  p95ResponseTime: number;
  p99ResponseTime: number;
  requestsPerSecond: number;
  errorRate: number;
  timestamp: string;
  duration: number;
}

export interface PerformanceReport {
  testId: string;
  config: LoadTestConfig;
  results: LoadTestResult;
  recommendations: string[];
  bottlenecks: string[];
  passed: boolean;
}

/**
 * [OP-ST001] 测试用例与质量保证 - 并发压力测试
 * Task ID: OP-ST001
 * 
 * 功能：
 * 1. 模拟并发用户负载
 * 2. 测量系统响应时间和吞吐量
 * 3. 识别性能瓶颈
 * 4. 生成性能报告
 * 5. 提供优化建议
 */
export class LoadTestService {
  private static readonly DEFAULT_CONFIG: Partial<LoadTestConfig> = {
    method: 'GET',
    headers: {
      'Content-Type': 'application/json',
    },
  };

  private static readonly PERFORMANCE_THRESHOLDS = {
    maxAvgResponseTime: 500, // ms
    maxP95ResponseTime: 1000, // ms
    maxErrorRate: 0.01, // 1%
    minRequestsPerSecond: 100,
  };

  /**
   * 执行负载测试
   */
  static async runLoadTest(config: LoadTestConfig): Promise<PerformanceReport> {
    const testId = `LOAD-${Date.now()}`;
    const mergedConfig = { ...this.DEFAULT_CONFIG, ...config };

    logger.info(`[LoadTest] Starting load test ${testId}: ${config.concurrentUsers} users for ${config.duration}s`);

    const startTime = Date.now();
    const responseTimes: number[] = [];
    let successfulRequests = 0;
    let failedRequests = 0;

    // 创建并发用户
    const userPromises: Promise<void>[] = [];

    for (let i = 0; i < config.concurrentUsers; i++) {
      // 渐进式增加负载
      const delay = (i / config.concurrentUsers) * config.rampUpTime * 1000;
      
      userPromises.push(
        new Promise<void>(resolve => {
          setTimeout(async () => {
            await this.simulateUser(mergedConfig as LoadTestConfig, config.duration, responseTimes, () => {
              successfulRequests++;
            }, () => {
              failedRequests++;
            });
            resolve();
          }, delay);
        })
      );
    }

    await Promise.all(userPromises);

    const endTime = Date.now();
    const actualDuration = (endTime - startTime) / 1000;

    // 计算统计指标
    const result = this.calculateMetrics(
      responseTimes,
      successfulRequests,
      failedRequests,
      actualDuration
    );

    // 生成报告
    const report = this.generateReport(testId, mergedConfig as LoadTestConfig, result);

    logger.info(`[LoadTest] Test ${testId} completed: ${result.successfulRequests} success, ${result.failedRequests} failed, avg ${result.avgResponseTime.toFixed(2)}ms`);

    return report;
  }

  /**
   * 模拟单个用户
   */
  private static async simulateUser(
    config: LoadTestConfig,
    duration: number,
    responseTimes: number[],
    onSuccess: () => void,
    onFailure: () => void
  ): Promise<void> {
    const endTime = Date.now() + duration * 1000;

    while (Date.now() < endTime) {
      const requestStart = Date.now();

      try {
        await this.makeRequest(config);
        const responseTime = Date.now() - requestStart;
        responseTimes.push(responseTime);
        onSuccess();
      } catch (error) {
        onFailure();
      }

      // 控制请求频率
      if (config.requestsPerSecond) {
        const delay = 1000 / config.requestsPerSecond;
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }

  /**
   * 发送 HTTP 请求
   */
  private static makeRequest(config: LoadTestConfig): Promise<void> {
    return new Promise((resolve, reject) => {
      const url = new URL(config.targetUrl);
      const client = url.protocol === 'https:' ? https : http;

      const options = {
        hostname: url.hostname,
        port: url.port,
        path: url.pathname + url.search,
        method: config.method,
        headers: config.headers,
      };

      const req = client.request(options, (res) => {
        let data = '';
        res.on('data', chunk => data += chunk);
        res.on('end', () => {
          if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
            resolve();
          } else {
            reject(new Error(`HTTP ${res.statusCode}`));
          }
        });
      });

      req.on('error', reject);

      if (config.payload) {
        req.write(JSON.stringify(config.payload));
      }

      req.end();
    });
  }

  /**
   * 计算性能指标
   */
  private static calculateMetrics(
    responseTimes: number[],
    successfulRequests: number,
    failedRequests: number,
    duration: number
  ): LoadTestResult {
    const totalRequests = successfulRequests + failedRequests;
    
    if (responseTimes.length === 0) {
      return {
        totalRequests,
        successfulRequests,
        failedRequests,
        avgResponseTime: 0,
        minResponseTime: 0,
        maxResponseTime: 0,
        p50ResponseTime: 0,
        p95ResponseTime: 0,
        p99ResponseTime: 0,
        requestsPerSecond: 0,
        errorRate: failedRequests / totalRequests,
        timestamp: new Date().toISOString(),
        duration,
      };
    }

    const sortedTimes = [...responseTimes].sort((a, b) => a - b);
    const sum = sortedTimes.reduce((a, b) => a + b, 0);

    return {
      totalRequests,
      successfulRequests,
      failedRequests,
      avgResponseTime: sum / sortedTimes.length,
      minResponseTime: sortedTimes[0],
      maxResponseTime: sortedTimes[sortedTimes.length - 1],
      p50ResponseTime: this.getPercentile(sortedTimes, 50),
      p95ResponseTime: this.getPercentile(sortedTimes, 95),
      p99ResponseTime: this.getPercentile(sortedTimes, 99),
      requestsPerSecond: totalRequests / duration,
      errorRate: failedRequests / totalRequests,
      timestamp: new Date().toISOString(),
      duration,
    };
  }

  /**
   * 获取百分位数
   */
  private static getPercentile(sortedArray: number[], percentile: number): number {
    const index = Math.ceil((percentile / 100) * sortedArray.length) - 1;
    return sortedArray[Math.max(0, index)];
  }

  /**
   * 生成性能报告
   */
  private static generateReport(
    testId: string,
    config: LoadTestConfig,
    results: LoadTestResult
  ): PerformanceReport {
    const recommendations: string[] = [];
    const bottlenecks: string[] = [];

    // 检查平均响应时间
    if (results.avgResponseTime > this.PERFORMANCE_THRESHOLDS.maxAvgResponseTime) {
      bottlenecks.push(`Average response time (${results.avgResponseTime.toFixed(2)}ms) exceeds threshold (${this.PERFORMANCE_THRESHOLDS.maxAvgResponseTime}ms)`);
      recommendations.push('Consider optimizing database queries or adding caching layer');
    }

    // 检查 P95 响应时间
    if (results.p95ResponseTime > this.PERFORMANCE_THRESHOLDS.maxP95ResponseTime) {
      bottlenecks.push(`P95 response time (${results.p95ResponseTime.toFixed(2)}ms) exceeds threshold (${this.PERFORMANCE_THRESHOLDS.maxP95ResponseTime}ms)`);
      recommendations.push('Implement request queuing or rate limiting');
    }

    // 检查错误率
    if (results.errorRate > this.PERFORMANCE_THRESHOLDS.maxErrorRate) {
      bottlenecks.push(`Error rate (${(results.errorRate * 100).toFixed(2)}%) exceeds threshold (${(this.PERFORMANCE_THRESHOLDS.maxErrorRate * 100).toFixed(2)}%)`);
      recommendations.push('Review error logs and fix underlying issues');
    }

    // 检查吞吐量
    if (results.requestsPerSecond < this.PERFORMANCE_THRESHOLDS.minRequestsPerSecond) {
      bottlenecks.push(`Throughput (${results.requestsPerSecond.toFixed(2)} req/s) below minimum (${this.PERFORMANCE_THRESHOLDS.minRequestsPerSecond} req/s)`);
      recommendations.push('Scale horizontally by adding more server instances');
    }

    // 通用建议
    if (recommendations.length === 0) {
      recommendations.push('System performance is within acceptable thresholds');
      recommendations.push('Continue monitoring under production load');
    }

    const passed = bottlenecks.length === 0;

    return {
      testId,
      config,
      results,
      recommendations,
      bottlenecks,
      passed,
    };
  }

  /**
   * 运行标准压力测试套件
   */
  static async runStandardSuite(baseUrl: string): Promise<PerformanceReport[]> {
    logger.info('[LoadTest] Running standard load test suite');

    const tests: LoadTestConfig[] = [
      {
        targetUrl: `${baseUrl}/api/health`,
        concurrentUsers: 10,
        duration: 60,
        rampUpTime: 5,
        method: 'GET',
      },
      {
        targetUrl: `${baseUrl}/api/orders`,
        concurrentUsers: 50,
        duration: 120,
        rampUpTime: 10,
        method: 'GET',
      },
      {
        targetUrl: `${baseUrl}/api/products`,
        concurrentUsers: 100,
        duration: 180,
        rampUpTime: 15,
        method: 'GET',
      },
    ];

    const reports: PerformanceReport[] = [];

    for (const test of tests) {
      const report = await this.runLoadTest(test);
      reports.push(report);

      // 如果测试失败，提前终止
      if (!report.passed) {
        logger.warn(`[LoadTest] Test failed, stopping suite early`);
        break;
      }
    }

    return reports;
  }

  /**
   * 生成测试摘要
   */
  static generateSummary(reports: PerformanceReport[]): string {
    const passed = reports.filter(r => r.passed).length;
    const failed = reports.filter(r => !r.passed).length;
    const total = reports.length;

    const avgResponseTime = reports.reduce((sum, r) => sum + r.results.avgResponseTime, 0) / total;
    const avgThroughput = reports.reduce((sum, r) => sum + r.results.requestsPerSecond, 0) / total;

    return `
Load Test Summary
=================
Total Tests: ${total}
Passed: ${passed}
Failed: ${failed}
Success Rate: ${((passed / total) * 100).toFixed(1)}%

Average Response Time: ${avgResponseTime.toFixed(2)}ms
Average Throughput: ${avgThroughput.toFixed(2)} req/s

${failed > 0 ? '⚠️ Some tests failed. Review bottlenecks and recommendations.' : '✅ All tests passed!'}
    `.trim();
  }
}
