import { describe, it, expect, beforeEach } from "vitest";
import {
  incMessages,
  incCost,
  recordLatency,
  incAlerts,
  formatMetrics,
  _resetMetrics,
} from "@/lib/token/metrics";

describe("Token Prometheus metrics", () => {
  beforeEach(() => {
    _resetMetrics();
  });

  /* ── incMessages ──────────────────────────────────────────────── */

  describe("incMessages", () => {
    it("increments counter for a model+intent pair", () => {
      incMessages("gemini-2.5-flash", "chat");
      incMessages("gemini-2.5-flash", "chat");
      incMessages("gemini-2.5-flash", "chat");

      const output = formatMetrics();
      expect(output).toContain('token_messages_total{model="gemini-2.5-flash",intent="chat"} 3');
    });

    it("tracks multiple models independently", () => {
      incMessages("gemini-2.5-flash", "chat");
      incMessages("claude-sonnet-4.6", "research");
      incMessages("claude-sonnet-4.6", "research");

      const output = formatMetrics();
      expect(output).toContain('token_messages_total{model="gemini-2.5-flash",intent="chat"} 1');
      expect(output).toContain('token_messages_total{model="claude-sonnet-4.6",intent="research"} 2');
    });

    it("tracks same model with different intents separately", () => {
      incMessages("gemini-2.5-flash", "chat");
      incMessages("gemini-2.5-flash", "research");

      const output = formatMetrics();
      expect(output).toContain('token_messages_total{model="gemini-2.5-flash",intent="chat"} 1');
      expect(output).toContain('token_messages_total{model="gemini-2.5-flash",intent="research"} 1');
    });
  });

  /* ── incCost ──────────────────────────────────────────────────── */

  describe("incCost", () => {
    it("accumulates cost per model", () => {
      incCost("gemini-2.5-flash", 0.01);
      incCost("gemini-2.5-flash", 0.0134);

      const output = formatMetrics();
      expect(output).toContain('token_cost_usd_total{model="gemini-2.5-flash"} 0.0234');
    });

    it("tracks multiple models independently", () => {
      incCost("gemini-2.5-flash", 0.05);
      incCost("deepseek-r1", 0.12);

      const output = formatMetrics();
      expect(output).toContain('token_cost_usd_total{model="gemini-2.5-flash"} 0.05');
      expect(output).toContain('token_cost_usd_total{model="deepseek-r1"} 0.12');
    });
  });

  /* ── recordLatency ────────────────────────────────────────────── */

  describe("recordLatency", () => {
    it("stores values and calculates percentiles", () => {
      // Add 100 values from 1 to 100 so percentiles are predictable
      for (let i = 1; i <= 100; i++) {
        recordLatency("gemini-2.5-flash", i);
      }

      const output = formatMetrics();
      expect(output).toContain('token_latency_ms{model="gemini-2.5-flash",quantile="0.5"} 50');
      expect(output).toContain('token_latency_ms{model="gemini-2.5-flash",quantile="0.95"} 95');
      expect(output).toContain('token_latency_ms{model="gemini-2.5-flash",quantile="0.99"} 99');
      expect(output).toContain('token_latency_ms_count{model="gemini-2.5-flash"} 100');
      expect(output).toContain('token_latency_ms_sum{model="gemini-2.5-flash"} 5050');
    });

    it("handles a single sample", () => {
      recordLatency("deepseek-r1", 450);

      const output = formatMetrics();
      expect(output).toContain('token_latency_ms{model="deepseek-r1",quantile="0.5"} 450');
      expect(output).toContain('token_latency_ms{model="deepseek-r1",quantile="0.95"} 450');
      expect(output).toContain('token_latency_ms{model="deepseek-r1",quantile="0.99"} 450');
      expect(output).toContain('token_latency_ms_count{model="deepseek-r1"} 1');
      expect(output).toContain('token_latency_ms_sum{model="deepseek-r1"} 450');
    });

    it("tracks multiple models independently", () => {
      recordLatency("model-a", 100);
      recordLatency("model-a", 200);
      recordLatency("model-b", 500);

      const output = formatMetrics();
      expect(output).toContain('token_latency_ms_count{model="model-a"} 2');
      expect(output).toContain('token_latency_ms_sum{model="model-a"} 300');
      expect(output).toContain('token_latency_ms_count{model="model-b"} 1');
      expect(output).toContain('token_latency_ms_sum{model="model-b"} 500');
    });
  });

  /* ── incAlerts ────────────────────────────────────────────────── */

  describe("incAlerts", () => {
    it("counts by severity", () => {
      incAlerts("critical");
      incAlerts("critical");
      incAlerts("critical");
      incAlerts("warning");

      const output = formatMetrics();
      expect(output).toContain('token_alerts_total{severity="critical"} 3');
      expect(output).toContain('token_alerts_total{severity="warning"} 1');
    });

    it("handles info severity", () => {
      incAlerts("info");
      incAlerts("info");

      const output = formatMetrics();
      expect(output).toContain('token_alerts_total{severity="info"} 2');
    });
  });

  /* ── formatMetrics ────────────────────────────────────────────── */

  describe("formatMetrics", () => {
    it("produces valid Prometheus text with HELP and TYPE lines", () => {
      incMessages("gemini-2.5-flash", "chat");
      incCost("gemini-2.5-flash", 0.0234);
      recordLatency("gemini-2.5-flash", 450);
      incAlerts("warning");

      const output = formatMetrics();

      // Check HELP lines
      expect(output).toContain("# HELP token_messages_total Total Token messages processed");
      expect(output).toContain("# HELP token_cost_usd_total Total Token cost in USD");
      expect(output).toContain("# HELP token_latency_ms Token response latency in milliseconds");
      expect(output).toContain("# HELP token_alerts_total Total Token alerts fired");

      // Check TYPE lines
      expect(output).toContain("# TYPE token_messages_total counter");
      expect(output).toContain("# TYPE token_cost_usd_total counter");
      expect(output).toContain("# TYPE token_latency_ms summary");
      expect(output).toContain("# TYPE token_alerts_total counter");
    });

    it("returns empty string when no data has been recorded", () => {
      const output = formatMetrics();
      expect(output).toBe("");
    });

    it("only includes metric families that have data", () => {
      incMessages("gemini-2.5-flash", "chat");

      const output = formatMetrics();
      expect(output).toContain("token_messages_total");
      expect(output).not.toContain("token_cost_usd_total");
      expect(output).not.toContain("token_latency_ms");
      expect(output).not.toContain("token_alerts_total");
    });

    it("escapes special characters in label values", () => {
      incMessages('model-with"quotes', "chat");
      incMessages("model-with\\backslash", "chat");

      const output = formatMetrics();
      expect(output).toContain('model="model-with\\"quotes"');
      expect(output).toContain('model="model-with\\\\backslash"');
    });
  });

  /* ── _resetMetrics ────────────────────────────────────────────── */

  describe("_resetMetrics", () => {
    it("clears all counters", () => {
      incMessages("gemini-2.5-flash", "chat");
      incCost("gemini-2.5-flash", 1.0);
      recordLatency("gemini-2.5-flash", 500);
      incAlerts("critical");

      // Verify data exists
      expect(formatMetrics()).not.toBe("");

      // Reset
      _resetMetrics();

      // Verify empty
      expect(formatMetrics()).toBe("");
    });
  });
});
