import { describe, it, expect, beforeEach, afterAll } from "vitest";
import { DEFAULT_ORG_ID, prisma, resetDb } from "./helpers.js";
import { canTriggerRole } from "../../src/permission.js";

describe("canTriggerRole (integration, per-role gate)", () => {
  beforeEach(async () => {
    await resetDb();
  });

  afterAll(async () => {
    await prisma.$disconnect();
  });

  it("allows when role is unconfigured on the project (back-compat: open)", async () => {
    const project = await prisma.project.create({
      data: { id: "p-role-1", organizationId: DEFAULT_ORG_ID, name: "T", workspaceDir: "/tmp/x" },
    });
    const r = await canTriggerRole(prisma, project.id, "draft", "ou_a");
    expect(r.allowed).toBe(true);
  });

  it("allows when principal holds an active grant for the role", async () => {
    const project = await prisma.project.create({
      data: { id: "p-role-2", organizationId: DEFAULT_ORG_ID, name: "T", workspaceDir: "/tmp/x" },
    });
    await prisma.roleTriggerGrant.create({
      data: { projectId: project.id, roleId: "review", principalType: "USER", principalId: "ou_a" },
    });
    const r = await canTriggerRole(prisma, project.id, "review", "ou_a");
    expect(r.allowed).toBe(true);
  });

  it("denies when grants exist for the role but principal has none", async () => {
    const project = await prisma.project.create({
      data: { id: "p-role-3", organizationId: DEFAULT_ORG_ID, name: "T", workspaceDir: "/tmp/x" },
    });
    // Someone else has the role; ou_b does not.
    await prisma.roleTriggerGrant.create({
      data: { projectId: project.id, roleId: "review", principalType: "USER", principalId: "ou_a" },
    });
    const r = await canTriggerRole(prisma, project.id, "review", "ou_b");
    expect(r.allowed).toBe(false);
  });

  it("denies when the principal's grant was revoked", async () => {
    const project = await prisma.project.create({
      data: { id: "p-role-4", organizationId: DEFAULT_ORG_ID, name: "T", workspaceDir: "/tmp/x" },
    });
    await prisma.roleTriggerGrant.create({
      data: { projectId: project.id, roleId: "review", principalType: "USER", principalId: "ou_a", revokedAt: new Date() },
    });
    const r = await canTriggerRole(prisma, project.id, "review", "ou_a");
    expect(r.allowed).toBe(false);
  });

  it("scopes grants per-project (grant on p1 does not allow on p2)", async () => {
    const p1 = await prisma.project.create({ data: { id: "p-role-5a", organizationId: DEFAULT_ORG_ID, name: "T", workspaceDir: "/tmp/x" } });
    const p2 = await prisma.project.create({ data: { id: "p-role-5b", organizationId: DEFAULT_ORG_ID, name: "T", workspaceDir: "/tmp/x" } });
    await prisma.roleTriggerGrant.create({
      data: { projectId: p1.id, roleId: "review", principalType: "USER", principalId: "ou_a" },
    });
    // p2 has the role configured for someone else; ou_a has no grant there.
    await prisma.roleTriggerGrant.create({
      data: { projectId: p2.id, roleId: "review", principalType: "USER", principalId: "ou_other" },
    });
    const onP1 = await canTriggerRole(prisma, p1.id, "review", "ou_a");
    expect(onP1.allowed).toBe(true);
    const onP2 = await canTriggerRole(prisma, p2.id, "review", "ou_a");
    expect(onP2.allowed).toBe(false);
  });

  it("denies an otherwise open role when the organization is suspended", async () => {
    const project = await prisma.project.create({
      data: { id: "p-role-suspended", organizationId: DEFAULT_ORG_ID, name: "T", workspaceDir: "/tmp/x" },
    });
    await prisma.organization.update({ where: { id: DEFAULT_ORG_ID }, data: { status: "SUSPENDED" } });

    const result = await canTriggerRole(prisma, project.id, "draft", "ou_a");

    expect(result.allowed).toBe(false);
    expect(result.reason).toContain(`organization ${DEFAULT_ORG_ID} is SUSPENDED`);
  });
});
