import { describe, expect, test } from "bun:test";

import {
  analyzeIncidentSequence,
  buildHourlyTrend,
  calculateAvailability,
  calculateCurrentStreak,
  calculatePercentile,
  type MetricCheckpoint,
} from "../../src/server/metrics";

describe("后端指标计算", () => {
  test("可用率无数据返回 0，并保留两位精度", () => {
    expect(calculateAvailability(0, 0)).toBe(0);
    expect(calculateAvailability(2, 3)).toBe(66.67);
  });

  test("百分位按 ceil(count * N / 100) - 1 取值", () => {
    const durations = Array.from({ length: 100 }, (_, index) => index + 1);

    expect(calculatePercentile([], 95)).toBeNull();
    expect(calculatePercentile([40, 10, 30, 20], 95)).toBe(40);
    expect(calculatePercentile(durations, 95)).toBe(95);
    expect(calculatePercentile(durations, 99)).toBe(99);
  });

  test("无检查数据时故障分析返回空口径", () => {
    const result = analyzeIncidentSequence([], "2025-01-01T00:00:00.000Z", "2025-01-01T01:00:00.000Z");

    expect(result).toEqual({ incidentCount: 0, longestOutage: null, mttr: null });
    expect(calculateCurrentStreak([])).toBeNull();
  });

  test("窗口起始即故障计入 incident 和最长故障，但不计入 MTTR", () => {
    const result = analyzeIncidentSequence(
      [
        checkpoint("2025-01-01T00:05:00.000Z", false),
        checkpoint("2025-01-01T00:10:00.000Z", false),
        checkpoint("2025-01-01T00:20:00.000Z", true),
      ],
      "2025-01-01T00:00:00.000Z",
      "2025-01-01T01:00:00.000Z",
    );

    expect(result.incidentCount).toBe(1);
    expect(result.longestOutage).toBe(20 * 60 * 1000);
    expect(result.mttr).toBeNull();
  });

  test("未恢复故障计算到窗口结束且不计入 MTTR", () => {
    const result = analyzeIncidentSequence(
      [checkpoint("2025-01-01T00:05:00.000Z", true), checkpoint("2025-01-01T00:20:00.000Z", false)],
      "2025-01-01T00:00:00.000Z",
      "2025-01-01T01:00:00.000Z",
    );

    expect(result.incidentCount).toBe(1);
    expect(result.longestOutage).toBe(40 * 60 * 1000);
    expect(result.mttr).toBeNull();
  });

  test("连续异常只计一次 incident，恢复后纳入 MTTR", () => {
    const result = analyzeIncidentSequence(
      [
        checkpoint("2025-01-01T00:00:00.000Z", true),
        checkpoint("2025-01-01T00:05:00.000Z", false),
        checkpoint("2025-01-01T00:10:00.000Z", false),
        checkpoint("2025-01-01T00:20:00.000Z", true),
      ],
      "2025-01-01T00:00:00.000Z",
      "2025-01-01T01:00:00.000Z",
    );

    expect(result.incidentCount).toBe(1);
    expect(result.longestOutage).toBe(15 * 60 * 1000);
    expect(result.mttr).toBe(15 * 60 * 1000);
  });

  test("连续状态支持 capped 标记", () => {
    expect(
      calculateCurrentStreak(
        [
          checkpoint("2025-01-01T00:00:00.000Z", true),
          checkpoint("2025-01-01T00:01:00.000Z", false),
          checkpoint("2025-01-01T00:02:00.000Z", false),
        ],
        2,
      ),
    ).toEqual({ capped: true, count: 2, up: false });
  });

  test("UTC 小时趋势分桶返回 up/down 和延迟范围", () => {
    const trend = buildHourlyTrend([
      checkpoint("2025-01-01T00:10:00.000Z", true, 100),
      checkpoint("2025-01-01T00:40:00.000Z", false, null),
      checkpoint("2025-01-01T01:05:00.000Z", true, 300),
    ]);

    expect(trend).toEqual([
      {
        availability: 50,
        avgDurationMs: 100,
        bucketStart: "2025-01-01T00:00:00.000Z",
        downChecks: 1,
        maxDurationMs: 100,
        minDurationMs: 100,
        totalChecks: 2,
        upChecks: 1,
      },
      {
        availability: 100,
        avgDurationMs: 300,
        bucketStart: "2025-01-01T01:00:00.000Z",
        downChecks: 0,
        maxDurationMs: 300,
        minDurationMs: 300,
        totalChecks: 1,
        upChecks: 1,
      },
    ]);
  });
});

function checkpoint(timestamp: string, matched: boolean, durationMs: null | number = null): MetricCheckpoint {
  return { durationMs, matched, timestamp };
}
