import prisma from '../config/db.js';
import type { CreateRoleBody, UpdateRoleBody } from '../validators/role.validator.js';
import type { Pagination } from '../utils/pagination.js';

const withPermissions = { permissions: { include: { permission: true } } } as const;

export function createRole(data: CreateRoleBody) {
  return prisma.role.create({ data });
}

export function getRoles({ skip, take }: Pick<Pagination, 'skip' | 'take'>) {
  return prisma.role.findMany({ orderBy: { id: 'asc' }, skip, take, include: withPermissions });
}

export function countRoles() {
  return prisma.role.count();
}

export function getRoleById(id: number) {
  return prisma.role.findUnique({ where: { id }, include: withPermissions });
}

export function updateRole(id: number, data: UpdateRoleBody) {
  return prisma.role.update({ where: { id }, data });
}

export async function deleteRole(id: number) {
  await prisma.role.delete({ where: { id } });
}

// Used by requirePermission(...) — true only if roleName's role has this
// exact permission via role_permissions. Finer-grained than authorize(),
// which only checks the role's name.
export async function roleHasPermission(roleName: string, permissionName: string): Promise<boolean> {
  const count = await prisma.rolePermission.count({
    where: { role: { name: roleName }, permission: { name: permissionName } },
  });
  return count > 0;
}

export async function setRolePermissions(roleId: number, permissionIds: number[]) {
  await prisma.$transaction([
    prisma.rolePermission.deleteMany({ where: { roleId } }),
    prisma.rolePermission.createMany({
      data: permissionIds.map((permissionId) => ({ roleId, permissionId })),
      skipDuplicates: true,
    }),
  ]);
  return getRoleById(roleId);
}
