using System.Collections.ObjectModel; using System.Windows.Controls; using ClaudeDo.Installer.Checks; using ClaudeDo.Installer.Core; using ClaudeDo.Installer.Localization; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace ClaudeDo.Installer.Pages.SystemCheckPage; public partial class SystemCheckPageViewModel : ObservableObject, IInstallerPage { private readonly InstallContext _context; private readonly ClaudeHelpLauncher _claudeHelpLauncher; private SystemCheckPageView? _view; private bool _hasStarted; public string Title => TrExtension.Localizer?["installer.systemCheck.title"] ?? "System Check"; public string Icon => ""; public int Order => 1; public bool ShowInWizard => true; public bool ShowInSettings => false; public UserControl View => _view ??= new SystemCheckPageView { DataContext = this }; public CheckListViewModel Checks { get; } // Pass-through to the shared check-run logic — kept so this page's UI/tests can bind // directly on it, matching the pre-extraction API. public ObservableCollection Rows => Checks.Rows; public bool IsRunning => Checks.IsRunning; public bool HasRun => Checks.HasRun; public bool HasBlockingError => Checks.HasBlockingError; public string Summary => Checks.Summary; public IAsyncRelayCommand RunChecksCommand => Checks.RunChecksCommand; public bool BlocksNavigation => Checks.IsRunning || Checks.HasBlockingError; [ObservableProperty] private string? _claudeHelpError; public bool ClaudeCliOk => Checks.LastReport?.Results.FirstOrDefault(r => r.Id == ClaudeCliCheck.CheckId)?.Status == CheckStatus.Ok; public bool ClaudeAuthFailed => Checks.LastReport?.Results.FirstOrDefault(r => r.Id == ClaudeAuthCheck.CheckId)?.Status == CheckStatus.Failed; public bool CanStartClaudeHelp => ClaudeCliOk && !ClaudeAuthFailed; public string ClaudeHelpTooltip { get { var loc = TrExtension.Localizer; if (!ClaudeCliOk) return loc?["installer.systemCheck.claudeHelp.tooltip.cliMissing"] ?? "The Claude CLI was not found."; if (ClaudeAuthFailed) return loc?["installer.systemCheck.claudeHelp.tooltip.notLoggedIn"] ?? "Claude is not logged in."; return loc?["installer.systemCheck.claudeHelp.tooltip.ready"] ?? "Start an interactive Claude session to help troubleshoot your setup."; } } public SystemCheckPageViewModel( InstallContext context, Func checkServiceFactory, ClaudeHelpLauncher claudeHelpLauncher) { _context = context; _claudeHelpLauncher = claudeHelpLauncher; Checks = new CheckListViewModel(context, checkServiceFactory); // The wizard listens for PropertyChanged on this page to re-evaluate "Next" — bubble // any change from the composed check list up so a live recheck can flip it back, and so // the Claude-Help gating re-reads the fresh report. Checks.PropertyChanged += (_, _) => { OnPropertyChanged(nameof(BlocksNavigation)); OnPropertyChanged(nameof(ClaudeCliOk)); OnPropertyChanged(nameof(ClaudeAuthFailed)); OnPropertyChanged(nameof(CanStartClaudeHelp)); OnPropertyChanged(nameof(ClaudeHelpTooltip)); StartClaudeHelpCommand.NotifyCanExecuteChanged(); }; } public Task LoadAsync() { if (!_hasStarted) { _hasStarted = true; _ = Checks.RunChecksCommand.ExecuteAsync(null); } return Task.CompletedTask; } public Task ApplyAsync() => Task.CompletedTask; public bool Validate() => !HasBlockingError; [RelayCommand(CanExecute = nameof(CanStartClaudeHelp))] private async Task StartClaudeHelpAsync() { if (Checks.LastReport is null) return; ClaudeHelpError = null; var result = await _claudeHelpLauncher.LaunchAsync(Checks.LastReport, _context, CancellationToken.None); if (!result.Success) { ClaudeHelpError = TrExtension.Localizer?.Get("installer.systemCheck.claudeHelp.error", result.ErrorMessage ?? "") ?? $"Could not start the Claude session: {result.ErrorMessage}"; } } }