import { describe, it, expect } from 'vitest'
import { StaffRole } from '@prisma/client'

import {
  hasPermission,
  hasAllPermissions,
  hasAnyPermission,
  getPermissions,
  getRoleDisplayName,
  getRoleDescription,
  canManageRole,
  canDeleteRole,
  getAssignableRoles,
} from '@/lib/services/permission-service'

describe('Permission Service', () => {
  describe('hasPermission', () => {
    it('should grant OWNER all permissions', () => {
      expect(hasPermission('OWNER' as StaffRole, 'dashboard:view')).toBe(true)
      expect(hasPermission('OWNER' as StaffRole, 'staff:delete')).toBe(true)
      expect(hasPermission('OWNER' as StaffRole, 'settings:edit')).toBe(true)
      expect(hasPermission('OWNER' as StaffRole, 'enterprise:manage')).toBe(true)
    })

    it('should grant ADMIN most permissions but not staff:delete', () => {
      expect(hasPermission('ADMIN' as StaffRole, 'orders:view')).toBe(true)
      expect(hasPermission('ADMIN' as StaffRole, 'orders:create')).toBe(true)
      expect(hasPermission('ADMIN' as StaffRole, 'staff:manage')).toBe(true)
      expect(hasPermission('ADMIN' as StaffRole, 'settings:edit')).toBe(true)
      expect(hasPermission('ADMIN' as StaffRole, 'staff:delete')).toBe(false)
    })

    it('should grant MANAGER operational permissions but not staff or settings', () => {
      expect(hasPermission('MANAGER' as StaffRole, 'orders:view')).toBe(true)
      expect(hasPermission('MANAGER' as StaffRole, 'orders:create')).toBe(true)
      expect(hasPermission('MANAGER' as StaffRole, 'orders:provision')).toBe(true)
      expect(hasPermission('MANAGER' as StaffRole, 'servers:power')).toBe(true)
      expect(hasPermission('MANAGER' as StaffRole, 'enterprise:manage')).toBe(true)
      // Should NOT have staff or settings access
      expect(hasPermission('MANAGER' as StaffRole, 'staff:view')).toBe(false)
      expect(hasPermission('MANAGER' as StaffRole, 'staff:invite')).toBe(false)
      expect(hasPermission('MANAGER' as StaffRole, 'settings:view')).toBe(false)
      expect(hasPermission('MANAGER' as StaffRole, 'settings:edit')).toBe(false)
      // Should NOT have delete permissions
      expect(hasPermission('MANAGER' as StaffRole, 'orders:delete')).toBe(false)
      expect(hasPermission('MANAGER' as StaffRole, 'customers:delete')).toBe(false)
    })

    it('should grant SUPPORT only view permissions', () => {
      expect(hasPermission('SUPPORT' as StaffRole, 'dashboard:view')).toBe(true)
      expect(hasPermission('SUPPORT' as StaffRole, 'orders:view')).toBe(true)
      expect(hasPermission('SUPPORT' as StaffRole, 'customers:view')).toBe(true)
      expect(hasPermission('SUPPORT' as StaffRole, 'servers:view')).toBe(true)
      expect(hasPermission('SUPPORT' as StaffRole, 'enterprise:view')).toBe(true)
      // Should NOT have any action permissions
      expect(hasPermission('SUPPORT' as StaffRole, 'orders:create')).toBe(false)
      expect(hasPermission('SUPPORT' as StaffRole, 'orders:edit')).toBe(false)
      expect(hasPermission('SUPPORT' as StaffRole, 'servers:power')).toBe(false)
      expect(hasPermission('SUPPORT' as StaffRole, 'staff:view')).toBe(false)
      expect(hasPermission('SUPPORT' as StaffRole, 'settings:view')).toBe(false)
    })

    it('should return false for unknown role', () => {
      expect(hasPermission('UNKNOWN' as StaffRole, 'dashboard:view')).toBe(false)
    })
  })

  describe('hasAllPermissions', () => {
    it('should return true when role has all listed permissions', () => {
      expect(
        hasAllPermissions('OWNER' as StaffRole, ['orders:view', 'orders:create', 'staff:delete'])
      ).toBe(true)
    })

    it('should return false when role lacks any permission', () => {
      expect(
        hasAllPermissions('SUPPORT' as StaffRole, ['orders:view', 'orders:create'])
      ).toBe(false)
    })

    it('should return true for empty permissions list', () => {
      expect(hasAllPermissions('SUPPORT' as StaffRole, [])).toBe(true)
    })
  })

  describe('hasAnyPermission', () => {
    it('should return true when role has at least one permission', () => {
      expect(
        hasAnyPermission('SUPPORT' as StaffRole, ['orders:create', 'orders:view'])
      ).toBe(true)
    })

    it('should return false when role has none of the permissions', () => {
      expect(
        hasAnyPermission('SUPPORT' as StaffRole, ['staff:delete', 'settings:edit'])
      ).toBe(false)
    })

    it('should return false for empty permissions list', () => {
      expect(hasAnyPermission('OWNER' as StaffRole, [])).toBe(false)
    })
  })

  describe('getPermissions', () => {
    it('should return all permissions for OWNER', () => {
      const perms = getPermissions('OWNER' as StaffRole)

      expect(perms).toContain('staff:delete')
      expect(perms).toContain('settings:edit')
      expect(perms).toContain('enterprise:manage')
      expect(perms.length).toBeGreaterThan(15)
    })

    it('should return fewer permissions for SUPPORT than OWNER', () => {
      const ownerPerms = getPermissions('OWNER' as StaffRole)
      const supportPerms = getPermissions('SUPPORT' as StaffRole)

      expect(supportPerms.length).toBeLessThan(ownerPerms.length)
    })

    it('should return empty array for unknown role', () => {
      expect(getPermissions('UNKNOWN' as StaffRole)).toEqual([])
    })
  })

  describe('getRoleDisplayName', () => {
    it('should return correct display names', () => {
      expect(getRoleDisplayName('OWNER' as StaffRole)).toBe('Owner')
      expect(getRoleDisplayName('ADMIN' as StaffRole)).toBe('Administrator')
      expect(getRoleDisplayName('MANAGER' as StaffRole)).toBe('Manager')
      expect(getRoleDisplayName('SUPPORT' as StaffRole)).toBe('Support')
    })

    it('should return raw role for unknown role', () => {
      expect(getRoleDisplayName('UNKNOWN' as StaffRole)).toBe('UNKNOWN')
    })
  })

  describe('getRoleDescription', () => {
    it('should return non-empty description for each role', () => {
      expect(getRoleDescription('OWNER' as StaffRole).length).toBeGreaterThan(0)
      expect(getRoleDescription('ADMIN' as StaffRole).length).toBeGreaterThan(0)
      expect(getRoleDescription('MANAGER' as StaffRole).length).toBeGreaterThan(0)
      expect(getRoleDescription('SUPPORT' as StaffRole).length).toBeGreaterThan(0)
    })

    it('should mention key restrictions in descriptions', () => {
      expect(getRoleDescription('OWNER' as StaffRole)).toContain('Cannot be deleted')
      expect(getRoleDescription('ADMIN' as StaffRole)).toContain('not delete')
      expect(getRoleDescription('SUPPORT' as StaffRole)).toContain('View-only')
    })

    it('should return empty string for unknown role', () => {
      expect(getRoleDescription('UNKNOWN' as StaffRole)).toBe('')
    })
  })

  describe('canManageRole', () => {
    it('should allow OWNER to manage any role', () => {
      expect(canManageRole('OWNER' as StaffRole, 'ADMIN' as StaffRole)).toBe(true)
      expect(canManageRole('OWNER' as StaffRole, 'MANAGER' as StaffRole)).toBe(true)
      expect(canManageRole('OWNER' as StaffRole, 'SUPPORT' as StaffRole)).toBe(true)
      expect(canManageRole('OWNER' as StaffRole, 'OWNER' as StaffRole)).toBe(true)
    })

    it('should allow ADMIN to manage MANAGER and SUPPORT', () => {
      expect(canManageRole('ADMIN' as StaffRole, 'MANAGER' as StaffRole)).toBe(true)
      expect(canManageRole('ADMIN' as StaffRole, 'SUPPORT' as StaffRole)).toBe(true)
    })

    it('should deny ADMIN managing ADMIN or OWNER', () => {
      expect(canManageRole('ADMIN' as StaffRole, 'ADMIN' as StaffRole)).toBe(false)
      expect(canManageRole('ADMIN' as StaffRole, 'OWNER' as StaffRole)).toBe(false)
    })

    it('should deny MANAGER managing anyone', () => {
      expect(canManageRole('MANAGER' as StaffRole, 'SUPPORT' as StaffRole)).toBe(false)
      expect(canManageRole('MANAGER' as StaffRole, 'MANAGER' as StaffRole)).toBe(false)
    })

    it('should deny SUPPORT managing anyone', () => {
      expect(canManageRole('SUPPORT' as StaffRole, 'SUPPORT' as StaffRole)).toBe(false)
    })
  })

  describe('canDeleteRole', () => {
    it('should allow OWNER to delete ADMIN, MANAGER, SUPPORT', () => {
      expect(canDeleteRole('OWNER' as StaffRole, 'ADMIN' as StaffRole)).toBe(true)
      expect(canDeleteRole('OWNER' as StaffRole, 'MANAGER' as StaffRole)).toBe(true)
      expect(canDeleteRole('OWNER' as StaffRole, 'SUPPORT' as StaffRole)).toBe(true)
    })

    it('should deny OWNER deleting another OWNER', () => {
      expect(canDeleteRole('OWNER' as StaffRole, 'OWNER' as StaffRole)).toBe(false)
    })

    it('should deny ADMIN deleting anyone', () => {
      expect(canDeleteRole('ADMIN' as StaffRole, 'MANAGER' as StaffRole)).toBe(false)
      expect(canDeleteRole('ADMIN' as StaffRole, 'SUPPORT' as StaffRole)).toBe(false)
    })

    it('should deny MANAGER deleting anyone', () => {
      expect(canDeleteRole('MANAGER' as StaffRole, 'SUPPORT' as StaffRole)).toBe(false)
    })

    it('should deny SUPPORT deleting anyone', () => {
      expect(canDeleteRole('SUPPORT' as StaffRole, 'SUPPORT' as StaffRole)).toBe(false)
    })
  })

  describe('getAssignableRoles', () => {
    it('should return ADMIN, MANAGER, SUPPORT for OWNER', () => {
      const roles = getAssignableRoles('OWNER' as StaffRole)

      expect(roles).toEqual(['ADMIN', 'MANAGER', 'SUPPORT'])
      expect(roles).not.toContain('OWNER')
    })

    it('should return ADMIN, MANAGER, SUPPORT for ADMIN', () => {
      const roles = getAssignableRoles('ADMIN' as StaffRole)

      expect(roles).toEqual(['ADMIN', 'MANAGER', 'SUPPORT'])
    })

    it('should return empty array for MANAGER', () => {
      expect(getAssignableRoles('MANAGER' as StaffRole)).toEqual([])
    })

    it('should return empty array for SUPPORT', () => {
      expect(getAssignableRoles('SUPPORT' as StaffRole)).toEqual([])
    })
  })
})
