import type { FormEvent } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { ArrowDown, ArrowUp, ArrowUpDown, Check, ChevronDown, Copy, Loader2, Pencil, Search, Trash2, UserPlus, Users, X } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { ModuleHeader } from '@/components/ui/module-header';
import { NativeSelect } from '@/components/ui/native-select';
import { PageSkeleton } from '@/components/ui/page-skeleton';
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '@/components/ui/command';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { TenantParentPicker } from '@/components/tenant-create/TenantParentPicker';
import { ImageUpload } from '@/components/common/ImageUpload';
import { TenantLogo } from '@/components/common/TenantLogo';
import { UserAvatar } from '@/components/common/UserAvatar';
import { useScopeContext } from '@/contexts/scope-context';
import { useAuth } from '@/contexts/useAuth';
import { useTenantChildren } from '@/business/scope/queries';
import { getAuthRoleLabel } from '@/business/auth/selectors';
import { useIamCapabilities } from '@/business/iam-capabilities/hooks';
import { usePermissions } from '@/hooks/usePermissions';
import {
  getRoleTenantInput,
  type RoleTenantInput,
} from '@/business/user-admin/selectors';
import {
  createOwnerWithOrganization,
  createUser,
  deleteUser,
  linkGuardianStudent,
  listGuardianStudents,
  listPermissions,
  listRoles,
  listUsers,
  updateUser,
  type AdminUserRow,
  type RoleRow,
  type SaveUserData,
} from '@/business/user-admin/api';
import { USER_NAME_PREFIX_OPTIONS } from '@/shared/constants/users';
import { getErrorMessage } from '@/shared/errors/errorMessages';
import type { UserRole } from '@/shared/types/app';
import type { ParentLevel } from '@/business/tenant-create/selectors';
import { cn } from '@/lib/utils';

const USER_LIST_PAGE_SIZE = 10;
const USER_LIST_FETCH_LIMIT = 1000;

interface StatusMessage {
  readonly type: 'success' | 'error';
  readonly text: string;
}

interface CreatedCredential {
  readonly email: string;
  readonly password: string;
}

type UserListSortField =
  | 'name'
  | 'email'
  | 'phoneNumber'
  | 'school'
  | 'campus'
  | 'class'
  | 'role';

type UserListSortDirection = 'asc' | 'desc';

const TENANT_INPUT_TARGET: Record<Exclude<RoleTenantInput, 'none' | 'guardian'>, ParentLevel> = {
  org: 'organization',
  school: 'school',
  campus: 'campus',
  class: 'campus',
};

function userName(row: AdminUserRow): string {
  return [row.firstName, row.lastName].filter(Boolean).join(' ').trim() || row.email;
}

function locationName(value?: { name?: string | null } | null): string {
  return value?.name?.trim() || '—';
}

function locationCell(value?: { name?: string | null; logo?: string | null } | null) {
  const name = value?.name?.trim();
  if (!name) {
    return '—';
  }
  return (
    <span className="flex min-w-[140px] items-center gap-2">
      <TenantLogo
        name={name}
        logoUrl={value?.logo ?? null}
        className="h-7 w-7 rounded-md text-[9px]"
      />
      <span className="truncate">{name}</span>
    </span>
  );
}

function classNamesForUser(
  row: AdminUserRow,
  guardianClassNamesById: ReadonlyMap<string, readonly string[]>,
): readonly string[] {
  const names: string[] = [];
  if (row.class?.name) {
    names.push(row.class.name);
  }
  for (const enrollment of row.class_enrollments_student ?? []) {
    const className = enrollment.class?.name;
    if (className && !names.includes(className)) {
      names.push(className);
    }
  }
  for (const className of guardianClassNamesById.get(row.id) ?? []) {
    if (!names.includes(className)) {
      names.push(className);
    }
  }
  return names;
}

function classCell(
  row: AdminUserRow,
  guardianClassNamesById: ReadonlyMap<string, readonly string[]>,
) {
  const classNames = classNamesForUser(row, guardianClassNamesById);
  if (classNames.length === 0) {
    return '—';
  }
  return (
    <span className="block min-w-[140px] truncate">
      {classNames.join(', ')}
    </span>
  );
}

function sortText(value: string | null | undefined): string {
  return value?.trim().toLocaleLowerCase() || '';
}

function permissionLabel(name: string | null | undefined, id: string): string {
  return (name?.trim() || id).replace(/_/g, ' ');
}

function studentPickerLabel(students: readonly AdminUserRow[], selectedIds: readonly string[]): string {
  if (selectedIds.length === 0) return 'Select students...';
  const names = students
    .filter((student) => selectedIds.includes(student.id))
    .map(userName);
  if (names.length === 0) return `${selectedIds.length} selected`;
  if (names.length <= 2) return names.join(', ');
  return `${names.slice(0, 2).join(', ')} +${names.length - 2}`;
}

export default function UserAdminPage() {
  const { tier, ownTenant } = useScopeContext();
  const { user } = useAuth();
  const queryClient = useQueryClient();
  const permissions = usePermissions();
  const capabilitiesQuery = useIamCapabilities();
  const rolesQuery = useQuery({ queryKey: ['roles'], queryFn: listRoles });
  const permissionsQuery = useQuery({ queryKey: ['permissions'], queryFn: listPermissions });
  const guardianStudentsQuery = useQuery({
    queryKey: ['guardian-students'],
    queryFn: () => listGuardianStudents(),
  });
  const [usersPage, setUsersPage] = useState(0);
  const [usersSearchDraft, setUsersSearchDraft] = useState('');
  const [usersSearch, setUsersSearch] = useState('');
  const [usersSortField, setUsersSortField] = useState<UserListSortField>('name');
  const [usersSortDirection, setUsersSortDirection] = useState<UserListSortDirection>('asc');
  const [isUserFormOpen, setIsUserFormOpen] = useState(false);
  const [isStudentPickerOpen, setIsStudentPickerOpen] = useState(false);
  const usersQuery = useQuery({
    queryKey: ['admin-users', usersSearch],
    queryFn: () =>
      listUsers({
        query: usersSearch || undefined,
        limit: USER_LIST_FETCH_LIMIT,
        page: 0,
      }),
  });

  const manageableRoles = useMemo(
    () => capabilitiesQuery.data?.manageableRoleNames ?? [],
    [capabilitiesQuery.data],
  );
  const createRoleOptions = useMemo(
    () => manageableRoles.filter((item) => item !== 'super_admin'),
    [manageableRoles],
  );
  const currentRoleName = user?.app_role?.name ?? null;
  const canCreateUsers = permissions.has('CREATE_USERS');
  const canUpdateUsers = permissions.has('UPDATE_USERS');
  const canDeleteUsers = permissions.has('DELETE_USERS');
  const canEditPermissions = canCreateUsers || canUpdateUsers;


  // role name → id (for create/update payloads + student lookup).
  const roleIdByName = useMemo(() => {
    const map = new Map<string, string>();
    for (const r of rolesQuery.data?.rows ?? []) {
      if (r.name) map.set(r.name, r.id);
    }
    return map;
  }, [rolesQuery.data]);
  const roleById = useMemo(() => {
    const map = new Map<string, RoleRow>();
    for (const roleItem of rolesQuery.data?.rows ?? []) {
      map.set(roleItem.id, roleItem);
    }
    return map;
  }, [rolesQuery.data]);
  const allPermissions = useMemo(
    () =>
      [...(permissionsQuery.data?.rows ?? [])].sort((a, b) =>
        permissionLabel(a.name, a.id).localeCompare(permissionLabel(b.name, b.id)),
      ),
    [permissionsQuery.data],
  );

  const [editingId, setEditingId] = useState<string | null>(null);
  const [namePrefix, setNamePrefix] = useState('');
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');
  const [phoneNumber, setPhoneNumber] = useState('');
  const [email, setEmail] = useState('');
  const [avatar, setAvatar] = useState<string | null>(null);
  const [role, setRole] = useState<UserRole | ''>('');
  const [pickedTenantId, setPickedTenantId] = useState<string | null>(null);
  const [classId, setClassId] = useState('');
  const [studentIds, setStudentIds] = useState<string[]>([]);
  const [grantPerms, setGrantPerms] = useState<string[]>([]);
  const [excludePerms, setExcludePerms] = useState<string[]>([]);
  const [saving, setSaving] = useState(false);
  const [status, setStatus] = useState<StatusMessage | null>(null);
  const [createdCredential, setCreatedCredential] = useState<CreatedCredential | null>(null);

  const editingSuperAdmin = editingId !== null && role === 'super_admin';
  const roleOptions = editingSuperAdmin ? ['super_admin' as UserRole] : createRoleOptions;
  const selectedRole = editingSuperAdmin ? ('super_admin' as UserRole) : (role || roleOptions[0] || '');
  const selectedRoleId = selectedRole ? (roleIdByName.get(selectedRole) ?? null) : null;
  const selectedRoleRecord = selectedRoleId ? roleById.get(selectedRoleId) ?? null : null;
  const rolePermissionIds = useMemo(
    () => new Set((selectedRoleRecord?.permissions ?? []).map((item) => item.id)),
    [selectedRoleRecord],
  );
  const effectivePermissionIds = useMemo(() => {
    const ids = new Set(rolePermissionIds);
    for (const id of grantPerms) ids.add(id);
    for (const id of excludePerms) ids.delete(id);
    return ids;
  }, [excludePerms, grantPerms, rolePermissionIds]);
  const addablePermissions = useMemo(
    () => allPermissions.filter((permission) => !effectivePermissionIds.has(permission.id)),
    [allPermissions, effectivePermissionIds],
  );
  const excludablePermissions = useMemo(
    () => allPermissions.filter((permission) => effectivePermissionIds.has(permission.id)),
    [allPermissions, effectivePermissionIds],
  );
  const tenantInput = selectedRole ? getRoleTenantInput(selectedRole) : 'none';
  const canManageAdvancedPermissions =
    canEditPermissions
    && selectedRole !== 'super_admin'
    && selectedRole !== 'student'
    && selectedRole !== 'guardian';
  const canAutoCreateOwnerOrganization =
    selectedRole === 'owner' && capabilitiesQuery.data?.canCreateOwnerWithOrganization === true;
  const targetLevel =
    tenantInput === 'none' || tenantInput === 'guardian'
      ? null
      : TENANT_INPUT_TARGET[tenantInput];
  // Picker is only needed when the creator's own tier is above the target level.
  const needsPicker =
    targetLevel !== null && tier !== targetLevel && !canAutoCreateOwnerOrganization;
  const resolvedTenantId = needsPicker ? pickedTenantId : (ownTenant?.id ?? null);

  // Class options = children of the chosen/own campus.
  const campusForClass =
    tenantInput === 'class' ? (needsPicker ? pickedTenantId : ownTenant?.id ?? null) : null;
  const classQuery = useTenantChildren(
    campusForClass ? { level: 'campus', id: campusForClass } : null,
    { enabled: Boolean(campusForClass) },
  );

  // Students for guardian linking (role 'student' in the actor's scope).
  const studentsQuery = useQuery({
    queryKey: ['admin-users', 'students', 'student'],
    queryFn: () => listUsers({ app_role: 'student' }),
    enabled: tenantInput === 'guardian',
  });
  const guardianStudentOptions = studentsQuery.data?.rows ?? [];

  const handlePickerChange = useCallback((id: string | null) => {
    setPickedTenantId(id);
    setClassId('');
  }, []);

  const handleUsersSearchSubmit = useCallback((event: FormEvent) => {
    event.preventDefault();
    setUsersPage(0);
    setUsersSearch(usersSearchDraft.trim());
  }, [usersSearchDraft]);

  const clearUsersSearch = useCallback(() => {
    setUsersSearchDraft('');
    setUsersSearch('');
    setUsersPage(0);
  }, []);

  const toggleUsersSort = useCallback((field: UserListSortField) => {
    setUsersPage(0);
    if (field === usersSortField) {
      setUsersSortDirection((current) => (current === 'asc' ? 'desc' : 'asc'));
      return;
    }
    setUsersSortField(field);
    setUsersSortDirection('asc');
  }, [usersSortField]);

  const includePermission = useCallback((permissionId: string) => {
    setExcludePerms((current) => current.filter((id) => id !== permissionId));
    if (!rolePermissionIds.has(permissionId)) {
      setGrantPerms((current) =>
        current.includes(permissionId) ? current : [...current, permissionId],
      );
      return;
    }
    setGrantPerms((current) => current.filter((id) => id !== permissionId));
  }, [rolePermissionIds]);

  const excludePermission = useCallback((permissionId: string) => {
    if (rolePermissionIds.has(permissionId)) {
      setExcludePerms((current) =>
        current.includes(permissionId) ? current : [...current, permissionId],
      );
    } else {
      setGrantPerms((current) => current.filter((id) => id !== permissionId));
      setExcludePerms((current) => current.filter((id) => id !== permissionId));
    }
  }, [rolePermissionIds]);

  const fetchedRows = usersQuery.data?.rows;
  const classNameByStudentId = useMemo(() => {
    const map = new Map<string, string>();
    for (const row of fetchedRows ?? []) {
      const className = classNamesForUser(row, new Map()).join(', ');
      if (row.app_role?.name === 'student' && className) {
        map.set(row.id, className);
      }
    }
    return map;
  }, [fetchedRows]);
  const guardianClassNamesById = useMemo(() => {
    const map = new Map<string, string[]>();
    for (const link of guardianStudentsQuery.data?.rows ?? []) {
      const className = classNameByStudentId.get(link.studentId);
      if (!className) continue;
      const current = map.get(link.guardianId) ?? [];
      if (!current.includes(className)) {
        current.push(className);
        map.set(link.guardianId, current);
      }
    }
    return map;
  }, [classNameByStudentId, guardianStudentsQuery.data]);
  const sortedRows = useMemo(() => {
    const collator = new Intl.Collator(undefined, {
      numeric: true,
      sensitivity: 'base',
    });

    const valueForField = (row: AdminUserRow, field: UserListSortField): string => {
      switch (field) {
        case 'name':
          return sortText(userName(row));
        case 'email':
          return sortText(row.email);
        case 'phoneNumber':
          return sortText(row.phoneNumber);
        case 'school':
          return sortText(locationName(row.school));
        case 'campus':
          return sortText(locationName(row.campus));
        case 'class':
          return sortText(classNamesForUser(row, guardianClassNamesById).join(' '));
        case 'role':
          return sortText(
            row.app_role?.name ? getAuthRoleLabel(row.app_role.name as UserRole) : '—',
          );
      }
    };

    return [...(fetchedRows ?? [])].sort((left, right) => {
      const result = collator.compare(
        valueForField(left, usersSortField),
        valueForField(right, usersSortField),
      );

      if (result !== 0) {
        return usersSortDirection === 'asc' ? result : -result;
      }

      return collator.compare(sortText(userName(left)), sortText(userName(right)));
    });
  }, [fetchedRows, guardianClassNamesById, usersSortDirection, usersSortField]);
  const usersTotal = usersQuery.data?.count ?? sortedRows.length;
  const rows = useMemo(() => {
    const start = usersPage * USER_LIST_PAGE_SIZE;
    return sortedRows.slice(start, start + USER_LIST_PAGE_SIZE);
  }, [sortedRows, usersPage]);

  function resetForm() {
    setEditingId(null);
    setNamePrefix('');
    setFirstName('');
    setLastName('');
    setPhoneNumber('');
    setEmail('');
    setAvatar(null);
    setRole('');
    setPickedTenantId(null);
    setClassId('');
    setStudentIds([]);
    setGrantPerms([]);
    setExcludePerms([]);
    setIsUserFormOpen(false);
    setCreatedCredential(null);
  }

  function startEdit(row: AdminUserRow) {
    setIsUserFormOpen(true);
    setEditingId(row.id);
    setNamePrefix(row.name_prefix ?? '');
    setFirstName(row.firstName ?? '');
    setLastName(row.lastName ?? '');
    setPhoneNumber(row.phoneNumber ?? '');
    setEmail(row.email);
    setAvatar(row.avatar?.[0]?.privateUrl ?? null);
    const roleName = row.app_role?.name;
    setRole(
      roleName === 'super_admin' || (roleName && manageableRoles.includes(roleName as UserRole))
        ? (roleName as UserRole)
        : '',
    );
    setPickedTenantId(null);
    setClassId('');
    setStudentIds([]);
    setGrantPerms((row.custom_permissions ?? []).map((p) => p.id));
    setExcludePerms((row.custom_permissions_filter ?? []).map((p) => p.id));
    setStatus(null);
    setCreatedCredential(null);
  }

  function buildTenantPayload(): SaveUserData {
    if (tenantInput === 'org' && resolvedTenantId) return { organizations: resolvedTenantId };
    if (tenantInput === 'school' && resolvedTenantId) return { schoolId: resolvedTenantId };
    if (tenantInput === 'campus' && resolvedTenantId) return { campusId: resolvedTenantId };
    if (tenantInput === 'class') {
      return {
        ...(resolvedTenantId ? { campusId: resolvedTenantId } : {}),
        ...(classId ? { classId } : {}),
      };
    }
    return {};
  }

  async function handleSubmit(event: FormEvent) {
    event.preventDefault();
    setStatus(null);
    setCreatedCredential(null);
    if (!selectedRole) return;

    if (needsPicker && !resolvedTenantId) {
      setStatus({ type: 'error', text: 'Please choose a tenant for this user.' });
      return;
    }
    if (tenantInput === 'class' && !classId) {
      setStatus({ type: 'error', text: 'Please choose a class.' });
      return;
    }

    const roleId = roleIdByName.get(selectedRole);

    const data: SaveUserData = {
      name_prefix: namePrefix === '' ? null : namePrefix,
      firstName: firstName.trim(),
      lastName: lastName.trim(),
      phoneNumber: phoneNumber.trim() || null,
      email: email.trim(),
      avatar,
      app_role: roleId ?? null,
      custom_permissions: canManageAdvancedPermissions ? grantPerms : [],
      custom_permissions_filter: canManageAdvancedPermissions ? excludePerms : [],
      ...buildTenantPayload(),
    };

    setSaving(true);
    try {
      let returnedTemporaryPassword: string | undefined;
      if (editingId) {
        await updateUser(editingId, data);
      } else {
        const { id, temporaryPassword } = selectedRole === 'owner' && !data.organizations
          ? await createOwnerWithOrganization(data)
          : await createUser(data);
        returnedTemporaryPassword = temporaryPassword;
        if (tenantInput === 'guardian' && id && studentIds.length > 0) {
          await Promise.all(studentIds.map((sid) => linkGuardianStudent(id, sid)));
        }
        if (temporaryPassword) {
          setCreatedCredential({ email: data.email ?? email.trim(), password: temporaryPassword });
        }
      }
      await queryClient.invalidateQueries({ queryKey: ['admin-users'] });
      await queryClient.invalidateQueries({ queryKey: ['guardian-students'] });
      setUsersPage(0);
      if (editingId) {
        setStatus({ type: 'success', text: 'User updated.' });
        resetForm();
      } else if (returnedTemporaryPassword) {
        setStatus({ type: 'success', text: 'User created.' });
      } else {
        setStatus({ type: 'success', text: 'User created (invite sent).' });
        resetForm();
      }
    } catch (error) {
      setStatus({ type: 'error', text: getErrorMessage(error, 'Could not save user') });
    } finally {
      setSaving(false);
    }
  }

  function copyCreatedPassword() {
    if (!createdCredential) return;
    void navigator.clipboard?.writeText(createdCredential.password);
    setStatus({
      type: 'success',
      text: 'Temporary password copied. Give it to the created user.',
    });
  }

  async function handleDelete(row: AdminUserRow) {
    setStatus(null);
    try {
      await deleteUser(row.id);
      await queryClient.invalidateQueries({ queryKey: ['admin-users'] });
      if (editingId === row.id) resetForm();
      if (rows.length === 1 && usersPage > 0) setUsersPage((page) => page - 1);
    } catch (error) {
      setStatus({ type: 'error', text: getErrorMessage(error, 'Could not delete user') });
    }
  }

  if (rolesQuery.isLoading || usersQuery.isLoading || capabilitiesQuery.isLoading) {
    return <PageSkeleton />;
  }
  const usersPageCount = Math.max(1, Math.ceil(usersTotal / USER_LIST_PAGE_SIZE));
  const usersStart = usersTotal === 0 ? 0 : usersPage * USER_LIST_PAGE_SIZE + 1;
  const usersEnd = Math.min(usersStart + rows.length - 1, usersTotal);
  const formControlClassName =
    'border-slate-600 bg-slate-950/80 text-slate-100 placeholder:text-slate-500 focus-visible:ring-sky-400 focus-visible:ring-offset-slate-950';
  const hasUsersSearch = usersSearch.length > 0;

  function renderSortIcon(field: UserListSortField) {
    if (usersSortField !== field) {
      return <ArrowUpDown className="h-3.5 w-3.5 text-slate-500" />;
    }
    if (usersSortDirection === 'asc') {
      return <ArrowUp className="h-3.5 w-3.5 text-sky-300" />;
    }
    return <ArrowDown className="h-3.5 w-3.5 text-sky-300" />;
  }

  return (
    <div className="space-y-6 px-3 py-4 md:px-4 md:py-5">
      <ModuleHeader
        title="Users"
        description="Create and manage users within your scope."
        icon={Users}
        iconClassName="bg-gradient-to-br from-sky-500 to-sky-700"
      />

      {(canCreateUsers || editingId) && (
      <Card className="border-slate-600/70 bg-slate-900/80 shadow-lg shadow-black/20">
        <CardHeader className="border-b border-slate-700/70 px-4 py-4 md:px-5">
          <CardTitle className="flex items-center gap-2 text-base text-slate-50">
            <button
              type="button"
              className="flex min-w-0 flex-1 items-center gap-2 text-left"
              aria-expanded={isUserFormOpen}
              aria-controls="user-admin-form"
              onClick={() => setIsUserFormOpen((open) => !open)}
            >
              {editingId ? <Pencil size={16} /> : <UserPlus size={16} />}
              <span>{editingId ? 'Edit user' : 'Add new user'}</span>
              <ChevronDown
                size={16}
                className={cn(
                  'ml-auto shrink-0 text-slate-400 transition-transform',
                  isUserFormOpen && 'rotate-180',
                )}
              />
            </button>
            {editingId && (
              <Button
                type="button"
                variant="ghost"
                onClick={resetForm}
                className="ml-auto h-auto px-2 py-1 text-xs text-slate-400"
              >
                Cancel edit
              </Button>
            )}
          </CardTitle>
        </CardHeader>
        {isUserFormOpen && (
        <CardContent id="user-admin-form" className="px-4 pb-4 md:px-5">
          <form className="space-y-5 pt-6" onSubmit={handleSubmit}>
            <div className="rounded-lg border border-slate-600/80 bg-slate-950/45 p-4 space-y-4">
              <div>
                <p className="text-sm font-semibold text-slate-100">User details</p>
                <p className="mt-1 text-xs text-slate-300">
                  Basic identity fields used for login, invitations, and profile display.
                </p>
              </div>
              <div className="grid gap-4 sm:grid-cols-[auto_1fr]">
                <ImageUpload
                  value={avatar}
                  onChange={setAvatar}
                  table="users"
                  field="avatar"
                  label="Avatar"
                  shape="square"
                  previewSize="lg"
                />
                <div className="grid gap-4 sm:grid-cols-4">
                <div className="space-y-1.5">
                  <Label htmlFor="prefix" className="text-slate-100">Title</Label>
                  <NativeSelect
                    id="prefix"
                    value={namePrefix}
                    className={formControlClassName}
                    onChange={(e) => setNamePrefix(e.target.value)}
                  >
                    <option value="">None</option>
                    {USER_NAME_PREFIX_OPTIONS.map((o) => (
                      <option key={o.value} value={o.value}>{o.label}</option>
                    ))}
                  </NativeSelect>
                </div>
                <div className="space-y-1.5">
                  <Label htmlFor="firstName" className="text-slate-100">First name</Label>
                  <Input
                    id="firstName"
                    value={firstName}
                    className={formControlClassName}
                    onChange={(e) => setFirstName(e.target.value)}
                  />
                </div>
                <div className="space-y-1.5">
                  <Label htmlFor="lastName" className="text-slate-100">Last name</Label>
                  <Input
                    id="lastName"
                    value={lastName}
                    className={formControlClassName}
                    onChange={(e) => setLastName(e.target.value)}
                  />
                </div>
                <div className="space-y-1.5">
                  <Label htmlFor="email" className="text-slate-100">Email</Label>
                  <Input
                    id="email"
                    type="email"
                    value={email}
                    className={formControlClassName}
                    onChange={(e) => setEmail(e.target.value)}
                    required
                  />
                </div>
                <div className="space-y-1.5 sm:col-span-2">
                  <Label htmlFor="phoneNumber" className="text-slate-100">Phone number</Label>
                  <Input
                    id="phoneNumber"
                    type="tel"
                    value={phoneNumber}
                    className={formControlClassName}
                    onChange={(e) => setPhoneNumber(e.target.value)}
                  />
                </div>
                </div>
              </div>
            </div>

            <div className="rounded-lg border border-sky-400/50 bg-sky-950/35 p-4 space-y-4">
              <div>
                <p className="text-sm font-semibold text-slate-100">Access</p>
                <p className="mt-1 text-xs text-sky-100/85">
                  Choose the user's role and the organization or location where this account should work.
                </p>
              </div>

              <div className="space-y-1.5">
                <Label htmlFor="role" className="text-slate-100">Role</Label>
                <NativeSelect
                  id="role"
                  value={selectedRole}
                  disabled={editingSuperAdmin}
                  className={formControlClassName}
                  onChange={(e) => {
                    setRole(e.target.value as UserRole);
                    setPickedTenantId(null);
                    setClassId('');
                    setStudentIds([]);
                    if (e.target.value === 'student' || e.target.value === 'guardian') {
                      setGrantPerms([]);
                      setExcludePerms([]);
                    }
                    setStatus(null);
                  }}
                >
                  {roleOptions.length === 0 ? (
                    <option value="">No available roles</option>
                  ) : (
                    roleOptions.map((r) => (
                      <option key={r} value={r}>{getAuthRoleLabel(r)}</option>
                    ))
                  )}
                </NativeSelect>
                {editingSuperAdmin && (
                  <p className="text-xs text-slate-300">
                    The platform has one Super Admin. This account can be updated, but its role cannot be reassigned.
                  </p>
                )}
              </div>

              {needsPicker && targetLevel && (
                <TenantParentPicker ownTier={tier} targetLevel={targetLevel} onChange={handlePickerChange} />
              )}

              {tenantInput === 'class' && (
                <div className="space-y-1.5">
                  <Label htmlFor="class" className="text-slate-100">Class</Label>
                  <NativeSelect
                    id="class"
                    value={classId}
                    disabled={!campusForClass}
                    className={formControlClassName}
                    onChange={(e) => setClassId(e.target.value)}
                  >
                    <option value="">Select class...</option>
                    {(classQuery.data?.rows ?? []).map((row) => (
                      <option key={row.id} value={row.id}>{row.name ?? row.id}</option>
                    ))}
                  </NativeSelect>
                </div>
              )}

              {tenantInput === 'guardian' && !editingId && (
                <div className="space-y-1.5">
                  <Label className="text-slate-100">Students</Label>
                  <Popover open={isStudentPickerOpen} onOpenChange={setIsStudentPickerOpen}>
                    <PopoverTrigger asChild>
                      <Button
                        type="button"
                        variant="outline"
                        className="h-12 w-full justify-between border-slate-600 bg-slate-950/80 px-3 text-left text-slate-100 hover:bg-slate-900"
                      >
                        <span className={cn('truncate', studentIds.length === 0 && 'text-slate-400')}>
                          {studentPickerLabel(guardianStudentOptions, studentIds)}
                        </span>
                        <ChevronDown className="ml-3 h-4 w-4 shrink-0 text-slate-400" />
                      </Button>
                    </PopoverTrigger>
                    <PopoverContent
                      align="start"
                      className="w-[var(--radix-popover-trigger-width)] border-slate-700 bg-slate-950 p-0 text-slate-100"
                    >
                      <Command className="bg-slate-950 text-slate-100">
                        <CommandInput placeholder="Search students..." />
                        <CommandList className="max-h-64">
                          <CommandEmpty>No students found in your scope.</CommandEmpty>
                          <CommandGroup>
                            {guardianStudentOptions.map((student) => {
                              const selected = studentIds.includes(student.id);
                              return (
                                <CommandItem
                                  key={student.id}
                                  value={`${userName(student)} ${student.email}`}
                                  onSelect={() => {
                                    setStudentIds((prev) =>
                                      selected
                                        ? prev.filter((id) => id !== student.id)
                                        : [...prev, student.id],
                                    );
                                  }}
                                  className="flex cursor-pointer items-center gap-2 text-slate-100"
                                >
                                  <span
                                    className={cn(
                                      'flex h-4 w-4 items-center justify-center rounded border border-slate-500',
                                      selected && 'border-sky-400 bg-sky-500 text-white',
                                    )}
                                    aria-hidden="true"
                                  >
                                    {selected && <Check className="h-3 w-3" />}
                                  </span>
                                  <span className="min-w-0 flex-1">
                                    <span className="block truncate text-sm">{userName(student)}</span>
                                    <span className="block truncate text-xs text-slate-400">{student.email}</span>
                                  </span>
                                </CommandItem>
                              );
                            })}
                          </CommandGroup>
                        </CommandList>
                      </Command>
                    </PopoverContent>
                  </Popover>
                </div>
              )}
            </div>

            {canManageAdvancedPermissions && (
            <details className="rounded-lg border border-slate-600/80 bg-slate-950/45 p-4">
              <summary className="cursor-pointer text-sm font-semibold text-slate-100">
                Advanced permissions (optional)
              </summary>
              <p className="mt-2 mb-3 text-xs text-slate-300">
                Add permissions on top of the role, or exclude permissions the role would grant. The role's
                base permissions apply automatically.
              </p>
              <div className="grid gap-4 sm:grid-cols-2">
                <div className="space-y-1.5">
                  <Label htmlFor="grant-perms" className="text-slate-100">Add permissions</Label>
                  <div
                    id="grant-perms"
                    className="max-h-[26rem] min-h-[8rem] space-y-1 overflow-y-auto rounded-md border border-slate-600 bg-slate-950/80 p-2"
                  >
                    {addablePermissions.length === 0 ? (
                      <p className="px-2 py-1 text-xs text-slate-400">No additional permissions available.</p>
                    ) : (
                      addablePermissions.map((permission) => (
                        <button
                          key={permission.id}
                          type="button"
                          onClick={() => includePermission(permission.id)}
                          className={cn(
                            'flex w-full items-center justify-between rounded-md px-2 py-1.5 text-left text-sm text-slate-200 transition',
                            'hover:bg-emerald-500/15 hover:text-emerald-100',
                          )}
                        >
                          <span className="truncate">{permissionLabel(permission.name, permission.id)}</span>
                          <span className="ml-3 shrink-0 text-xs text-emerald-300">Add</span>
                        </button>
                      ))
                    )}
                  </div>
                </div>
                <div className="space-y-1.5">
                  <Label htmlFor="exclude-perms" className="text-slate-100">Exclude permissions</Label>
                  <div
                    id="exclude-perms"
                    className="max-h-[26rem] min-h-[8rem] space-y-1 overflow-y-auto rounded-md border border-slate-600 bg-slate-950/80 p-2"
                  >
                    {excludablePermissions.length === 0 ? (
                      <p className="px-2 py-1 text-xs text-slate-400">No effective permissions to exclude.</p>
                    ) : (
                      excludablePermissions.map((permission) => (
                        <button
                          key={permission.id}
                          type="button"
                          onClick={() => excludePermission(permission.id)}
                          className={cn(
                            'flex w-full items-center justify-between rounded-md px-2 py-1.5 text-left text-sm text-slate-100 transition',
                            'hover:bg-amber-500/15 hover:text-amber-100',
                          )}
                        >
                          <span className="truncate">{permissionLabel(permission.name, permission.id)}</span>
                          <span className="ml-3 shrink-0 text-xs text-amber-300">Exclude</span>
                        </button>
                      ))
                    )}
                  </div>
                </div>
              </div>
            </details>
            )}

            {createdCredential && (
              <div className="rounded-lg border border-amber-400/50 bg-amber-950/30 p-4 text-amber-50">
                <p className="text-sm font-semibold">Temporary password</p>
                <p className="mt-1 text-xs text-amber-100/85">
                  Mailer is not configured, so this password is shown only once here. Copy it now and give it to
                  the created user so they can sign in and change it from their profile.
                </p>
                <div className="mt-3 grid gap-3 md:grid-cols-[1fr_auto]">
                  <div className="space-y-1.5">
                    <Label htmlFor="created-user-password" className="text-amber-50">
                      {createdCredential.email}
                    </Label>
                    <Input
                      id="created-user-password"
                      value={createdCredential.password}
                      readOnly
                      className="border-amber-400/50 bg-slate-950/80 font-mono text-amber-50"
                    />
                  </div>
                  <Button
                    type="button"
                    variant="outline"
                    onClick={copyCreatedPassword}
                    className="self-end border-amber-300/60 text-amber-50 hover:bg-amber-400/10"
                  >
                    <Copy className="mr-2 h-4 w-4" />
                    Copy
                  </Button>
                </div>
              </div>
            )}

            <div className="flex justify-end">
              <Button
                type="submit"
                disabled={saving || (editingId ? !canUpdateUsers : !canCreateUsers)}
              >
                {saving && <Loader2 size={16} className="mr-2 animate-spin" />}
                {editingId ? 'Save changes' : 'Create user'}
              </Button>
            </div>
          </form>
        </CardContent>
        )}
      </Card>
      )}

      {status && (
        <div
          className={`rounded-lg border px-3 py-2 text-sm ${
            status.type === 'success'
              ? 'border-emerald-500/30 bg-emerald-500/10 text-emerald-200'
              : 'border-red-500/30 bg-red-500/10 text-red-200'
          }`}
        >
          {status.text}
        </div>
      )}

      <Card>
        <CardHeader className="px-4 py-4 md:px-5">
          <div className="flex flex-wrap items-center justify-between gap-3">
            <CardTitle className="text-base">Users ({usersTotal})</CardTitle>
            {usersTotal > 0 && (
              <p className="text-xs text-slate-400">
                Showing {usersStart}-{usersEnd} of {usersTotal}
              </p>
            )}
          </div>
        </CardHeader>
        <CardContent className="space-y-4 px-4 pb-4 md:px-5">
          <form
            className="flex flex-col gap-3 rounded-lg border border-slate-700/60 bg-slate-950/35 p-3 md:flex-row md:items-center"
            onSubmit={handleUsersSearchSubmit}
          >
            <div className="relative flex-1">
              <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-500" />
              <Input
                value={usersSearchDraft}
                onChange={(event) => setUsersSearchDraft(event.target.value)}
                placeholder="Search by name, email, phone, school, campus, class, or role"
                className="pl-9"
              />
            </div>
            <div className="flex items-center gap-2">
              <Button type="submit" variant="outline" disabled={usersQuery.isFetching}>
                Search
              </Button>
              <Button
                type="button"
                variant="ghost"
                disabled={!hasUsersSearch && usersSearchDraft.length === 0}
                onClick={clearUsersSearch}
              >
                <X className="mr-2 h-4 w-4" />
                Clear
              </Button>
            </div>
          </form>

          {rows.length === 0 ? (
            <p className="text-sm text-slate-400">
              {hasUsersSearch ? 'No users match the current search.' : 'No users yet.'}
            </p>
          ) : (
            <div className="overflow-x-auto rounded-lg border border-slate-700/60">
              <table className="min-w-full divide-y divide-slate-700/60 text-sm">
                <thead className="bg-slate-950/60 text-left text-xs uppercase tracking-wide text-slate-400">
                  <tr>
                    {([
                      ['name', 'User'],
                      ['email', 'Email'],
                      ['phoneNumber', 'Phone'],
                      ['school', 'School'],
                      ['campus', 'Campus'],
                      ['class', 'Class'],
                      ['role', 'Role'],
                    ] as const).map(([field, label]) => (
                      <th key={field} className="px-3 py-3 font-medium">
                        <button
                          type="button"
                          onClick={() => toggleUsersSort(field)}
                          className="inline-flex items-center gap-1.5 text-left text-slate-300 transition hover:text-white"
                        >
                          <span>{label}</span>
                          {renderSortIcon(field)}
                        </button>
                      </th>
                    ))}
                    <th className="w-[88px] px-3 py-3 text-right font-medium text-slate-300">Actions</th>
                  </tr>
                </thead>
                <tbody className="divide-y divide-slate-700/50 bg-slate-950/20">
                  {rows.map((row) => {
                    const roleName = row.app_role?.name;
                    const isSuperAdminRow = roleName === 'super_admin';
                    const manageable = roleName ? manageableRoles.includes(roleName as UserRole) : true;
                    const canEditRow =
                      canUpdateUsers
                      && (manageable || (isSuperAdminRow && currentRoleName === 'super_admin'));
                    const canDeleteRow = canDeleteUsers && manageable && !isSuperAdminRow;

                    return (
                      <tr key={row.id} className="align-middle">
                        <td className="px-3 py-2.5">
                          <div className="flex min-w-[180px] items-center gap-3">
                            <UserAvatar
                              name={userName(row)}
                              avatarUrl={row.avatar?.[0]?.privateUrl ?? null}
                              className="h-9 w-9 text-[11px]"
                            />
                            <div className="min-w-0">
                              <p className="truncate font-medium text-slate-100">{userName(row)}</p>
                            </div>
                          </div>
                        </td>
                        <td className="px-3 py-2.5 text-slate-300 break-all">{row.email || '—'}</td>
                        <td className="px-3 py-2.5 text-slate-300">{row.phoneNumber || '—'}</td>
                        <td className="px-3 py-2.5 text-slate-300">{locationCell(row.school)}</td>
                        <td className="px-3 py-2.5 text-slate-300">{locationCell(row.campus)}</td>
                        <td className="px-3 py-2.5 text-slate-300">
                          {classCell(row, guardianClassNamesById)}
                        </td>
                        <td className="px-3 py-2.5 text-slate-300">
                          {roleName ? getAuthRoleLabel(roleName as UserRole) : '—'}
                        </td>
                        <td className="px-3 py-2.5">
                          <div className="flex items-center justify-end gap-1">
                            <Button
                              type="button"
                              variant="ghost"
                              disabled={!canEditRow}
                              onClick={() => startEdit(row)}
                              className="h-8 w-8 px-0"
                              title="Edit"
                              aria-label={`Edit ${userName(row)}`}
                            >
                              <Pencil className="h-3.5 w-3.5" />
                            </Button>
                            <Button
                              type="button"
                              variant="ghost"
                              disabled={!canDeleteRow}
                              onClick={() => handleDelete(row)}
                              className="h-8 w-8 px-0 text-red-400 hover:bg-red-500/10"
                              title="Delete"
                              aria-label={`Delete ${userName(row)}`}
                            >
                              <Trash2 className="h-3.5 w-3.5" />
                            </Button>
                          </div>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          )}
          {usersPageCount > 1 && (
            <div className="mt-4 flex flex-wrap items-center justify-between gap-3 border-t border-slate-700/50 pt-4">
              <p className="text-xs text-slate-400">
                Page {usersPage + 1} of {usersPageCount}
              </p>
              <div className="flex items-center gap-2">
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  disabled={usersPage === 0 || usersQuery.isFetching}
                  onClick={() => setUsersPage((page) => Math.max(0, page - 1))}
                >
                  Previous
                </Button>
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  disabled={usersPage >= usersPageCount - 1 || usersQuery.isFetching}
                  onClick={() => setUsersPage((page) => Math.min(usersPageCount - 1, page + 1))}
                >
                  Next
                </Button>
              </div>
            </div>
          )}
        </CardContent>
      </Card>
    </div>
  );
}
