import { describe, expect, test } from "bun:test";
import { defineAuthz } from "../src/registry.ts";

describe("defineAuthz", () => {
  test("returns a frozen module", () => {
    const mod = defineAuthz({
      permissions: { "post:read": { title: "View posts" } },
      roles: { editor: ["post:*"] },
    });
    expect(Object.isFrozen(mod)).toBe(true);
    expect(mod.permissions!["post:read"]!.title).toBe("View posts");
    expect(mod.roles!.editor).toEqual(["post:*"]);
  });

  test("defaults missing sections to empty objects", () => {
    const mod = defineAuthz({});
    expect(mod.permissions).toEqual({});
    expect(mod.roles).toEqual({});
    expect(mod.policies).toEqual({});
    expect(mod.attributes).toEqual({});
    expect(mod.bindings).toEqual({});
  });

  test("rejects a permission id that is not colon-namespaced lowercase", () => {
    expect(() => defineAuthz({ permissions: { "Post Read": {} } })).toThrow(/permission id/i);
    expect(() => defineAuthz({ permissions: { "post:*": {} } })).toThrow(/wildcard/i);
  });

  test("rejects a role granting an unknown-shaped entry", () => {
    expect(() => defineAuthz({ roles: { editor: [""] } })).toThrow(/role 'editor'/i);
  });

  test("rejects a binding naming a policy that is not declared", () => {
    expect(() =>
      defineAuthz({
        permissions: { "post:write": {} },
        bindings: { "post:write": ["missingPolicy"] },
      }),
    ).toThrow(/missingPolicy/);
  });
});
