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;
}
}
}