import { describe, expect, it } from 'vitest';

import {
  aggregateMetrics,
  calculateScenarioMetrics,
} from '../../scripts/comms/replay.mjs';
import { evaluateReport } from '../../scripts/comms/compare.mjs';

function buildPassingScenarioMetrics() {
  return {
    duplicate_event_rate: 0,
    event_fanout_ratio: 1,
    history_inflight_max: 1,
    history_load_qps: 0.3,
    rpc_p50_ms: 100,
    rpc_p95_ms: 150,
    rpc_timeout_rate: 0,
    gateway_reconnect_count: 0,
    message_loss_count: 0,
    message_order_violation_count: 0,
  };
}

describe('comms scripts', () => {
  it('computes scenario metrics with dedupe and inflight tracking', () => {
    const metrics = calculateScenarioMetrics([
      { ts: 0, type: 'gateway_event', runId: 'r1', sessionKey: 's1', seq: 1, state: 'started', fanout: 1 },
      { ts: 0.2, type: 'gateway_event', runId: 'r1', sessionKey: 's1', seq: 1, state: 'started', fanout: 1 },
      { ts: 0.5, type: 'history_load', sessionKey: 's1', action: 'start' },
      { ts: 0.7, type: 'history_load', sessionKey: 's1', action: 'end' },
      { ts: 1.0, type: 'rpc', latencyMs: 120, timeout: false },
      { ts: 1.5, type: 'message', lost: false, orderViolation: false },
    ]);

    expect(metrics.duplicate_event_rate).toBeCloseTo(0.5, 6);
    expect(metrics.history_inflight_max).toBe(1);
    expect(metrics.rpc_p95_ms).toBe(120);
  });

  it('aggregates multiple scenario metrics deterministically', () => {
    const aggregate = aggregateMetrics([
      { ...buildPassingScenarioMetrics(), rpc_p95_ms: 200 },
      { ...buildPassingScenarioMetrics(), rpc_p95_ms: 400 },
    ]);
    expect(aggregate.rpc_p95_ms).toBe(300);
    expect(aggregate.history_inflight_max).toBe(1);
  });

  it('fails report evaluation when required scenarios are missing', () => {
    const passing = buildPassingScenarioMetrics();
    const current = {
      aggregate: passing,
      scenarios: {
        'happy-path-chat': passing,
      },
    };
    const baseline = { aggregate: passing };
    const result = evaluateReport(current, baseline);

    expect(result.failures.some((f) => f.includes('missing scenario'))).toBe(true);
  });
});