import { test } from 'node:test';
import assert from 'node:assert/strict';
import {
  canAssignUserRole,
  canCreateUserWithRole,
  canDeleteUserWithRole,
  canManageUserWithRole,
  canUpdateUserWithRole,
  canDeleteOrganization,
} from '@/services/shared/role-policy';
import { ROLE_NAMES } from '@/shared/constants/roles';
import type { CurrentUser } from '@/db/api/types';

function actor(role: string): CurrentUser {
  return { id: 'actor', app_role: { name: role } };
}

// --- user-management relational constraints (§3.3) ---

test('super_admin can manage every assignable role except creating another super_admin', () => {
  for (const role of Object.values(ROLE_NAMES).filter((item) =>
    item !== ROLE_NAMES.GUEST && item !== ROLE_NAMES.SUPER_ADMIN
  )) {
    assert.equal(canManageUserWithRole(actor(ROLE_NAMES.SUPER_ADMIN), role), true);
    assert.equal(canCreateUserWithRole(actor(ROLE_NAMES.SUPER_ADMIN), role), true);
  }
  assert.equal(canCreateUserWithRole(actor(ROLE_NAMES.SUPER_ADMIN), ROLE_NAMES.SUPER_ADMIN), false);
  assert.equal(canManageUserWithRole(actor(ROLE_NAMES.SUPER_ADMIN), ROLE_NAMES.GUEST), false);
});

test('super_admin account is update-only', () => {
  const superAdmin = actor(ROLE_NAMES.SUPER_ADMIN);
  const systemAdmin = actor(ROLE_NAMES.SYSTEM_ADMIN);

  assert.equal(canUpdateUserWithRole(superAdmin, ROLE_NAMES.SUPER_ADMIN), true);
  assert.equal(canUpdateUserWithRole(systemAdmin, ROLE_NAMES.SUPER_ADMIN), false);
  assert.equal(canDeleteUserWithRole(superAdmin, ROLE_NAMES.SUPER_ADMIN), false);
  assert.equal(canAssignUserRole(superAdmin, ROLE_NAMES.OWNER, ROLE_NAMES.SUPER_ADMIN), false);
  assert.equal(canAssignUserRole(superAdmin, ROLE_NAMES.SUPER_ADMIN, ROLE_NAMES.OWNER), false);
  assert.equal(canAssignUserRole(superAdmin, ROLE_NAMES.SUPER_ADMIN, ROLE_NAMES.SUPER_ADMIN), true);
});

test('system_admin cannot manage super_admin or system_admin', () => {
  const sysAdmin = actor(ROLE_NAMES.SYSTEM_ADMIN);
  assert.equal(canManageUserWithRole(sysAdmin, ROLE_NAMES.SUPER_ADMIN), false);
  assert.equal(canManageUserWithRole(sysAdmin, ROLE_NAMES.SYSTEM_ADMIN), false);
  assert.equal(canManageUserWithRole(sysAdmin, ROLE_NAMES.OWNER), true);
  assert.equal(canManageUserWithRole(sysAdmin, ROLE_NAMES.TEACHER), true);
});

test('superintendent cannot manage owner or another superintendent', () => {
  const sup = actor(ROLE_NAMES.SUPERINTENDENT);
  assert.equal(canManageUserWithRole(sup, ROLE_NAMES.OWNER), false);
  assert.equal(canManageUserWithRole(sup, ROLE_NAMES.SUPERINTENDENT), false);
  assert.equal(canManageUserWithRole(sup, ROLE_NAMES.DIRECTOR), true);
  assert.equal(canManageUserWithRole(sup, ROLE_NAMES.TEACHER), true);
});

test('director manages campus/external roles but not director or above', () => {
  const dir = actor(ROLE_NAMES.DIRECTOR);
  assert.equal(canManageUserWithRole(dir, ROLE_NAMES.DIRECTOR), false);
  assert.equal(canManageUserWithRole(dir, ROLE_NAMES.SUPERINTENDENT), false);
  assert.equal(canManageUserWithRole(dir, ROLE_NAMES.TEACHER), true);
  assert.equal(canManageUserWithRole(dir, ROLE_NAMES.STUDENT), true);
});

test('owner and superintendent manage the school-tier roles', () => {
  for (const boss of [ROLE_NAMES.OWNER, ROLE_NAMES.SUPERINTENDENT]) {
    assert.equal(canManageUserWithRole(actor(boss), ROLE_NAMES.PRINCIPAL), true);
    assert.equal(canManageUserWithRole(actor(boss), ROLE_NAMES.REGISTRAR), true);
  }
});

test('principal manages the school staff but not org/system roles or another principal', () => {
  const principal = actor(ROLE_NAMES.PRINCIPAL);
  assert.equal(canManageUserWithRole(principal, ROLE_NAMES.REGISTRAR), true);
  assert.equal(canManageUserWithRole(principal, ROLE_NAMES.DIRECTOR), true);
  assert.equal(canManageUserWithRole(principal, ROLE_NAMES.TEACHER), true);
  assert.equal(canManageUserWithRole(principal, ROLE_NAMES.STUDENT), true);
  assert.equal(canManageUserWithRole(principal, ROLE_NAMES.PRINCIPAL), false);
  assert.equal(canManageUserWithRole(principal, ROLE_NAMES.SUPERINTENDENT), false);
  assert.equal(canManageUserWithRole(principal, ROLE_NAMES.OWNER), false);
});

test('registrar (read-only) manages nobody', () => {
  const registrar = actor(ROLE_NAMES.REGISTRAR);
  for (const role of Object.values(ROLE_NAMES)) {
    assert.equal(canManageUserWithRole(registrar, role), false);
  }
});

test('campus staff (e.g. teacher) cannot manage any user', () => {
  const teacher = actor(ROLE_NAMES.TEACHER);
  for (const role of Object.values(ROLE_NAMES)) {
    assert.equal(canManageUserWithRole(teacher, role), false);
  }
  // ...including a roleless target.
  assert.equal(canManageUserWithRole(teacher, null), false);
});

test('a manager may act on a roleless (null) target', () => {
  assert.equal(canManageUserWithRole(actor(ROLE_NAMES.DIRECTOR), null), true);
});

test('an unauthenticated/roleless actor manages nobody', () => {
  assert.equal(canManageUserWithRole(undefined, ROLE_NAMES.TEACHER), false);
  assert.equal(canManageUserWithRole({ id: 'x' }, ROLE_NAMES.TEACHER), false);
});

// --- organization deletion (§3.3) ---

test('only super_admin / system_admin / owner may delete an organization', () => {
  assert.equal(canDeleteOrganization(actor(ROLE_NAMES.SUPER_ADMIN)), true);
  assert.equal(canDeleteOrganization(actor(ROLE_NAMES.SYSTEM_ADMIN)), true);
  assert.equal(canDeleteOrganization(actor(ROLE_NAMES.OWNER)), true);
  assert.equal(canDeleteOrganization(actor(ROLE_NAMES.SUPERINTENDENT)), false);
  assert.equal(canDeleteOrganization(actor(ROLE_NAMES.DIRECTOR)), false);
  assert.equal(canDeleteOrganization(undefined), false);
});
