import { describe, it, expect, beforeEach } from 'vitest';
import { HealthTracker } from '../health.js';

describe('HealthTracker', () => {
  let tracker: HealthTracker;

  beforeEach(() => {
    tracker = new HealthTracker({ windowMs: 10_000, errorThreshold: 0.5, rateLimitThreshold: 0.3 });
  });

  it('reports healthy with no data', () => {
    expect(tracker.isHealthy('groq', 'llama-3.3-70b')).toBe(true);
  });

  it('reports healthy with all successes', () => {
    for (let i = 0; i < 5; i++) {
      tracker.record('groq', 'llama-3.3-70b', {
        timestamp: Date.now(),
        latencyMs: 200,
        status: 'success',
      });
    }
    expect(tracker.isHealthy('groq', 'llama-3.3-70b')).toBe(true);
  });

  it('marks unhealthy when error rate exceeds threshold', () => {
    for (let i = 0; i < 5; i++) {
      tracker.record('groq', 'llama-3.3-70b', {
        timestamp: Date.now(),
        latencyMs: 200,
        status: 'error',
      });
    }
    expect(tracker.isHealthy('groq', 'llama-3.3-70b')).toBe(false);
  });

  it('marks unhealthy when rate-limit rate exceeds threshold', () => {
    // 2 successes + 3 rate limits = 60% rate limit rate > 30% threshold
    for (let i = 0; i < 2; i++) {
      tracker.record('openrouter', 'model-a', {
        timestamp: Date.now(),
        latencyMs: 100,
        status: 'success',
      });
    }
    for (let i = 0; i < 3; i++) {
      tracker.record('openrouter', 'model-a', {
        timestamp: Date.now(),
        latencyMs: 50,
        status: 'rate_limit',
      });
    }
    expect(tracker.isHealthy('openrouter', 'model-a')).toBe(false);
  });

  it('assumes healthy with fewer than 3 records', () => {
    tracker.record('groq', 'llama-3.3-70b', {
      timestamp: Date.now(),
      latencyMs: 200,
      status: 'error',
    });
    tracker.record('groq', 'llama-3.3-70b', {
      timestamp: Date.now(),
      latencyMs: 200,
      status: 'error',
    });
    // Only 2 records — not enough data, should still be healthy
    expect(tracker.isHealthy('groq', 'llama-3.3-70b')).toBe(true);
  });

  it('computes avg and p95 latency', () => {
    const latencies = [100, 200, 300, 400, 500];
    for (const latencyMs of latencies) {
      tracker.record('groq', 'model-a', {
        timestamp: Date.now(),
        latencyMs,
        status: 'success',
      });
    }
    const snap = tracker.snapshot('groq', 'model-a');
    expect(snap.avgLatencyMs).toBe(300);
    expect(snap.p95LatencyMs).toBe(500);
    expect(snap.successes).toBe(5);
  });

  it('tracks different providers independently', () => {
    tracker.record('groq', 'model-a', {
      timestamp: Date.now(),
      latencyMs: 100,
      status: 'success',
    });
    tracker.record('openrouter', 'model-b', {
      timestamp: Date.now(),
      latencyMs: 500,
      status: 'error',
    });

    const snapA = tracker.snapshot('groq', 'model-a');
    const snapB = tracker.snapshot('openrouter', 'model-b');
    expect(snapA.successes).toBe(1);
    expect(snapB.errors).toBe(1);
  });

  it('returns all snapshots', () => {
    tracker.record('groq', 'model-a', { timestamp: Date.now(), latencyMs: 100, status: 'success' });
    tracker.record('together', 'model-b', {
      timestamp: Date.now(),
      latencyMs: 200,
      status: 'success',
    });

    const all = tracker.allSnapshots();
    expect(all).toHaveLength(2);
  });

  it('resets all data', () => {
    tracker.record('groq', 'model-a', { timestamp: Date.now(), latencyMs: 100, status: 'success' });
    tracker.reset();
    expect(tracker.allSnapshots()).toHaveLength(0);
  });
});
