import { db } from "@/lib/db"
import { ACTIONS, type ActionType } from "@/lib/shared/constants/modules"
import type { Prisma } from "@prisma/client"

import { RoleWithPermissionsInput, PermissionInput } from "./schema"
import { Role, RoleWithPermissions } from "./types"

function normalizeActions(actions: string[]): ActionType[] {
  const allowed = new Set<string>(ACTIONS)
  return actions.filter((a): a is ActionType => allowed.has(a))
}

type PrismaRoleWithPermissions = Prisma.RoleGetPayload<{ include: { permissions: true } }>

function normalizeRoleWithPermissions(role: PrismaRoleWithPermissions): RoleWithPermissions {
  return {
    ...role,
    permissions: role.permissions.map((p) => ({
      ...p,
      actions: normalizeActions(p.actions),
    })),
  }
}

export async function getAllRoles(): Promise<RoleWithPermissions[]> {
  const roles = await db.role.findMany({
    orderBy: { name: "asc" },
    include: {
      permissions: true,
    },
  })
  return roles.map(normalizeRoleWithPermissions)
}

export async function getRoleById(id: string): Promise<RoleWithPermissions | null> {
  const role = await db.role.findUnique({
    where: { id },
    include: {
      permissions: true,
    },
  })
  return role ? normalizeRoleWithPermissions(role) : null
}

export async function createRole(data: RoleWithPermissionsInput): Promise<Role> {
  const { permissions, ...roleData } = data

  const role = await db.role.create({
    data: {
      name: roleData.name,
    },
  })

  if (permissions && permissions.length > 0) {
    await db.permission.createMany({
      data: permissions.map((p) => ({
        roleId: role.id,
        module: p.module,
        actions: p.actions,
      })),
    })
  }

  return role
}

export async function updateRole(id: string, data: Partial<RoleWithPermissionsInput>): Promise<Role> {
  const { permissions, ...roleData } = data

  const role = await db.role.update({
    where: { id },
    data: {
      name: roleData.name,
    },
  })

  if (permissions) {
    await db.permission.deleteMany({
      where: { roleId: id },
    })

    if (permissions.length > 0) {
      await db.permission.createMany({
        data: permissions.map((p) => ({
          roleId: id,
          module: p.module,
          actions: p.actions,
        })),
      })
    }
  }

  return role
}

export async function deleteRole(id: string): Promise<Role> {
  return db.role.delete({
    where: { id },
  })
}

export async function getPermissionsByRoleId(roleId: string) {
  return db.permission.findMany({
    where: { roleId },
  })
}

export async function setRolePermissions(roleId: string, permissions: PermissionInput[]) {
  await db.permission.deleteMany({
    where: { roleId },
  })

  if (permissions.length > 0) {
    await db.permission.createMany({
      data: permissions.map((p) => ({
        roleId,
        module: p.module,
        actions: p.actions,
      })),
    })
  }
}

export async function createPermission(data: PermissionInput) {
  return db.permission.create({
    data: {
      roleId: data.roleId,
      module: data.module,
      actions: data.actions,
    },
  })
}

