import { describe, expect, it } from "vitest";
import { ID_PREFIXES, newApiKeyValue, newId, newPublicToken } from "./id.util";

describe("newId", () => {
  it("uses correct prefix per entity kind", () => {
    for (const [kind, prefix] of Object.entries(ID_PREFIXES)) {
      const id = newId(kind as keyof typeof ID_PREFIXES);
      expect(id.startsWith(`${prefix}_`)).toBe(true);
    }
  });

  it("generates unique ids", () => {
    const ids = new Set(Array.from({ length: 1000 }, () => newId("merchant")));
    expect(ids.size).toBe(1000);
  });

  it("is time-ordered: older ids sort before newer ones lexicographically", async () => {
    const a = newId("paymentIntent");
    await new Promise((r) => setTimeout(r, 5));
    const b = newId("paymentIntent");
    expect(a < b).toBe(true);
  });

  it("emits Crockford base32 ULID body (26 lowercased chars after prefix)", () => {
    const id = newId("merchant");
    const body = id.slice("mer_".length);
    expect(body).toMatch(/^[0-9a-hjkmnp-tv-z]{26}$/);
  });
});

describe("newPublicToken", () => {
  it("is 43 chars URL-safe", () => {
    const token = newPublicToken();
    expect(token).toMatch(/^[0-9a-z]{43}$/);
  });
});

describe("newApiKeyValue", () => {
  it("builds sk_live_ prefix for secret/live", () => {
    const { full, prefix } = newApiKeyValue("secret", "live");
    expect(full.startsWith("sk_live_")).toBe(true);
    expect(prefix.startsWith("sk_live_")).toBe(true);
    expect(full.length).toBeGreaterThan(prefix.length);
  });

  it("builds pk_test_ prefix for publishable/test", () => {
    const { full, prefix } = newApiKeyValue("publishable", "test");
    expect(full.startsWith("pk_test_")).toBe(true);
    expect(prefix.startsWith("pk_test_")).toBe(true);
  });
});
