/**
 * Performance Tracker
 *
 * Records HTTP request metrics in a fixed-size ring buffer and computes
 * percentile-based performance statistics over configurable time windows.
 * Used by the monitoring dashboard to display response time distributions,
 * error rates, and throughput.
 */

import type { PerformanceEntry, PerformanceMetrics } from "./types";

const PERIOD_MS: Record<string, number> = {
  "1h": 3_600_000,
  "6h": 21_600_000,
  "24h": 86_400_000,
  "7d": 604_800_000,
};

const EMPTY_METRICS: PerformanceMetrics = {
  avgResponseTimeMs: 0,
  p95ResponseTimeMs: 0,
  p99ResponseTimeMs: 0,
  errorRate: 0,
  requestsPerMinute: 0,
};

export class PerformanceTracker {
  private readonly buffer: PerformanceEntry[];
  private pointer: number = 0;
  private count: number = 0;
  private readonly capacity: number;

  constructor(capacity: number = 10_000) {
    this.capacity = capacity;
    this.buffer = new Array(capacity);
  }

  track(method: string, path: string, statusCode: number, durationMs: number): void {
    this.buffer[this.pointer] = {
      timestamp: Date.now(),
      method,
      path,
      statusCode,
      durationMs,
    };
    this.pointer = (this.pointer + 1) % this.capacity;
    if (this.count < this.capacity) {
      this.count++;
    }
  }

  getMetrics(period: "1h" | "6h" | "24h" | "7d" = "1h"): PerformanceMetrics {
    const cutoff = Date.now() - (PERIOD_MS[period] ?? PERIOD_MS["1h"]);

    const entries: PerformanceEntry[] = [];
    for (let i = 0; i < this.count; i++) {
      const entry = this.buffer[i];
      if (entry && entry.timestamp >= cutoff) {
        entries.push(entry);
      }
    }

    if (entries.length === 0) {
      return { ...EMPTY_METRICS };
    }

    const durations = entries.map((e) => e.durationMs).sort((a, b) => a - b);

    const avg = durations.reduce((sum, d) => sum + d, 0) / durations.length;
    const p95 = percentile(durations, 0.95);
    const p99 = percentile(durations, 0.99);

    const errorCount = entries.filter((e) => e.statusCode >= 500).length;
    const errorRate = errorCount / entries.length;

    const earliestTimestamp = Math.min(...entries.map((e) => e.timestamp));
    const windowMinutes = Math.max((Date.now() - earliestTimestamp) / 60_000, 1);
    const requestsPerMinute = entries.length / windowMinutes;

    return {
      avgResponseTimeMs: Math.round(avg),
      p95ResponseTimeMs: p95,
      p99ResponseTimeMs: p99,
      errorRate: Math.round(errorRate * 1000) / 1000,
      requestsPerMinute: Math.round(requestsPerMinute * 10) / 10,
    };
  }
}

function percentile(sorted: number[], p: number): number {
  const index = Math.floor(sorted.length * p);
  return sorted[Math.min(index, sorted.length - 1)];
}

/** Singleton instance used across the application. */
export const performanceTracker = new PerformanceTracker(10_000);
