using System; using System.Collections.ObjectModel; using System.Windows; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using HC_APTBS.Services; using HC_APTBS.Views.Dialogs; namespace HC_APTBS.ViewModels.Dialogs { /// /// ViewModel for the user management dialog. /// Invokes incremental methods on /// (AddUser, RemoveUser, ChangeUserPassword) so that /// hashes of untouched accounts are preserved. Each action persists immediately; /// the dialog has no Accept/Cancel split — Close simply dismisses the window. /// public sealed partial class UserManageViewModel : ObservableObject { private readonly IConfigurationService _config; private readonly ILocalizationService _loc; /// Creates the ViewModel and populates from the service. public UserManageViewModel(IConfigurationService config, ILocalizationService loc) { _config = config; _loc = loc; ReloadUsers(); } // ── Bindable state ──────────────────────────────────────────────────── /// Usernames currently stored in the configuration. public ObservableCollection Users { get; } = new(); /// Currently selected username in the DataGrid, or null when nothing is selected. [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(RemoveCommand))] [NotifyCanExecuteChangedFor(nameof(ChangePasswordCommand))] private string? _selectedUser; /// Raised to close the owning dialog window. public event Action? RequestClose; // ── Commands ────────────────────────────────────────────────────────── /// Prompts for a username and password, then adds the user via the service. [RelayCommand] private void Add() { var prompt = new UserPromptDialog( _loc.GetString("Dialog.UserManage.Prompt.AddTitle"), usernameVisible: true) { Owner = Application.Current?.Windows.Count > 0 ? GetActiveWindow() : null }; if (prompt.ShowDialog() != true) return; string username = prompt.EnteredUsername?.Trim() ?? string.Empty; string password = prompt.EnteredPassword ?? string.Empty; if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) { ShowError("Dialog.UserManage.Error.Empty", "Dialog.UserManage.Error.EmptyTitle"); return; } if (username.IndexOfAny(new[] { ':', ',' }) >= 0) { ShowError("Dialog.UserManage.Error.InvalidChars", "Dialog.UserManage.Error.InvalidCharsTitle"); return; } if (!_config.AddUser(username, password)) { ShowError("Dialog.UserManage.Error.Duplicate", "Dialog.UserManage.Error.DuplicateTitle"); return; } ReloadUsers(); SelectedUser = username; } /// Removes the selected user after confirmation, refusing when only one user remains. [RelayCommand(CanExecute = nameof(HasSelection))] private void Remove() { string user = SelectedUser!; var confirm = MessageBox.Show( string.Format(_loc.GetString("Dialog.UserManage.Confirm.Remove"), user), _loc.GetString("Dialog.UserManage.Confirm.RemoveTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question); if (confirm != MessageBoxResult.Yes) return; if (!_config.RemoveUser(user)) { ShowError("Dialog.UserManage.Error.LastUser", "Dialog.UserManage.Error.LastUserTitle"); return; } ReloadUsers(); } /// Prompts for a new password for the selected user and applies it. [RelayCommand(CanExecute = nameof(HasSelection))] private void ChangePassword() { string user = SelectedUser!; var prompt = new UserPromptDialog( string.Format(_loc.GetString("Dialog.UserManage.Prompt.ChangeTitle"), user), usernameVisible: false, prefillUsername: user) { Owner = GetActiveWindow() }; if (prompt.ShowDialog() != true) return; string newPassword = prompt.EnteredPassword ?? string.Empty; if (string.IsNullOrEmpty(newPassword)) { ShowError("Dialog.UserManage.Error.Empty", "Dialog.UserManage.Error.EmptyTitle"); return; } if (!_config.ChangeUserPassword(user, newPassword)) { ShowError("Dialog.UserManage.Error.Empty", "Dialog.UserManage.Error.EmptyTitle"); return; } } /// Closes the dialog. [RelayCommand] private void Close() => RequestClose?.Invoke(); // ── Helpers ─────────────────────────────────────────────────────────── private bool HasSelection() => !string.IsNullOrEmpty(SelectedUser); /// Reloads the user list from the service, preserving selection when possible. private void ReloadUsers() { string? previous = SelectedUser; Users.Clear(); foreach (var name in _config.GetUsers()) Users.Add(name); SelectedUser = (previous != null && Users.Contains(previous)) ? previous : null; } private void ShowError(string messageKey, string titleKey) { MessageBox.Show( _loc.GetString(messageKey), _loc.GetString(titleKey), MessageBoxButton.OK, MessageBoxImage.Stop); } /// Returns the topmost active window for use as a dialog owner, or null if none. private static Window? GetActiveWindow() { foreach (Window w in Application.Current.Windows) { if (w.IsActive) return w; } return Application.Current.MainWindow; } } }