import type { Access, FieldAccess, PayloadRequest } from 'payload'

import type { User } from '@/payload-types'

export type Role = 'admin' | 'editor' | 'viewer'

const normalizeRoles = (roles: readonly Role[]) => new Set<Role>(roles)

export const hasRole = (user: User | null | undefined, roles: readonly Role[]) => {
  if (!user) return false
  const userRoles = user.roles?.length ? user.roles : (['viewer'] as Role[])
  const allowed = normalizeRoles(roles)
  return userRoles.some((role) => allowed.has(role as Role))
}

export const allowRoles =
  (roles: readonly Role[]): Access<User> =>
  ({ req: { user } }) =>
    hasRole(user, roles)

export const allowRolesAdmin =
  (roles: readonly Role[]) =>
  ({ req }: { req: PayloadRequest }) =>
    hasRole(req.user as User | null | undefined, roles)

export const allowRolesField =
  (roles: readonly Role[]): FieldAccess<User> =>
  ({ req: { user } }) =>
    hasRole(user, roles)

export const adminOnly = allowRoles(['admin'])
export const adminOrEditor = allowRoles(['admin', 'editor'])
export const anyRole = allowRoles(['admin', 'editor', 'viewer'])

export const adminOnlyAdmin = allowRolesAdmin(['admin'])
export const adminOrEditorAdmin = allowRolesAdmin(['admin', 'editor'])
export const anyRoleAdmin = allowRolesAdmin(['admin', 'editor', 'viewer'])

export const adminOnlyField = allowRolesField(['admin'])

export const readPublishedOrRoles: Access<User> = ({ req: { user } }) => {
  if (hasRole(user, ['admin', 'editor', 'viewer'])) return true
  return {
    _status: {
      equals: 'published',
    },
  }
}
