import { describe, expect, it, beforeEach, vi, afterEach } from 'vitest';
import {
  getCoverCachedPerMinute,
  getCoverPerfState,
  getCoverUiPerMinute,
  recordCoverProgress,
  recordCoverUiTotal,
  resetCoverPerfStateForTest,
} from './coverPerfStore';

beforeEach(() => {
  resetCoverPerfStateForTest();
});

afterEach(() => {
  vi.useRealTimers();
});

describe('coverPerfStore', () => {
  it('derives covers-per-minute from done deltas over the trailing window', () => {
    vi.useFakeTimers();
    vi.setSystemTime(1_000_000);
    recordCoverProgress({ done: 100, total: 1000, pending: 900 });
    vi.advanceTimersByTime(1_000);
    recordCoverProgress({ done: 110, total: 1000, pending: 890 });
    vi.advanceTimersByTime(1_000);
    recordCoverProgress({ done: 120, total: 1000, pending: 880 });
    // +20 covers over the last 2s ≈ 600 cpm (no minute-long inertia).
    expect(getCoverCachedPerMinute()).toBeCloseTo(600, 0);
    expect(getCoverPerfState().done).toBe(120);
  });

  it('returns 0 with a single sample and decays once the trailing window empties', () => {
    vi.useFakeTimers();
    vi.setSystemTime(2_000_000);
    recordCoverProgress({ done: 10 });
    expect(getCoverCachedPerMinute()).toBe(0);
    vi.advanceTimersByTime(1_000);
    recordCoverProgress({ done: 20 });
    expect(getCoverCachedPerMinute()).toBeGreaterThan(0);
    // No fresh samples for >5s → trailing window empties → back to 0.
    vi.advanceTimersByTime(6_000);
    expect(getCoverCachedPerMinute()).toBe(0);
  });

  it('resets the window on a backwards jump (server switch / cache clear)', () => {
    vi.useFakeTimers();
    vi.setSystemTime(3_000_000);
    recordCoverProgress({ done: 500 });
    vi.advanceTimersByTime(5_000);
    recordCoverProgress({ done: 5 });
    // Only the new baseline remains → no rate yet.
    expect(getCoverCachedPerMinute()).toBe(0);
    expect(getCoverPerfState().done).toBe(5);
  });

  it('derives UI covers-per-minute from backend total deltas over the trailing window', () => {
    vi.useFakeTimers();
    vi.setSystemTime(4_000_000);
    expect(getCoverUiPerMinute()).toBe(0);
    recordCoverUiTotal(100);
    // A single sample has no delta yet.
    expect(getCoverUiPerMinute()).toBe(0);
    vi.advanceTimersByTime(2_000);
    recordCoverUiTotal(130);
    // +30 produced over the last 2s ≈ 900 cpm; lib series stays untouched.
    expect(getCoverUiPerMinute()).toBeCloseTo(900, 0);
    expect(getCoverCachedPerMinute()).toBe(0);
    // Idle poll keeps reporting the same total → delta 0 → rate decays to 0.
    vi.advanceTimersByTime(6_000);
    recordCoverUiTotal(130);
    expect(getCoverUiPerMinute()).toBe(0);
  });

  it('resets the UI window on a backwards jump (process restart)', () => {
    vi.useFakeTimers();
    vi.setSystemTime(5_000_000);
    recordCoverUiTotal(500);
    vi.advanceTimersByTime(5_000);
    recordCoverUiTotal(3);
    expect(getCoverUiPerMinute()).toBe(0);
  });
});
