export interface InstanceMetrics {
  instanceId: string;
  status: 'healthy' | 'unhealthy' | 'unknown';
  uptime: number;
  requestCount: number;
  errorCount: number;
  lastRequestAt: Date | null;
  latencyMs: number[];
}

export class MetricsCollector {
  private metrics = new Map<string, InstanceMetrics>();
  private startTimes = new Map<string, Date>();

  register(instanceId: string): void {
    if (!this.metrics.has(instanceId)) {
      this.metrics.set(instanceId, {
        instanceId,
        status: 'unknown',
        uptime: 0,
        requestCount: 0,
        errorCount: 0,
        lastRequestAt: null,
        latencyMs: [],
      });
      this.startTimes.set(instanceId, new Date());
    }
  }

  unregister(instanceId: string): void {
    this.metrics.delete(instanceId);
    this.startTimes.delete(instanceId);
  }

  recordRequest(instanceId: string, latencyMs?: number): void {
    const m = this.ensureMetrics(instanceId);
    m.requestCount++;
    m.lastRequestAt = new Date();
    if (latencyMs !== undefined) {
      m.latencyMs.push(latencyMs);
      // Keep only last 1000 latency samples
      if (m.latencyMs.length > 1000) {
        m.latencyMs = m.latencyMs.slice(-1000);
      }
    }
  }

  recordError(instanceId: string): void {
    const m = this.ensureMetrics(instanceId);
    m.errorCount++;
  }

  updateStatus(instanceId: string, status: InstanceMetrics['status']): void {
    const m = this.ensureMetrics(instanceId);
    m.status = status;
  }

  getMetrics(instanceId: string): InstanceMetrics | undefined {
    const m = this.metrics.get(instanceId);
    if (!m) return undefined;

    // Compute uptime from start time
    const start = this.startTimes.get(instanceId);
    if (start) {
      m.uptime = (Date.now() - start.getTime()) / 1000;
    }

    return { ...m, latencyMs: [...m.latencyMs] };
  }

  getAllMetrics(): InstanceMetrics[] {
    return [...this.metrics.keys()]
      .map((id) => this.getMetrics(id))
      .filter((m): m is InstanceMetrics => m !== undefined);
  }

  getErrorRate(instanceId: string): number {
    const m = this.metrics.get(instanceId);
    if (!m || m.requestCount === 0) return 0;
    return m.errorCount / m.requestCount;
  }

  getAverageLatency(instanceId: string): number {
    const m = this.metrics.get(instanceId);
    if (!m || m.latencyMs.length === 0) return 0;
    const sum = m.latencyMs.reduce((a, b) => a + b, 0);
    return sum / m.latencyMs.length;
  }

  reset(): void {
    this.metrics.clear();
    this.startTimes.clear();
  }

  private ensureMetrics(instanceId: string): InstanceMetrics {
    let m = this.metrics.get(instanceId);
    if (!m) {
      this.register(instanceId);
      m = this.metrics.get(instanceId)!;
    }
    return m;
  }
}
