import { ForbiddenException } from '@nestjs/common';
import { RbacService } from './rbac.service';

describe('RbacService V2.7 adapter contract', () => {
  const makeService = () => {
    const prisma = {
      projectMember: {
        findUnique: jest.fn(),
      },
    };
    return { prisma, service: new RbacService(prisma as any) };
  };

  it('allows a system admin actor without querying project membership', async () => {
    const { prisma, service } = makeService();

    await expect(service.assertProjectRole({
      actorId: 'm-admin',
      projectId: 'project-1',
      allowedRoles: ['owner'],
      permissions: ['*'],
    })).resolves.toEqual({
      actorId: 'm-admin',
      projectId: 'project-1',
      role: 'owner',
      via: 'system',
    });

    expect(prisma.projectMember.findUnique).not.toHaveBeenCalled();
  });

  it('allows actors with an explicit global permission', async () => {
    const { service } = makeService();

    await expect(service.assertGlobalPermission({
      actorId: 'm-pm',
      permissions: ['management:view'],
      requiredPermissions: ['management:view'],
    })).resolves.toEqual({
      actorId: 'm-pm',
      via: 'permission',
    });
  });

  it('rejects actors without the required global permission', async () => {
    const { service } = makeService();

    await expect(service.assertGlobalPermission({
      actorId: 'm-dev',
      permissions: ['project:view'],
      requiredPermissions: ['governance:manage'],
    })).rejects.toBeInstanceOf(ForbiddenException);
  });

  it('allows project owners to perform admin-scoped actions', async () => {
    const { prisma, service } = makeService();
    prisma.projectMember.findUnique.mockResolvedValue({
      id: 'pm-1',
      projectId: 'project-1',
      userId: 'm-owner',
      role: 'owner',
    });

    await expect(service.assertProjectRole({
      actorId: 'm-owner',
      projectId: 'project-1',
      allowedRoles: ['admin'],
      permissions: [],
    })).resolves.toEqual({
      actorId: 'm-owner',
      projectId: 'project-1',
      role: 'owner',
      via: 'project_member',
    });
  });

  it('rejects actors below the required project role', async () => {
    const { prisma, service } = makeService();
    prisma.projectMember.findUnique.mockResolvedValue({
      id: 'pm-1',
      projectId: 'project-1',
      userId: 'm-viewer',
      role: 'viewer',
    });

    await expect(service.assertProjectRole({
      actorId: 'm-viewer',
      projectId: 'project-1',
      allowedRoles: ['member'],
      permissions: [],
    })).rejects.toBeInstanceOf(ForbiddenException);
  });
});
