using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using NetDocsForLLM.Models; using NetDocsForLLM.Services; using Ookii.Dialogs.Wpf; using System; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows; namespace NetDocsForLLM.ViewModels { public partial class MainViewModel : ObservableObject { private readonly IAssemblyAnalyzer _assemblyAnalyzer; private readonly IDocumentationGenerator _documentationGenerator; private ObservableCollection _selectedAssemblies; private DocumentationModel _documentationModel; private ExportSettings _settings; private string _documentationPreview; private string _documentationStats; private string _statusMessage; private bool _isProcessing; [ObservableProperty] private bool _hasGeneratedDocumentation; public ObservableCollection SelectedAssemblies { get => _selectedAssemblies; set => SetProperty(ref _selectedAssemblies, value); } public DocumentationModel DocumentationModel { get => _documentationModel; set => SetProperty(ref _documentationModel, value); } public ExportSettings Settings { get => _settings; set => SetProperty(ref _settings, value); } public string DocumentationPreview { get => _documentationPreview; set => SetProperty(ref _documentationPreview, value); } public string DocumentationStats { get => _documentationStats; set => SetProperty(ref _documentationStats, value); } public string StatusMessage { get => _statusMessage; set => SetProperty(ref _statusMessage, value); } public bool IsProcessing { get => _isProcessing; set => SetProperty(ref _isProcessing, value); } public bool HasSelectedAssemblies => SelectedAssemblies.Count > 0; // Comandos public IRelayCommand SelectAssembliesCommand { get; } public IRelayCommand RemoveAssemblyCommand { get; } public IRelayCommand GenerateDocumentationCommand { get; } // Estos campos se actualizan desde propiedades computadas private IRelayCommand _copyToClipboardCommand; private IRelayCommand _exportDocumentationCommand; // Redefine los comandos con canExecute actualizado public IRelayCommand CopyToClipboardCommand => _copyToClipboardCommand ??= new RelayCommand(CopyToClipboard, () => HasGeneratedDocumentation); public IRelayCommand ExportDocumentationCommand => _exportDocumentationCommand ??= new RelayCommand(ExportDocumentation, () => HasGeneratedDocumentation); // Constructor public MainViewModel(IAssemblyAnalyzer assemblyAnalyzer, IDocumentationGenerator documentationGenerator) { _assemblyAnalyzer = assemblyAnalyzer ?? throw new ArgumentNullException(nameof(assemblyAnalyzer)); _documentationGenerator = documentationGenerator ?? throw new ArgumentNullException(nameof(documentationGenerator)); _selectedAssemblies = new ObservableCollection(); _documentationModel = new DocumentationModel(); _settings = new ExportSettings(); _documentationPreview = string.Empty; _documentationStats = string.Empty; _statusMessage = "Listo"; _isProcessing = false; _hasGeneratedDocumentation = false; SelectAssembliesCommand = new RelayCommand(SelectAssemblies); RemoveAssemblyCommand = new RelayCommand(RemoveAssembly); GenerateDocumentationCommand = new AsyncRelayCommand(GenerateDocumentationAsync); // Subscribe to collection changes to update HasSelectedAssemblies _selectedAssemblies.CollectionChanged += (sender, e) => { OnPropertyChanged(nameof(HasSelectedAssemblies)); }; } // Asegúrate de que UpdateCanExecuteForCommands se llame cuando cambie HasGeneratedDocumentation partial void OnHasGeneratedDocumentationChanged(bool value) { UpdateCanExecuteForCommands(); } // Método para actualizar el CanExecute de los comandos private void UpdateCanExecuteForCommands() { (CopyToClipboardCommand as RelayCommand)?.NotifyCanExecuteChanged(); (ExportDocumentationCommand as RelayCommand)?.NotifyCanExecuteChanged(); } private void SelectAssemblies() { var dialog = new VistaOpenFileDialog { Filter = "Ensamblados .NET (*.dll)|*.dll", Multiselect = true, Title = "Seleccionar librerías .NET" }; if (dialog.ShowDialog() == true) { foreach (var filePath in dialog.FileNames) { try { // Check if the assembly is already selected if (_selectedAssemblies.Any(a => a.FilePath == filePath)) continue; var assembly = _assemblyAnalyzer.LoadAssembly(filePath); if (assembly != null) { SelectedAssemblies.Add(assembly); StatusMessage = $"Librería cargada: {assembly.Name}"; } } catch (Exception ex) { MessageBox.Show($"Error al cargar el ensamblado: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } } } private void RemoveAssembly(AssemblyModel assembly) { if (assembly != null) { SelectedAssemblies.Remove(assembly); StatusMessage = $"Librería removida: {assembly.Name}"; } } private async Task GenerateDocumentationAsync() { if (SelectedAssemblies.Count == 0) { MessageBox.Show("Por favor, seleccione al menos una librería para generar documentación.", "Sin librerías", MessageBoxButton.OK, MessageBoxImage.Information); return; } try { IsProcessing = true; StatusMessage = "Generando documentación..."; // Generate documentation DocumentationModel = await Task.Run(() => _documentationGenerator.GenerateDocumentation(SelectedAssemblies, Settings)); // Generate preview DocumentationPreview = await Task.Run(() => _documentationGenerator.GenerateDocumentationPreview(DocumentationModel, Settings)); // Update stats var totalTypes = DocumentationModel.Namespaces.Sum(n => n.Types.Count); var totalMembers = DocumentationModel.Namespaces.Sum(n => n.Types.Sum(t => t.Members.Count)); DocumentationStats = $"Resumen: {DocumentationModel.Namespaces.Count} namespaces, " + $"{totalTypes} tipos, {totalMembers} miembros"; // Estas dos líneas son cruciales - aseguran que HasGeneratedDocumentation se actualice // y que los comandos se habiliten HasGeneratedDocumentation = true; UpdateCanExecuteForCommands(); StatusMessage = "Documentación generada correctamente"; } catch (Exception ex) { MessageBox.Show($"Error al generar la documentación: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); StatusMessage = "Error al generar documentación"; } finally { IsProcessing = false; } } private void CopyToClipboard() { if (string.IsNullOrEmpty(DocumentationPreview)) return; try { Clipboard.SetText(DocumentationPreview); StatusMessage = "Documentación copiada al portapapeles"; } catch (Exception ex) { MessageBox.Show($"Error al copiar al portapapeles: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } private void ExportDocumentation() { if (string.IsNullOrEmpty(DocumentationPreview)) return; // Determinar extensión y filtro basado en formato seleccionado string extension; string filter; switch (Settings.OutputFormat) { case OutputFormat.Xml: extension = ".xml"; filter = "Archivos XML (*.xml)|*.xml"; break; case OutputFormat.Json: extension = ".json"; filter = "Archivos JSON (*.json)|*.json"; break; case OutputFormat.Yaml: default: extension = ".yaml"; filter = "Archivos YAML (*.yaml;*.yml)|*.yaml;*.yml"; break; } var dialog = new VistaSaveFileDialog { Filter = filter, DefaultExt = extension, Title = "Guardar documentación", OverwritePrompt = true }; if (dialog.ShowDialog() == true) { try { File.WriteAllText(dialog.FileName, DocumentationPreview); StatusMessage = $"Documentación guardada en: {dialog.FileName}"; } catch (Exception ex) { MessageBox.Show($"Error al guardar el archivo: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } } } }