import { describe, expect, it } from "vitest";
import { BOUNDED_JSON_LIMITS, BoundedJsonRecord } from "../schemas/bounded-json.schema.js";

describe("BoundedJsonRecord", () => {
  it("accepts simple key/value records", () => {
    const result = BoundedJsonRecord.safeParse({ a: "b", c: 1, d: true, e: null });
    expect(result.success).toBe(true);
  });

  it("accepts nested objects and arrays within limits", () => {
    const result = BoundedJsonRecord.safeParse({
      nested: { a: 1, b: [1, 2, 3] },
      arr: ["x", "y"],
    });
    expect(result.success).toBe(true);
  });

  it("rejects keys longer than MAX_KEY_LENGTH", () => {
    const tooLongKey = "k".repeat(BOUNDED_JSON_LIMITS.MAX_KEY_LENGTH + 1);
    const result = BoundedJsonRecord.safeParse({ [tooLongKey]: "v" });
    expect(result.success).toBe(false);
  });

  it("rejects records with more than MAX_KEYS top-level keys", () => {
    const tooMany: Record<string, string> = {};
    for (let i = 0; i <= BOUNDED_JSON_LIMITS.MAX_KEYS; i++) tooMany[`k${i}`] = "v";
    const result = BoundedJsonRecord.safeParse(tooMany);
    expect(result.success).toBe(false);
  });

  it("rejects nested objects deeper than MAX_DEPTH", () => {
    let nested: unknown = "leaf";
    for (let i = 0; i <= BOUNDED_JSON_LIMITS.MAX_DEPTH + 1; i++) {
      nested = { inner: nested };
    }
    const result = BoundedJsonRecord.safeParse({ a: nested });
    expect(result.success).toBe(false);
  });

  it("rejects strings longer than MAX_STRING_LENGTH", () => {
    const tooLong = "x".repeat(BOUNDED_JSON_LIMITS.MAX_STRING_LENGTH + 1);
    const result = BoundedJsonRecord.safeParse({ a: tooLong });
    expect(result.success).toBe(false);
  });

  it("rejects payloads exceeding MAX_SERIALIZED_BYTES", () => {
    // Fill with many short string values whose total JSON size exceeds the cap.
    const big: Record<string, string> = {};
    const chunk = "y".repeat(1024);
    for (let i = 0; i < 40; i++) big[`k${i}`] = chunk;
    const result = BoundedJsonRecord.safeParse(big);
    expect(result.success).toBe(false);
  });
});
