<!DOCTYPE html>
<html>

<head>
  <meta name="description" content="Role Management">
  <title>{{ $t('nav.roles') }}</title>
  <style>
    body {
      display: flex;
      flex-direction: column;
      gap: var(--spacing-lg);
      padding: var(--spacing-lg);
      box-sizing: border-box;
      background-color: var(--bg-color);
    }

    .page-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      flex-wrap: wrap;
      gap: var(--spacing-md);
      padding-bottom: var(--spacing-md);
      border-bottom: 1px solid var(--border-color);
    }

    .page-title {
      font-size: var(--font-size-2xl);
      font-weight: var(--font-weight-bold);
      color: var(--text-color);
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
    }

    .search-box {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
      background: var(--bg-color-secondary);
      padding: 0 var(--spacing-md);
      border-radius: var(--radius-full);
      border: 1px solid var(--border-color);
      min-width: 320px;
      height: 40px;
      transition: all var(--transition-base);
    }

    .search-box:focus-within {
      border-color: var(--color-primary);
      box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary), transparent 85%);
    }

    .search-box input {
      border: none;
      background: transparent;
      outline: none;
      font-size: var(--font-size-md);
      color: var(--text-color);
      width: 100%;
      height: 100%;
    }

    .table-container {
      flex: 1;
      overflow: auto;
      background: var(--bg-color-secondary);
      border-radius: var(--radius-lg);
      box-shadow: var(--shadow-sm);
      border: 1px solid var(--border-color);
    }

    table {
      width: 100%;
      border-collapse: collapse;
      white-space: nowrap;
    }

    th,
    td {
      text-align: left;
      padding: var(--spacing-md);
      border-bottom: 1px solid var(--border-color);
    }

    th {
      background-color: var(--bg-color-tertiary);
      font-weight: 600;
      position: sticky;
      top: 0;
      z-index: 10;
    }

    tr:last-child td {
      border-bottom: none;
    }

    tr:hover td {
      background-color: var(--bg-color-tertiary);
    }

    .status-badge {
      display: inline-block;
      padding: 2px 8px;
      border-radius: var(--radius-full);
      font-size: var(--font-size-xs);
      font-weight: 500;
    }

    .status-active {
      background-color: color-mix(in srgb, var(--color-success), transparent 85%);
      color: var(--color-success);
    }

    .status-inactive {
      background-color: color-mix(in srgb, var(--text-color-disabled), transparent 85%);
      color: var(--text-color-secondary);
    }

    /* Tab Styles */
    .tab,
    .tab-active {
      padding: 12px 20px;
      cursor: pointer;
      border-bottom: 2px solid transparent;
      transition: all var(--transition-base);
      display: flex;
      align-items: center;
      gap: 8px;
      font-weight: 500;
    }

    .tab {
      color: var(--text-color-secondary);
    }

    .tab:hover {
      color: var(--text-color);
    }

    .tab-active {
      color: var(--color-primary);
      border-bottom-color: var(--color-primary);
    }

    /* Permission List */
    .permission-list,
    .user-list,
    .available-permission-list,
    .available-user-list {
      max-height: 400px;
      overflow-y: auto;
      display: flex;
      flex-direction: column;
      gap: 8px;
    }

    .permission-item,
    .user-item,
    .available-permission-item,
    .available-user-item {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 12px;
      background: var(--bg-color-tertiary);
      border-radius: var(--radius-md);
      transition: background var(--transition-base);
    }

    .permission-item:hover,
    .user-item:hover {
      background: var(--border-color);
    }

    .permission-info,
    .user-info {
      flex: 1;
      min-width: 0;
    }

    .permission-id,
    .user-name {
      font-weight: 500;
      color: var(--text-color);
    }

    .permission-scope,
    .user-username {
      font-size: var(--font-size-sm);
      color: var(--text-color-secondary);
    }

    .permission-level {
      flex-shrink: 0;
    }

    .level-badge {
      display: inline-block;
      padding: 2px 8px;
      border-radius: var(--radius-full);
      font-size: var(--font-size-xs);
      font-weight: 500;
    }

    .level-1 {
      background: color-mix(in srgb, var(--color-info), transparent 85%);
      color: var(--color-info);
    }

    .level-2 {
      background: color-mix(in srgb, var(--color-success), transparent 85%);
      color: var(--color-success);
    }

    .level-4 {
      background: color-mix(in srgb, var(--color-warning), transparent 85%);
      color: var(--color-warning);
    }

    .level-6 {
      background: color-mix(in srgb, var(--color-warning), transparent 70%);
      color: var(--color-warning);
    }

    .level-7 {
      background: color-mix(in srgb, var(--color-danger), transparent 85%);
      color: var(--color-danger);
    }

    /* User Avatar */
    .user-avatar,
    .user-avatar-sm {
      border-radius: var(--radius-full);
      object-fit: cover;
    }

    .user-avatar {
      width: 40px;
      height: 40px;
    }

    .user-avatar-sm {
      width: 32px;
      height: 32px;
    }

    /* Empty State */
    .empty-state {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      padding: 40px;
      color: var(--text-color-secondary);
      gap: 12px;
    }

    .empty-state p {
      margin: 0;
    }

    /* Checkbox styling */
    input[type="checkbox"] {
      width: 18px;
      height: 18px;
      cursor: pointer;
      accent-color: var(--color-primary);
    }
  </style>
</head>

<body>
  <div class="page-header">
    <div class="page-title">
      <i class="fas fa-user-tag" style="color: var(--color-primary);"></i>
      {{ $t('nav.roles') }}
    </div>
    <div style="display: flex; gap: var(--spacing-md); align-items: center;">
      <div class="search-box">
        <i class="fas fa-search" style="color: var(--text-color-tertiary);"></i>
        <input type="text" v:value="searchQuery" :placeholder="$t('role.search_placeholder')">
      </div>
      <v-btn color="primary" :click="openCreateModal">
        <i class="fas fa-plus"></i>
        {{ $t('common.create') }}
      </v-btn>
    </div>
  </div>

  <div class="table-container">
    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>{{ $t('role.code') }}</th>
          <th>{{ $t('role.name') }}</th>
          <th>{{ $t('role.description') }}</th>
          <th>System</th>
          <th>Status</th>
          <th>{{ $t('common.actions') }}</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="r in filteredRoles">
          <td>{{ r.id }}</td>
          <td>{{ r.code }}</td>
          <td>{{ r.name }}</td>
          <td>{{ r.description }}</td>
          <td>
            <span class="status-badge" :class="r.is_system ? 'status-active' : 'status-inactive'">
              {{ r.is_system ? 'Yes' : 'No' }}
            </span>
          </td>
          <td>
            <span class="status-badge" :class="r.status === 1 ? 'status-active' : 'status-inactive'">
              {{ r.status === 1 ? 'Active' : 'Inactive' }}
            </span>
          </td>
          <td>
            <div style="display: flex; gap: 8px;">
              <v-btn icon size="sm" variant="outline" :click="() => openDetailModal(r)" :title="$t('common.detail')">
                <i class="fas fa-eye"></i>
              </v-btn>
              <v-btn icon size="sm" variant="outline" :click="() => openEditModal(r)" :title="$t('common.edit')"
                :disabled="r.is_system">
                <i class="fas fa-edit"></i>
              </v-btn>
              <v-btn icon size="sm" color="danger" variant="outline" :click="() => deleteRole(r)"
                :title="$t('common.delete')" :disabled="r.is_system">
                <i class="fas fa-trash"></i>
              </v-btn>
            </div>
          </td>
        </tr>
      </tbody>
    </table>
  </div>

  <!-- Create/Edit Dialog -->
  <v-dialog v:visible="showModal" :title="isEdit ? $t('role.edit') : $t('role.create')">
    <form @submit.prevent="saveRole" style="display: grid; gap: 16px;">
      <v-input :label="$t('role.code')" required v:value="formData.code" :disabled="isEdit"
        placeholder="e.g. admin"></v-input>
      <v-input :label="$t('role.name')" required v:value="formData.name" placeholder="e.g. Administrator"></v-input>
      <v-input :label="$t('role.description')" v:value="formData.description" placeholder="Description..."></v-input>
    </form>
    <div vslot="footer">
      <v-btn variant="outline" :click="closeModal">{{ $t('common.cancel') }}</v-btn>
      <v-btn color="primary" :click="saveRole">
        {{ isEdit ? $t('common.save') : $t('common.create') }}
      </v-btn>
    </div>
  </v-dialog>

  <!-- Role Detail Dialog - Permissions & Users -->
  <v-dialog v:visible="showDetailModal" width="800px" :title="$t('role.detail') + ' - ' + (currentRole?.name || '')">
    <div style="display: flex; flex-direction: column; gap: 20px;">
      <!-- Tabs -->
      <div style="display: flex; gap: 8px; border-bottom: 1px solid var(--border-color);">
        <div :class="detailTab === 'permissions' ? 'tab-active' : 'tab'" @click="switchTab('permissions')">
          <i class="fas fa-shield-alt"></i> {{ $t('role.permissions') }}
        </div>
        <div :class="detailTab === 'users' ? 'tab-active' : 'tab'" @click="switchTab('users')">
          <i class="fas fa-users"></i> {{ $t('role.users') }}
        </div>
      </div>

      <!-- Permissions Tab -->
      <div v-if="detailTab === 'permissions'" style="display: flex; flex-direction: column; gap: 16px;">
        <div style="display: flex; justify-content: space-between; align-items: center;">
          <span style="color: var(--text-color-secondary); font-size: var(--font-size-sm);">
            {{ $t('role.permissions_desc') }}
          </span>
          <v-btn size="sm" color="primary" :click="openPermissionSelector" :disabled="currentRole?.is_system">
            <i class="fas fa-plus"></i> {{ $t('role.add_permission') }}
          </v-btn>
        </div>
        <div class="permission-list">
          <div v-for="p in rolePermissions" class="permission-item">
            <div class="permission-info">
              <div class="permission-id">{{ p.permission_id }}</div>
              <div class="permission-scope">{{ p.scope }}</div>
            </div>
            <div class="permission-level">
              <span :class="'level-badge level-' + p.level">{{ formatLevel(p.level) }}</span>
            </div>
            <v-btn v-if="!currentRole?.is_system" icon size="xs" color="danger" variant="ghost"
              :click="() => removePermission(p)" :title="$t('common.remove')">
              <i class="fas fa-times"></i>
            </v-btn>
          </div>
          <div v-if="rolePermissions.length === 0" class="empty-state">
            <i class="fas fa-shield-alt" style="font-size: 48px; color: var(--text-color-disabled);"></i>
            <p>{{ $t('role.no_permissions') }}</p>
          </div>
        </div>
      </div>

      <!-- Users Tab -->
      <div v-if="detailTab === 'users'" style="display: flex; flex-direction: column; gap: 16px;">
        <div style="display: flex; justify-content: space-between; align-items: center;">
          <div class="search-box" style="min-width: 240px;">
            <i class="fas fa-search" style="color: var(--text-color-tertiary);"></i>
            <input type="text" v:value="userSearchQuery" :placeholder="$t('role.search_users')">
          </div>
          <v-btn size="sm" color="primary" :click="openUserSelector" :disabled="currentRole?.is_system">
            <i class="fas fa-plus"></i> {{ $t('role.add_user') }}
          </v-btn>
        </div>
        <div class="user-list">
          <div v-for="u in filteredRoleUsers" class="user-item">
            <img :src="u.avatar || '/assets/default-avatar.png'" class="user-avatar" alt="">
            <div class="user-info">
              <div class="user-name">{{ u.nickname || u.username }}</div>
              <div class="user-username">@{{ u.username }}</div>
            </div>
            <v-btn v-if="!currentRole?.is_system" icon size="xs" color="danger" variant="ghost"
              :click="() => removeUserFromRole(u)" :title="$t('common.remove')">
              <i class="fas fa-times"></i>
            </v-btn>
          </div>
          <div v-if="filteredRoleUsers.length === 0" class="empty-state">
            <i class="fas fa-users" style="font-size: 48px; color: var(--text-color-disabled);"></i>
            <p>{{ $t('role.no_users') }}</p>
          </div>
        </div>
      </div>
    </div>
    <div vslot="footer">
      <v-btn variant="outline" :click="closeDetailModal">{{ $t('common.close') }}</v-btn>
    </div>
  </v-dialog>

  <!-- Permission Selector Dialog -->
  <v-dialog v:visible="showPermissionSelector" width="600px" :title="$t('role.select_permissions')">
    <div style="display: flex; flex-direction: column; gap: 16px;">
      <div class="search-box">
        <i class="fas fa-search" style="color: var(--text-color-tertiary);"></i>
        <input type="text" v:value="permissionSearchQuery" :placeholder="$t('role.search_permissions')">
      </div>
      <div class="available-permission-list">
        <div v-for="p in filteredAvailablePermissions" class="available-permission-item">
          <input type="checkbox" :checked="isPermissionSelected(p.id)" @change="togglePermission(p.id)">
          <div class="permission-info">
            <div class="permission-id">{{ p.permission_id }}</div>
            <div class="permission-scope">{{ p.scope }}</div>
          </div>
        </div>
        <div v-if="filteredAvailablePermissions.length === 0" class="empty-state">
          <p>{{ $t('role.no_available_permissions') }}</p>
        </div>
      </div>
    </div>
    <div vslot="footer">
      <v-btn variant="outline" :click="closePermissionSelector">{{ $t('common.cancel') }}</v-btn>
      <v-btn color="primary" :click="saveRolePermissions">{{ $t('common.save') }}</v-btn>
    </div>
  </v-dialog>

  <!-- User Selector Dialog -->
  <v-dialog v:visible="showUserSelector" width="600px" :title="$t('role.select_users')">
    <div style="display: flex; flex-direction: column; gap: 16px;">
      <div class="search-box">
        <i class="fas fa-search" style="color: var(--text-color-tertiary);"></i>
        <input type="text" v:value="availableUserSearchQuery" @input="searchAvailableUsers"
          :placeholder="$t('role.search_users_placeholder')">
      </div>
      <div class="available-user-list">
        <div v-for="u in availableUsers" class="available-user-item">
          <input type="checkbox" :checked="isUserSelected(u.id)" @change="toggleUser(u.id)">
          <img :src="u.avatar || '/assets/default-avatar.png'" class="user-avatar-sm" alt="">
          <div class="user-info">
            <div class="user-name">{{ u.nickname || u.username }}</div>
            <div class="user-username">@{{ u.username }}</div>
          </div>
        </div>
        <div v-if="availableUsers.length === 0" class="empty-state">
          <p>{{ $t('role.no_available_users') }}</p>
        </div>
      </div>
    </div>
    <div vslot="footer">
      <v-btn variant="outline" :click="closeUserSelector">{{ $t('common.cancel') }}</v-btn>
      <v-btn color="primary" :click="saveRoleUsers">{{ $t('common.save') }}</v-btn>
    </div>
  </v-dialog>
</body>
<script setup>
  // Basic data
  roles = [];
  searchQuery = "";
  showModal = false;
  isEdit = false;
  formData = {
    id: null,
    code: "",
    name: "",
    description: ""
  };

  // Detail modal data
  showDetailModal = false;
  detailTab = "permissions";
  currentRole = null;

  // Permissions data
  rolePermissions = [];
  showPermissionSelector = false;
  permissionSearchQuery = "";
  availablePermissions = [];
  selectedPermissionIds = [];

  // Users data
  roleUsers = [];
  userSearchQuery = "";
  showUserSelector = false;
  availableUserSearchQuery = "";
  availableUsers = [];
  selectedUserIds = [];

  loadRoles = async () => {
    try {
      const res = await fetch('/api/roles');
      if (res.status !== 200) {
        const err = await res.json();
        throw new Error(err.message);
      }
      const data = await res.json();
      roles = data.items || [];
    } catch (e) {
      $message.error(e.message);
    }
  };

  filteredRoles = () => {
    if (!searchQuery) return roles;
    const query = searchQuery.toLowerCase();
    return roles.filter(r =>
      r.name.toLowerCase().includes(query) ||
      r.code.toLowerCase().includes(query) ||
      (r.description && r.description.toLowerCase().includes(query))
    );
  };

  openCreateModal = () => {
    isEdit = false;
    formData = {id: null, code: "", name: "", description: ""};
    showModal = true;
  };

  openEditModal = (r) => {
    isEdit = true;
    formData = {...r};
    showModal = true;
  };

  closeModal = () => {
    showModal = false;
  };

  saveRole = async () => {
    if (!formData.code || !formData.name) {
      $message.error($t('org.required_fields'));
      return;
    }
    try {
      if (isEdit) {
        const payload = {
          name: formData.name,
          description: formData.description
        };
        const res = await fetch(`/api/roles/${formData.id}`, {method: 'PATCH', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(payload)});
        if (res.status !== 200) {
          const err = await res.json();
          throw new Error(err.message);
        }
        $message.success($t('org.updated'));
      } else {
        const res = await fetch('/api/roles', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(formData)});
        if (res.status !== 200) {
          const err = await res.json();
          throw new Error(err.message);
        }
        $message.success($t('org.created'));
      }
      closeModal();
      loadRoles();
    } catch (e) {
      $message.error(e.message);
    }
  };

  deleteRole = async (r) => {
    try {
      await $message.confirm($t('role.delete_confirm'));
      const res = await fetch(`/api/roles/${r.id}`, {method: 'DELETE'});
      if (res.status !== 200) {
        const err = await res.json();
        throw new Error(err.message);
      }
      $message.success($t('org.deleted'));
      loadRoles();
    } catch (e) {
      // Cancelled
    }
  };

  // Detail modal functions
  openDetailModal = (r) => {
    currentRole = r;
    detailTab = "permissions";
    showDetailModal = true;
    loadRolePermissions();
    loadRoleUsers();
  };

  closeDetailModal = () => {
    showDetailModal = false;
    currentRole = null;
    rolePermissions = [];
    roleUsers = [];
  };

  switchTab = (tab) => {
    detailTab = tab;
  };

  // Permission functions
  loadRolePermissions = async () => {
    if (!currentRole) return;
    try {
      const res = await fetch(`/api/roles/${currentRole.id}/permissions`);
      if (res.status !== 200) {
        const err = await res.json();
        throw new Error(err.message);
      }
      rolePermissions = res || [];
    } catch (e) {
      $message.error(e.message);
    }
  };

  openPermissionSelector = async () => {
    selectedPermissionIds = rolePermissions.map(p => p.id);
    showPermissionSelector = true;
    await loadAvailablePermissions();
  };

  closePermissionSelector = () => {
    showPermissionSelector = false;
    permissionSearchQuery = "";
    selectedPermissionIds = [];
  };

  loadAvailablePermissions = async () => {
    // Get all permissions from user's own permissions or a dedicated endpoint
    // For now, we'll use a mock approach - in real implementation,
    // you might need a /api/permissions endpoint to list all available permissions
    try {
      // This is a placeholder - adjust based on your actual API
      const res = await fetch('/api/auth/me');
      if (res.status !== 200) {
        const err = await res.json();
        throw new Error(err.message);
      }
      const me = await res.json();
      if (me.permissions) {
        // Extract unique permission IDs
        const uniquePerms = [];
        const seen = new Set();
        me.permissions.forEach(p => {
          if (!seen.has(p.permission_id)) {
            seen.add(p.permission_id);
            uniquePerms.push({
              id: p.permission_id,
              permission_id: p.permission_id,
              scope: p.scope,
              level: p.level
            });
          }
        });
        availablePermissions = uniquePerms;
      }
    } catch (e) {
      // Fallback: use current role permissions as base
      availablePermissions = rolePermissions.map(p => ({
        id: p.id,
        permission_id: p.permission_id,
        scope: p.scope,
        level: p.level
      }));
    }
  };

  filteredAvailablePermissions = () => {
    if (!permissionSearchQuery) return availablePermissions;
    const query = permissionSearchQuery.toLowerCase();
    return availablePermissions.filter(p =>
      p.permission_id.toLowerCase().includes(query) ||
      p.scope.toLowerCase().includes(query)
    );
  };

  isPermissionSelected = (id) => {
    return selectedPermissionIds.includes(id);
  };

  togglePermission = (id) => {
    const idx = selectedPermissionIds.indexOf(id);
    if (idx > -1) {
      selectedPermissionIds.splice(idx, 1);
    } else {
      selectedPermissionIds.push(id);
    }
    // Trigger reactivity
    selectedPermissionIds = [...selectedPermissionIds];
  };

  saveRolePermissions = async () => {
    if (!currentRole) return;
    try {
      const res = await fetch(`/api/roles/${currentRole.id}/permissions`, {
        method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({
          permission_ids: selectedPermissionIds
        })
      });
      if (res.status !== 200) {
        const err = await res.json();
        throw new Error(err.message);
      }
      $message.success($t('role.permissions_updated'));
      closePermissionSelector();
      loadRolePermissions();
    } catch (e) {
      $message.error(e.message);
    }
  };

  removePermission = async (p) => {
    if (!currentRole || currentRole.is_system) return;
    try {
      await $message.confirm($t('role.remove_permission_confirm'));
      const newPermissions = rolePermissions
        .filter(rp => rp.id !== p.id)
        .map(rp => rp.id);
      const res = await fetch(`/api/roles/${currentRole.id}/permissions`, {
        method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({
          permission_ids: newPermissions
        })
      });
      if (res.status !== 200) {
        const err = await res.json();
        throw new Error(err.message);
      }
      $message.success($t('role.permission_removed'));
      loadRolePermissions();
    } catch (e) {
      // Cancelled or error
    }
  };

  formatLevel = (level) => {
    const levels = {
      1: $t('permission.level.create') || 'Create',
      2: $t('permission.level.read') || 'Read',
      4: $t('permission.level.write') || 'Write',
      6: $t('permission.level.rw') || 'Read+Write',
      7: $t('permission.level.admin') || 'Admin'
    };
    return levels[level] || `Level ${level}`;
  };

  // User functions
  loadRoleUsers = async () => {
    if (!currentRole) return;
    try {
      // Get users who have this role
      // We need to fetch users and filter by role
      const params = new URLSearchParams({page_size: 1000});
      let res = await fetch('/api/users?' + params);
      if (res.status !== 200) {
        const err = await res.json();
        throw new Error(err.message);
      }
      const data = await res.json();
      const allUsers = data.items || [];
      // For each user, check if they have this role
      const usersWithRole = [];
      for (const user of allUsers) {
        try {
          res = await fetch(`/api/users/${user.id}/roles`);
          if (res.status !== 200) {
            const err = await res.json();
            throw new Error(err.message);
          }
          const userRoles = await res.json();
          if (userRoles.some(ur => ur.id === currentRole.id)) {
            usersWithRole.push(user);
          }
        } catch (e) {
          // Skip users we can't check
        }
      }
      roleUsers = usersWithRole;
    } catch (e) {
      $message.error(e.message);
    }
  };

  filteredRoleUsers = () => {
    if (!userSearchQuery) return roleUsers;
    const query = userSearchQuery.toLowerCase();
    return roleUsers.filter(u =>
      (u.nickname || u.username).toLowerCase().includes(query) ||
      u.username.toLowerCase().includes(query)
    );
  };

  openUserSelector = async () => {
    selectedUserIds = roleUsers.map(u => u.id);
    showUserSelector = true;
    await searchAvailableUsers();
  };

  closeUserSelector = () => {
    showUserSelector = false;
    availableUserSearchQuery = "";
    availableUsers = [];
    selectedUserIds = [];
  };

  searchAvailableUsers = async () => {
    try {
      const params = new URLSearchParams({keyword: availableUserSearchQuery, limit: 50});
      const res = await fetch('/api/auth/users?' + params);
      const json_ = await res.json();
      if (json_.code !== 200) throw new Error(json_.message);
      availableUsers = json_.data?.items || [];
    } catch (e) {
      $message.error(e.message);
    }
  };

  isUserSelected = (id) => {
    return selectedUserIds.includes(id);
  };

  toggleUser = (id) => {
    const idx = selectedUserIds.indexOf(id);
    if (idx > -1) {
      selectedUserIds.splice(idx, 1);
    } else {
      selectedUserIds.push(id);
    }
    // Trigger reactivity
    selectedUserIds = [...selectedUserIds];
  };

  saveRoleUsers = async () => {
    if (!currentRole) return;
    try {
      // Update each user's roles
      const currentUserIds = roleUsers.map(u => u.id);

      // Users to add
      const toAdd = selectedUserIds.filter(id => !currentUserIds.includes(id));
      // Users to remove
      const toRemove = currentUserIds.filter(id => !selectedUserIds.includes(id));

      let res = null
      for (const userId of toAdd) {
        res = await fetch(`/api/users/${userId}/roles`);
        if (res.status !== 200) {
          const err = await res.json();
          throw new Error(err.message);
        }
        const userRoles = await res.json();
        const roleIds = [...userRoles.map(r => r.id), currentRole.id];
        res = await fetch(`/api/users/${userId}/roles`, {method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({role_ids: roleIds})});
        if (res.status !== 200) {
          const err = await res.json();
          throw new Error(err.message);
        }
      }

      for (const userId of toRemove) {
        res = await fetch(`/api/users/${userId}/roles`);
        if (res.status !== 200) {
          const err = await res.json();
          throw new Error(err.message);
        }
        const userRoles = await res.json();
        const roleIds = userRoles.filter(r => r.id !== currentRole.id).map(r => r.id);
        res = await fetch(`/api/users/${userId}/roles`, {method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({role_ids: roleIds})});
        if (res.status !== 200) {
          const err = await res.json();
          throw new Error(err.message);
        }
      }

      $message.success($t('role.users_updated'));
      closeUserSelector();
      loadRoleUsers();
    } catch (e) {
      $message.error(e.message);
    }
  };

  removeUserFromRole = async (u) => {
    if (!currentRole || currentRole.is_system) return;
    try {
      await $message.confirm($t('role.remove_user_confirm'));
      let res = await fetch(`/api/users/${u.id}/roles`);
      if (res.status !== 200) {
        const err = await res.json();
        throw new Error(err.message);
      }
      const userRoles = await res.json();
      const roleIds = userRoles.filter(r => r.id !== currentRole.id).map(r => r.id);
      res = await fetch(`/api/users/${u.id}/roles`, {method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({role_ids: roleIds})});
      if (res.status !== 200) {
        const err = await res.json();
        throw new Error(err.message);
      }
      $message.success($t('role.user_removed'));
      loadRoleUsers();
    } catch (e) {
      // Cancelled or error
    }
  };
</script>
<script>
  $data.loadRoles();
</script>

</html>
