using System.Collections.ObjectModel; using System.Windows; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using Microsoft.Extensions.Logging; using SharepointToolbox.Core.Messages; using SharepointToolbox.Core.Models; using SharepointToolbox.Services; using SharepointToolbox.Views.Dialogs; namespace SharepointToolbox.ViewModels; public partial class MainWindowViewModel : ObservableRecipient { private readonly ProfileService _profileService; private readonly SessionManager _sessionManager; private readonly ILogger _logger; // Set by the view layer (MainWindow.xaml.cs) to open the dialog using DI public Func? OpenProfileManagementDialog { get; set; } /// /// Factory set by MainWindow.xaml.cs to open the SitePickerDialog for global site selection. /// Returns the opened Window; ViewModel calls ShowDialog() on it. /// public Func? OpenGlobalSitePickerDialog { get; set; } [ObservableProperty] private TenantProfile? _selectedProfile; [ObservableProperty] private string _connectionStatus = "Not connected"; [ObservableProperty] private string _progressStatus = string.Empty; [ObservableProperty] private int _progressPercentage; public ObservableCollection TenantProfiles { get; } = new(); public ObservableCollection GlobalSelectedSites { get; } = new(); /// /// Label for toolbar display: "3 site(s) selected" or "No sites selected". /// public string GlobalSitesSelectedLabel => GlobalSelectedSites.Count > 0 ? $"{GlobalSelectedSites.Count} site(s) selected" : "No sites selected"; public IAsyncRelayCommand ConnectCommand { get; } public IAsyncRelayCommand ClearSessionCommand { get; } public RelayCommand ManageProfilesCommand { get; } public RelayCommand OpenGlobalSitePickerCommand { get; } public MainWindowViewModel( ProfileService profileService, SessionManager sessionManager, ILogger logger) { _profileService = profileService; _sessionManager = sessionManager; _logger = logger; ConnectCommand = new AsyncRelayCommand(ConnectAsync, () => SelectedProfile != null); ClearSessionCommand = new AsyncRelayCommand(ClearSessionAsync, () => SelectedProfile != null); ManageProfilesCommand = new RelayCommand(OpenProfileManagement); OpenGlobalSitePickerCommand = new RelayCommand(ExecuteOpenGlobalSitePicker, () => SelectedProfile != null); GlobalSelectedSites.CollectionChanged += (_, _) => { OnPropertyChanged(nameof(GlobalSitesSelectedLabel)); BroadcastGlobalSites(); }; IsActive = true; } protected override void OnActivated() { base.OnActivated(); Messenger.Register(this, (r, m) => { var vm = (MainWindowViewModel)r; vm.ProgressStatus = m.Value.Message; vm.ProgressPercentage = m.Value.Total > 0 ? (int)(100.0 * m.Value.Current / m.Value.Total) : 0; }); } partial void OnSelectedProfileChanged(TenantProfile? value) { if (value != null) { WeakReferenceMessenger.Default.Send(new TenantSwitchedMessage(value)); } ConnectCommand.NotifyCanExecuteChanged(); ClearSessionCommand.NotifyCanExecuteChanged(); // Clear global site selection on tenant switch (sites belong to a tenant) GlobalSelectedSites.Clear(); OpenGlobalSitePickerCommand.NotifyCanExecuteChanged(); } public async Task LoadProfilesAsync() { try { var profiles = await _profileService.GetProfilesAsync(); TenantProfiles.Clear(); foreach (var profile in profiles) TenantProfiles.Add(profile); if (TenantProfiles.Count > 0) SelectedProfile = TenantProfiles[0]; } catch (Exception ex) { _logger.LogError(ex, "Failed to load tenant profiles."); } } private async Task ConnectAsync() { if (SelectedProfile == null) return; try { ConnectionStatus = "Connecting..."; await _sessionManager.GetOrCreateContextAsync(SelectedProfile, CancellationToken.None); ConnectionStatus = SelectedProfile.Name; } catch (Exception ex) { ConnectionStatus = "Connection failed"; _logger.LogError(ex, "Failed to connect to tenant {TenantUrl}.", SelectedProfile.TenantUrl); } } private async Task ClearSessionAsync() { if (SelectedProfile == null) return; try { await _sessionManager.ClearSessionAsync(SelectedProfile.TenantUrl); GlobalSelectedSites.Clear(); ConnectionStatus = "Not connected"; } catch (Exception ex) { _logger.LogError(ex, "Failed to clear session for {TenantUrl}.", SelectedProfile.TenantUrl); } } private void OpenProfileManagement() { if (OpenProfileManagementDialog == null) return; var dialog = OpenProfileManagementDialog(); dialog.Owner = Application.Current.MainWindow; dialog.ShowDialog(); // Reload profiles after dialog closes (modal — ShowDialog blocks until closed) _ = LoadProfilesAsync(); } private void ExecuteOpenGlobalSitePicker() { if (OpenGlobalSitePickerDialog == null) return; var dialog = OpenGlobalSitePickerDialog.Invoke(); if (dialog?.ShowDialog() == true && dialog is SitePickerDialog picker) { GlobalSelectedSites.Clear(); foreach (var site in picker.SelectedUrls) GlobalSelectedSites.Add(site); } } private void BroadcastGlobalSites() { WeakReferenceMessenger.Default.Send( new GlobalSitesChangedMessage(GlobalSelectedSites.ToList().AsReadOnly())); } }