/* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-explicit-any */
/**
 * Unit tests for lib/metrics.ts
 *
 * Tests the lightweight in-memory metrics system including:
 * - Counter class: increment, label tracking, Prometheus format
 * - Histogram class: observe, percentiles, ring buffer, Prometheus format
 * - recordRequest: counter increments, duration observation, error tracking
 * - recordLogEntry: level-based counting
 * - requestStarted/requestEnded: active request gauge
 * - getDashboardMetrics: structured dashboard data
 * - getPrometheusMetrics: Prometheus text export
 *
 * Uses jest.isolateModules() to get fresh singleton state per describe block.
 */

// ---------------------------------------------------------------------------
// 1. Counter — inc increments correctly, multiple labels tracked separately
// ---------------------------------------------------------------------------
describe("Counter", () => {
  // Counter is not exported directly — test it through exported counter instances.

  test("inc increments value for a single label set", () => {
    jest.isolateModules(() => {
      const { logEntriesTotal } = require("@/lib/metrics");
      logEntriesTotal.inc({ level: "info" });
      logEntriesTotal.inc({ level: "info" });
      logEntriesTotal.inc({ level: "info" });

      const entries = logEntriesTotal.getEntries();
      expect(entries).toHaveLength(1);
      expect(entries[0]).toEqual({ labels: { level: "info" }, value: 3 });
    });
  });

  test("inc increments by custom value", () => {
    jest.isolateModules(() => {
      const { logEntriesTotal } = require("@/lib/metrics");
      logEntriesTotal.inc({ level: "warn" }, 5);

      const entries = logEntriesTotal.getEntries();
      expect(entries).toHaveLength(1);
      expect(entries[0]).toEqual({ labels: { level: "warn" }, value: 5 });
    });
  });

  test("multiple label sets are tracked separately", () => {
    jest.isolateModules(() => {
      const { logEntriesTotal } = require("@/lib/metrics");
      logEntriesTotal.inc({ level: "info" });
      logEntriesTotal.inc({ level: "info" });
      logEntriesTotal.inc({ level: "error" });
      logEntriesTotal.inc({ level: "warn" }, 3);

      const entries = logEntriesTotal.getEntries();
      expect(entries).toHaveLength(3);

      const info = entries.find((e: any) => e.labels.level === "info");
      const error = entries.find((e: any) => e.labels.level === "error");
      const warn = entries.find((e: any) => e.labels.level === "warn");

      expect(info?.value).toBe(2);
      expect(error?.value).toBe(1);
      expect(warn?.value).toBe(3);
    });
  });

  test("getEntries returns a copy, not internal array", () => {
    jest.isolateModules(() => {
      const { logEntriesTotal } = require("@/lib/metrics");
      logEntriesTotal.inc({ level: "info" });

      const entries1 = logEntriesTotal.getEntries();
      const entries2 = logEntriesTotal.getEntries();
      expect(entries1).not.toBe(entries2);
      expect(entries1).toEqual(entries2);
    });
  });
});

// ---------------------------------------------------------------------------
// 2. Counter — toPrometheus format is correct
// ---------------------------------------------------------------------------
describe("Counter toPrometheus", () => {
  test("produces correct Prometheus text format", () => {
    jest.isolateModules(() => {
      const { logEntriesTotal } = require("@/lib/metrics");
      logEntriesTotal.inc({ level: "info" }, 42);
      logEntriesTotal.inc({ level: "error" }, 7);

      const output = logEntriesTotal.toPrometheus();
      const lines = output.split("\n");

      expect(lines[0]).toBe(
        "# HELP log_entries_total Total log entries by level",
      );
      expect(lines[1]).toBe("# TYPE log_entries_total counter");
      expect(lines[2]).toBe('log_entries_total{level="info"} 42');
      expect(lines[3]).toBe('log_entries_total{level="error"} 7');
    });
  });

  test("handles multiple label keys", () => {
    jest.isolateModules(() => {
      const { httpRequestsTotal } = require("@/lib/metrics");
      httpRequestsTotal.inc(
        { method: "GET", category: "api:health", status: "2xx" },
        10,
      );

      const output = httpRequestsTotal.toPrometheus();
      expect(output).toContain('method="GET"');
      expect(output).toContain('category="api:health"');
      expect(output).toContain('status="2xx"');
      expect(output).toContain("} 10");
    });
  });

  test("empty counter still produces HELP and TYPE lines", () => {
    jest.isolateModules(() => {
      const { logEntriesTotal } = require("@/lib/metrics");
      const output = logEntriesTotal.toPrometheus();
      const lines = output.split("\n");

      expect(lines).toHaveLength(2);
      expect(lines[0]).toMatch(/^# HELP/);
      expect(lines[1]).toMatch(/^# TYPE/);
    });
  });
});

// ---------------------------------------------------------------------------
// 3. Histogram — observe stores values, getPercentiles returns correct stats
// ---------------------------------------------------------------------------
describe("Histogram observe and getPercentiles", () => {
  test("stores values and computes percentiles correctly", () => {
    jest.isolateModules(() => {
      const { httpRequestDuration } = require("@/lib/metrics");

      // Insert 100 values: 1, 2, 3, ..., 100
      for (let i = 1; i <= 100; i++) {
        httpRequestDuration.observe({ category: "api:health" }, i);
      }

      const result = httpRequestDuration.getPercentiles({
        category: "api:health",
      });
      expect(result).not.toBeNull();
      expect(result!.count).toBe(100);
      expect(result!.avg).toBe(51); // Math.round(5050 / 100)

      // p50 = sorted[50] = 51 (0-indexed: floor(100*0.5) = 50 -> value at index 50 is 51)
      expect(result!.p50).toBe(51);
      // p95 = sorted[95] = 96
      expect(result!.p95).toBe(96);
      // p99 = sorted[99] = 100
      expect(result!.p99).toBe(100);
    });
  });

  test("single observation returns correct values", () => {
    jest.isolateModules(() => {
      const { httpRequestDuration } = require("@/lib/metrics");
      httpRequestDuration.observe({ category: "api:auth" }, 150);

      const result = httpRequestDuration.getPercentiles({
        category: "api:auth",
      });
      expect(result).not.toBeNull();
      expect(result!.count).toBe(1);
      expect(result!.avg).toBe(150);
      expect(result!.p50).toBe(150);
      expect(result!.p95).toBe(150);
      expect(result!.p99).toBe(150);
    });
  });

  test("different label sets are tracked independently", () => {
    jest.isolateModules(() => {
      const { httpRequestDuration } = require("@/lib/metrics");
      httpRequestDuration.observe({ category: "api:auth" }, 100);
      httpRequestDuration.observe({ category: "api:auth" }, 200);
      httpRequestDuration.observe({ category: "api:health" }, 10);

      const authResult = httpRequestDuration.getPercentiles({
        category: "api:auth",
      });
      const healthResult = httpRequestDuration.getPercentiles({
        category: "api:health",
      });

      expect(authResult!.count).toBe(2);
      expect(authResult!.avg).toBe(150);
      expect(healthResult!.count).toBe(1);
      expect(healthResult!.avg).toBe(10);
    });
  });
});

// ---------------------------------------------------------------------------
// 4. Histogram — ring buffer drops oldest samples when full
// ---------------------------------------------------------------------------
describe("Histogram ring buffer", () => {
  test("drops oldest samples when maxSamples exceeded", () => {
    jest.isolateModules(() => {
      const { httpRequestDuration } = require("@/lib/metrics");

      // Default maxSamples is 10000
      // Fill beyond capacity
      const maxSamples = 10000;
      for (let i = 1; i <= maxSamples + 500; i++) {
        httpRequestDuration.observe({ category: "api:public" }, i);
      }

      const result = httpRequestDuration.getPercentiles({
        category: "api:public",
      });
      expect(result).not.toBeNull();
      // Should have exactly maxSamples entries (oldest 500 dropped)
      expect(result!.count).toBe(maxSamples);

      // The oldest values (1-500) should be dropped.
      // Remaining values: 501 to 10500
      // Average: (501 + 10500) / 2 = 5500.5 -> sum = 5500.5 * 10000 = 55005000
      // Math.round(55005000 / 10000) = 5501
      expect(result!.avg).toBe(5501);
    });
  });
});

// ---------------------------------------------------------------------------
// 5. Histogram — getPercentiles returns null for empty bucket
// ---------------------------------------------------------------------------
describe("Histogram getPercentiles empty", () => {
  test("returns null for non-existent label set", () => {
    jest.isolateModules(() => {
      const { httpRequestDuration } = require("@/lib/metrics");
      const result = httpRequestDuration.getPercentiles({
        category: "nonexistent",
      });
      expect(result).toBeNull();
    });
  });
});

// ---------------------------------------------------------------------------
// 6. recordRequest — increments httpRequestsTotal with correct labels
// ---------------------------------------------------------------------------
describe("recordRequest", () => {
  test("increments httpRequestsTotal with method, category, and status group", () => {
    jest.isolateModules(() => {
      const { recordRequest, httpRequestsTotal } = require("@/lib/metrics");

      recordRequest({
        method: "GET",
        category: "api:health",
        statusCode: 200,
        durationMs: 50,
      });

      const entries = httpRequestsTotal.getEntries();
      expect(entries).toHaveLength(1);
      expect(entries[0]).toEqual({
        labels: { method: "GET", category: "api:health", status: "2xx" },
        value: 1,
      });
    });
  });

  test("groups status codes correctly (1xx, 2xx, 3xx, 4xx, 5xx)", () => {
    jest.isolateModules(() => {
      const { recordRequest, httpRequestsTotal } = require("@/lib/metrics");

      recordRequest({
        method: "GET",
        category: "api:public",
        statusCode: 101,
        durationMs: 5,
      });
      recordRequest({
        method: "GET",
        category: "api:public",
        statusCode: 200,
        durationMs: 10,
      });
      recordRequest({
        method: "GET",
        category: "api:public",
        statusCode: 301,
        durationMs: 15,
      });
      recordRequest({
        method: "POST",
        category: "api:auth",
        statusCode: 400,
        durationMs: 20,
      });
      recordRequest({
        method: "GET",
        category: "api:auth",
        statusCode: 500,
        durationMs: 25,
      });

      const entries = httpRequestsTotal.getEntries();
      const statuses = entries.map((e: any) => e.labels.status);
      expect(statuses).toContain("1xx");
      expect(statuses).toContain("2xx");
      expect(statuses).toContain("3xx");
      expect(statuses).toContain("4xx");
      expect(statuses).toContain("5xx");
    });
  });

  // ---------------------------------------------------------------------------
  // 7. recordRequest — observes httpRequestDuration with category and durationMs
  // ---------------------------------------------------------------------------
  test("observes httpRequestDuration with category and durationMs", () => {
    jest.isolateModules(() => {
      const { recordRequest, httpRequestDuration } = require("@/lib/metrics");

      recordRequest({
        method: "POST",
        category: "api:billing",
        statusCode: 200,
        durationMs: 123,
      });

      const result = httpRequestDuration.getPercentiles({
        category: "api:billing",
      });
      expect(result).not.toBeNull();
      expect(result!.count).toBe(1);
      expect(result!.avg).toBe(123);
    });
  });

  // ---------------------------------------------------------------------------
  // 8. recordRequest — increments httpErrorsTotal for 4xx and 5xx status codes
  // ---------------------------------------------------------------------------
  test("increments httpErrorsTotal for 4xx status codes", () => {
    jest.isolateModules(() => {
      const { recordRequest, httpErrorsTotal } = require("@/lib/metrics");

      recordRequest({
        method: "POST",
        category: "api:auth",
        statusCode: 401,
        durationMs: 10,
      });
      recordRequest({
        method: "GET",
        category: "api:public",
        statusCode: 404,
        durationMs: 5,
      });

      const entries = httpErrorsTotal.getEntries();
      expect(entries).toHaveLength(2);

      const authError = entries.find(
        (e: any) => e.labels.category === "api:auth",
      );
      expect(authError).toEqual({
        labels: { category: "api:auth", status: "4xx" },
        value: 1,
      });
    });
  });

  test("increments httpErrorsTotal for 5xx status codes", () => {
    jest.isolateModules(() => {
      const { recordRequest, httpErrorsTotal } = require("@/lib/metrics");

      recordRequest({
        method: "GET",
        category: "api:dashboard",
        statusCode: 500,
        durationMs: 250,
      });
      recordRequest({
        method: "GET",
        category: "api:dashboard",
        statusCode: 503,
        durationMs: 300,
      });

      const entries = httpErrorsTotal.getEntries();
      expect(entries).toHaveLength(1);
      expect(entries[0]).toEqual({
        labels: { category: "api:dashboard", status: "5xx" },
        value: 2,
      });
    });
  });

  // ---------------------------------------------------------------------------
  // 9. recordRequest — does NOT increment errors for 2xx/3xx
  // ---------------------------------------------------------------------------
  test("does NOT increment httpErrorsTotal for 2xx status codes", () => {
    jest.isolateModules(() => {
      const { recordRequest, httpErrorsTotal } = require("@/lib/metrics");

      recordRequest({
        method: "GET",
        category: "api:public",
        statusCode: 200,
        durationMs: 10,
      });
      recordRequest({
        method: "POST",
        category: "api:auth",
        statusCode: 201,
        durationMs: 15,
      });

      expect(httpErrorsTotal.getEntries()).toHaveLength(0);
    });
  });

  test("does NOT increment httpErrorsTotal for 3xx status codes", () => {
    jest.isolateModules(() => {
      const { recordRequest, httpErrorsTotal } = require("@/lib/metrics");

      recordRequest({
        method: "GET",
        category: "page:public",
        statusCode: 301,
        durationMs: 5,
      });
      recordRequest({
        method: "GET",
        category: "page:public",
        statusCode: 304,
        durationMs: 3,
      });

      expect(httpErrorsTotal.getEntries()).toHaveLength(0);
    });
  });
});

// ---------------------------------------------------------------------------
// 10. recordLogEntry — increments logEntriesTotal with level label
// ---------------------------------------------------------------------------
describe("recordLogEntry", () => {
  test("increments logEntriesTotal with level label", () => {
    jest.isolateModules(() => {
      const { recordLogEntry, logEntriesTotal } = require("@/lib/metrics");

      recordLogEntry("info");
      recordLogEntry("info");
      recordLogEntry("error");
      recordLogEntry("warn");

      const entries = logEntriesTotal.getEntries();
      expect(entries).toHaveLength(3);

      const info = entries.find((e: any) => e.labels.level === "info");
      const error = entries.find((e: any) => e.labels.level === "error");
      const warn = entries.find((e: any) => e.labels.level === "warn");

      expect(info?.value).toBe(2);
      expect(error?.value).toBe(1);
      expect(warn?.value).toBe(1);
    });
  });
});

// ---------------------------------------------------------------------------
// 11. requestStarted/requestEnded — activeRequests tracking
// ---------------------------------------------------------------------------
describe("requestStarted / requestEnded", () => {
  test("activeRequests increments and decrements correctly", () => {
    jest.isolateModules(() => {
      const {
        requestStarted,
        requestEnded,
        getDashboardMetrics,
      } = require("@/lib/metrics");

      // Initially 0
      expect(getDashboardMetrics().activeRequests).toBe(0);

      requestStarted();
      requestStarted();
      requestStarted();
      expect(getDashboardMetrics().activeRequests).toBe(3);

      requestEnded();
      expect(getDashboardMetrics().activeRequests).toBe(2);

      requestEnded();
      requestEnded();
      expect(getDashboardMetrics().activeRequests).toBe(0);
    });
  });

  test("activeRequests never goes below 0", () => {
    jest.isolateModules(() => {
      const { requestEnded, getDashboardMetrics } = require("@/lib/metrics");

      // Call requestEnded without any requestStarted
      requestEnded();
      requestEnded();
      requestEnded();

      expect(getDashboardMetrics().activeRequests).toBe(0);
    });
  });

  test("mixed start/end sequences", () => {
    jest.isolateModules(() => {
      const {
        requestStarted,
        requestEnded,
        getDashboardMetrics,
      } = require("@/lib/metrics");

      requestStarted();
      requestStarted();
      requestEnded();
      requestStarted();
      // 2 - 1 + 1 = 2
      expect(getDashboardMetrics().activeRequests).toBe(2);

      requestEnded();
      requestEnded();
      requestEnded(); // Would go to -1 but clamped to 0
      expect(getDashboardMetrics().activeRequests).toBe(0);
    });
  });
});

// ---------------------------------------------------------------------------
// 12. getDashboardMetrics — returns correct structure
// ---------------------------------------------------------------------------
describe("getDashboardMetrics", () => {
  test("returns correct structure with all required fields", () => {
    jest.isolateModules(() => {
      const { getDashboardMetrics } = require("@/lib/metrics");
      const data = getDashboardMetrics();

      // uptime
      expect(data.uptime).toBeDefined();
      expect(typeof data.uptime.startedAt).toBe("string");
      expect(typeof data.uptime.uptimeSeconds).toBe("number");
      expect(data.uptime.uptimeSeconds).toBeGreaterThanOrEqual(0);

      // activeRequests
      expect(typeof data.activeRequests).toBe("number");
      expect(data.activeRequests).toBe(0);

      // requests
      expect(data.requests).toBeDefined();
      expect(Array.isArray(data.requests.total)).toBe(true);
      expect(typeof data.requests.errorRate).toBe("number");

      // responseTimes
      expect(Array.isArray(data.responseTimes)).toBe(true);

      // errors
      expect(Array.isArray(data.errors)).toBe(true);

      // logLevels
      expect(Array.isArray(data.logLevels)).toBe(true);
    });
  });

  test("startedAt is a valid ISO date string", () => {
    jest.isolateModules(() => {
      const { getDashboardMetrics } = require("@/lib/metrics");
      const data = getDashboardMetrics();
      const parsed = new Date(data.uptime.startedAt);
      expect(parsed.getTime()).not.toBeNaN();
    });
  });

  test("includes request entries after recording", () => {
    jest.isolateModules(() => {
      const { recordRequest, getDashboardMetrics } = require("@/lib/metrics");

      recordRequest({
        method: "GET",
        category: "api:health",
        statusCode: 200,
        durationMs: 10,
      });
      recordRequest({
        method: "POST",
        category: "api:auth",
        statusCode: 201,
        durationMs: 50,
      });

      const data = getDashboardMetrics();
      expect(data.requests.total).toHaveLength(2);
    });
  });

  test("includes response times per category", () => {
    jest.isolateModules(() => {
      const { recordRequest, getDashboardMetrics } = require("@/lib/metrics");

      recordRequest({
        method: "GET",
        category: "api:health",
        statusCode: 200,
        durationMs: 10,
      });
      recordRequest({
        method: "GET",
        category: "api:health",
        statusCode: 200,
        durationMs: 20,
      });
      recordRequest({
        method: "POST",
        category: "api:auth",
        statusCode: 200,
        durationMs: 100,
      });

      const data = getDashboardMetrics();
      expect(data.responseTimes.length).toBeGreaterThanOrEqual(2);

      const healthTimes = data.responseTimes.find(
        (rt: any) => rt.category === "api:health",
      );
      expect(healthTimes).toBeDefined();
      expect(healthTimes!.count).toBe(2);
      expect(healthTimes!.avg).toBe(15); // Math.round((10+20)/2)
    });
  });

  test("includes log levels after recording", () => {
    jest.isolateModules(() => {
      const { recordLogEntry, getDashboardMetrics } = require("@/lib/metrics");

      recordLogEntry("info");
      recordLogEntry("error");

      const data = getDashboardMetrics();
      expect(data.logLevels).toHaveLength(2);

      const infoEntry = data.logLevels.find(
        (e: any) => e.labels.level === "info",
      );
      expect(infoEntry?.value).toBe(1);
    });
  });

  // ---------------------------------------------------------------------------
  // 13. getDashboardMetrics — error rate calculation is correct
  // ---------------------------------------------------------------------------
  test("error rate is 0 when no requests recorded", () => {
    jest.isolateModules(() => {
      const { getDashboardMetrics } = require("@/lib/metrics");
      const data = getDashboardMetrics();
      expect(data.requests.errorRate).toBe(0);
    });
  });

  test("error rate is calculated correctly as percentage", () => {
    jest.isolateModules(() => {
      const { recordRequest, getDashboardMetrics } = require("@/lib/metrics");

      // 8 successful, 2 errors = 20% error rate
      for (let i = 0; i < 8; i++) {
        recordRequest({
          method: "GET",
          category: "api:public",
          statusCode: 200,
          durationMs: 10,
        });
      }
      recordRequest({
        method: "GET",
        category: "api:public",
        statusCode: 404,
        durationMs: 10,
      });
      recordRequest({
        method: "GET",
        category: "api:public",
        statusCode: 500,
        durationMs: 10,
      });

      const data = getDashboardMetrics();
      // totalRequests = 10 (8 x 2xx + 1 x 4xx + 1 x 5xx)
      // totalErrors = 2 (1 x 4xx + 1 x 5xx)
      // errorRate = 2/10 = 0.2 -> 20.00%
      // Math.round(0.2 * 10000) / 100 = 20
      expect(data.requests.errorRate).toBe(20);
    });
  });

  test("error rate handles 100% errors", () => {
    jest.isolateModules(() => {
      const { recordRequest, getDashboardMetrics } = require("@/lib/metrics");

      recordRequest({
        method: "GET",
        category: "api:auth",
        statusCode: 500,
        durationMs: 10,
      });
      recordRequest({
        method: "POST",
        category: "api:auth",
        statusCode: 400,
        durationMs: 10,
      });

      const data = getDashboardMetrics();
      expect(data.requests.errorRate).toBe(100);
    });
  });

  test("error rate handles fractional percentages with 2 decimal places", () => {
    jest.isolateModules(() => {
      const { recordRequest, getDashboardMetrics } = require("@/lib/metrics");

      // 1 error out of 3 requests = 33.33%
      recordRequest({
        method: "GET",
        category: "api:public",
        statusCode: 200,
        durationMs: 10,
      });
      recordRequest({
        method: "GET",
        category: "api:public",
        statusCode: 200,
        durationMs: 10,
      });
      recordRequest({
        method: "GET",
        category: "api:public",
        statusCode: 500,
        durationMs: 10,
      });

      const data = getDashboardMetrics();
      // 1/3 = 0.3333... * 10000 = 3333.33... -> Math.round = 3333 / 100 = 33.33
      expect(data.requests.errorRate).toBe(33.33);
    });
  });
});

// ---------------------------------------------------------------------------
// 14. getPrometheusMetrics — includes all metric sections in text format
// ---------------------------------------------------------------------------
describe("getPrometheusMetrics", () => {
  test("includes server uptime section", () => {
    jest.isolateModules(() => {
      const { getPrometheusMetrics } = require("@/lib/metrics");
      const output = getPrometheusMetrics();

      expect(output).toContain("# Server uptime");
      expect(output).toContain("process_start_time_seconds");
      expect(output).toContain("active_requests");
    });
  });

  test("includes all four metric sections", () => {
    jest.isolateModules(() => {
      const { getPrometheusMetrics } = require("@/lib/metrics");
      const output = getPrometheusMetrics();

      // httpRequestsTotal counter
      expect(output).toContain("# HELP http_requests_total");
      expect(output).toContain("# TYPE http_requests_total counter");

      // httpRequestDuration histogram
      expect(output).toContain("# HELP http_request_duration_ms");
      expect(output).toContain("# TYPE http_request_duration_ms histogram");

      // httpErrorsTotal counter
      expect(output).toContain("# HELP http_errors_total");
      expect(output).toContain("# TYPE http_errors_total counter");

      // logEntriesTotal counter
      expect(output).toContain("# HELP log_entries_total");
      expect(output).toContain("# TYPE log_entries_total counter");
    });
  });

  test("includes recorded data in Prometheus format", () => {
    jest.isolateModules(() => {
      const {
        getPrometheusMetrics,
        recordRequest,
        recordLogEntry,
      } = require("@/lib/metrics");

      recordRequest({
        method: "GET",
        category: "api:health",
        statusCode: 200,
        durationMs: 42,
      });
      recordRequest({
        method: "POST",
        category: "api:auth",
        statusCode: 401,
        durationMs: 15,
      });
      recordLogEntry("info");

      const output = getPrometheusMetrics();

      // Request counter entries
      expect(output).toContain(
        'http_requests_total{method="GET",category="api:health",status="2xx"} 1',
      );
      expect(output).toContain(
        'http_requests_total{method="POST",category="api:auth",status="4xx"} 1',
      );

      // Duration histogram entries
      expect(output).toContain(
        "http_request_duration_ms_count{category=api:health} 1",
      );
      expect(output).toContain(
        "http_request_duration_ms_sum{category=api:health} 42",
      );

      // Error counter
      expect(output).toContain(
        'http_errors_total{category="api:auth",status="4xx"} 1',
      );

      // Log entries
      expect(output).toContain('log_entries_total{level="info"} 1');
    });
  });

  test("active_requests reflects current state", () => {
    jest.isolateModules(() => {
      const { getPrometheusMetrics, requestStarted } = require("@/lib/metrics");

      requestStarted();
      requestStarted();

      const output = getPrometheusMetrics();
      expect(output).toContain("active_requests 2");
    });
  });

  test("process_start_time_seconds is a valid unix timestamp", () => {
    jest.isolateModules(() => {
      const { getPrometheusMetrics } = require("@/lib/metrics");
      const output = getPrometheusMetrics();

      const match = output.match(/process_start_time_seconds (\d+)/);
      expect(match).not.toBeNull();

      const timestamp = parseInt(match![1], 10);
      // Should be a reasonable timestamp (after 2024)
      expect(timestamp).toBeGreaterThan(1700000000);
      // Should be within a reasonable range of now
      expect(timestamp).toBeLessThanOrEqual(Math.floor(Date.now() / 1000));
    });
  });
});

// ---------------------------------------------------------------------------
// Histogram toPrometheus format
// ---------------------------------------------------------------------------
describe("Histogram toPrometheus", () => {
  test("produces correct Prometheus text format with _count, _sum, percentiles", () => {
    jest.isolateModules(() => {
      const { httpRequestDuration } = require("@/lib/metrics");

      httpRequestDuration.observe({ category: "api:health" }, 10);
      httpRequestDuration.observe({ category: "api:health" }, 20);
      httpRequestDuration.observe({ category: "api:health" }, 30);

      const output = httpRequestDuration.toPrometheus();
      const lines = output.split("\n");

      expect(lines[0]).toBe(
        "# HELP http_request_duration_ms HTTP request duration in milliseconds by category",
      );
      expect(lines[1]).toBe("# TYPE http_request_duration_ms histogram");

      // Check that we have count and sum
      expect(output).toContain(
        "http_request_duration_ms_count{category=api:health} 3",
      );
      expect(output).toContain(
        "http_request_duration_ms_sum{category=api:health} 60",
      );

      // Check percentile lines exist
      expect(output).toContain(
        "http_request_duration_ms_p50{category=api:health}",
      );
      expect(output).toContain(
        "http_request_duration_ms_p95{category=api:health}",
      );
      expect(output).toContain(
        "http_request_duration_ms_p99{category=api:health}",
      );
    });
  });

  test("empty histogram only produces HELP and TYPE lines", () => {
    jest.isolateModules(() => {
      const { httpRequestDuration } = require("@/lib/metrics");
      const output = httpRequestDuration.toPrometheus();
      const lines = output.split("\n");

      expect(lines).toHaveLength(2);
      expect(lines[0]).toMatch(/^# HELP/);
      expect(lines[1]).toMatch(/^# TYPE/);
    });
  });
});

// ---------------------------------------------------------------------------
// Histogram getAllBucketKeys
// ---------------------------------------------------------------------------
describe("Histogram getAllBucketKeys", () => {
  test("returns all observed label combinations", () => {
    jest.isolateModules(() => {
      const { httpRequestDuration } = require("@/lib/metrics");

      httpRequestDuration.observe({ category: "api:auth" }, 10);
      httpRequestDuration.observe({ category: "api:health" }, 20);
      httpRequestDuration.observe({ category: "api:auth" }, 30); // Same category

      const keys = httpRequestDuration.getAllBucketKeys();
      expect(keys).toHaveLength(2);
      expect(keys).toContain("category=api:auth");
      expect(keys).toContain("category=api:health");
    });
  });

  test("empty histogram returns empty keys", () => {
    jest.isolateModules(() => {
      const { httpRequestDuration } = require("@/lib/metrics");
      const keys = httpRequestDuration.getAllBucketKeys();
      expect(keys).toHaveLength(0);
    });
  });
});

// ---------------------------------------------------------------------------
// Edge cases
// ---------------------------------------------------------------------------
describe("Edge cases", () => {
  test("Counter labels are copied, not referenced", () => {
    jest.isolateModules(() => {
      const { logEntriesTotal } = require("@/lib/metrics");

      const labels = { level: "info" };
      logEntriesTotal.inc(labels);

      // Mutate the original object
      labels.level = "mutated";
      logEntriesTotal.inc(labels);

      const entries = logEntriesTotal.getEntries();
      // Should have 2 separate entries since the labels differ
      expect(entries).toHaveLength(2);
      expect(entries[0].labels.level).toBe("info");
      expect(entries[1].labels.level).toBe("mutated");
    });
  });

  test("Histogram label keys are sorted for consistent key generation", () => {
    jest.isolateModules(() => {
      const { httpRequestDuration } = require("@/lib/metrics");

      // Observe with labels in different order
      httpRequestDuration.observe({ category: "api:auth", method: "GET" }, 10);
      httpRequestDuration.observe({ method: "GET", category: "api:auth" }, 20);

      // Should be in the same bucket regardless of label order
      const result = httpRequestDuration.getPercentiles({
        category: "api:auth",
        method: "GET",
      });
      expect(result).not.toBeNull();
      expect(result!.count).toBe(2);
    });
  });

  test("recordRequest with edge status code 400 is counted as error", () => {
    jest.isolateModules(() => {
      const { recordRequest, httpErrorsTotal } = require("@/lib/metrics");

      recordRequest({
        method: "GET",
        category: "api:public",
        statusCode: 400,
        durationMs: 10,
      });
      expect(httpErrorsTotal.getEntries()).toHaveLength(1);
    });
  });

  test("recordRequest with status code 399 is NOT counted as error", () => {
    jest.isolateModules(() => {
      const { recordRequest, httpErrorsTotal } = require("@/lib/metrics");

      recordRequest({
        method: "GET",
        category: "api:public",
        statusCode: 399,
        durationMs: 10,
      });
      expect(httpErrorsTotal.getEntries()).toHaveLength(0);
    });
  });
});
