import { describe, expect, test } from "bun:test";
import {
  GRANTABLE_SYS_PERMISSIONS,
  isGrantableSysPermission,
  RESERVED_SYS_PERMISSIONS,
  resolveSysPermission,
  SYS_PERMISSION_GROUPS,
} from "./sys-permissions";

describe("sys permission vocabulary", () => {
  test("13 grantable permissions across 4 groups", () => {
    expect(GRANTABLE_SYS_PERMISSIONS).toHaveLength(13);
    expect(Object.keys(SYS_PERMISSION_GROUPS)).toEqual([
      "users",
      "orgs",
      "billing",
      "data",
    ]);
  });
  test("reserved permissions are never grantable", () => {
    for (const p of RESERVED_SYS_PERMISSIONS) {
      expect(isGrantableSysPermission(p)).toBe(false);
    }
    expect(isGrantableSysPermission("users:impersonate")).toBe(false);
    expect(isGrantableSysPermission("staff:manage")).toBe(false);
    expect(isGrantableSysPermission("users:ban")).toBe(true);
  });
});

describe("resolveSysPermission (gate matrix)", () => {
  const admin = {
    userId: "a",
    email: "a@x.co",
    kind: "admin-sys" as const,
    twoFactorEnabled: true,
  };
  const staff = { ...admin, kind: "staff-sys" as const };
  test("no operator → forbidden", () => {
    expect(resolveSysPermission(null, "users:read", new Set())).toBe(
      "forbidden",
    );
  });
  test("operator without 2FA → 2fa-required (admin AND staff)", () => {
    expect(
      resolveSysPermission(
        { ...admin, twoFactorEnabled: false },
        "users:read",
        new Set(),
      ),
    ).toBe("2fa-required");
    expect(
      resolveSysPermission(
        { ...staff, twoFactorEnabled: false },
        "users:read",
        new Set(["users:read"]),
      ),
    ).toBe("2fa-required");
  });
  test("admin-sys → ok for everything, even reserved", () => {
    expect(resolveSysPermission(admin, "staff:manage", new Set())).toBe("ok");
    expect(resolveSysPermission(admin, "users:impersonate", new Set())).toBe(
      "ok",
    );
  });
  test("staff-sys → ok only with the exact grant", () => {
    expect(
      resolveSysPermission(staff, "users:ban", new Set(["users:ban"])),
    ).toBe("ok");
    expect(
      resolveSysPermission(staff, "users:ban", new Set(["users:read"])),
    ).toBe("forbidden");
  });
  test("staff-sys never passes a reserved permission, even if a rogue row exists", () => {
    expect(
      resolveSysPermission(staff, "staff:manage", new Set(["staff:manage"])),
    ).toBe("forbidden");
    expect(
      resolveSysPermission(
        staff,
        "users:impersonate",
        new Set(["users:impersonate"]),
      ),
    ).toBe("forbidden");
  });
});
