88 "github.com/Tomas-vilte/MateCommit/internal/domain/models"
99 "github.com/Tomas-vilte/MateCommit/internal/domain/ports"
1010 "github.com/Tomas-vilte/MateCommit/internal/i18n"
11+ "github.com/Tomas-vilte/MateCommit/internal/ui"
12+ "github.com/fatih/color"
1113)
1214
1315var _ ports.CommitHandler = (* SuggestionHandler )(nil )
@@ -30,65 +32,132 @@ func (h *SuggestionHandler) HandleSuggestions(ctx context.Context, suggestions [
3032}
3133
3234func (h * SuggestionHandler ) displaySuggestions (suggestions []models.CommitSuggestion ) {
33- fmt .Printf ("%s\n " , h .t .GetMessage ("commit.header_message" , 0 , nil ))
35+ titleColor := color .New (color .FgCyan , color .Bold )
36+ sectionColor := color .New (color .FgYellow , color .Bold )
37+ fileColor := color .New (color .FgHiBlack )
38+
39+ fmt .Printf ("\n %s\n " , h .t .GetMessage ("commit.header_message" , 0 , nil ))
3440
3541 for i , suggestion := range suggestions {
36- suggestionHeader := h .t .GetMessage ("suggestion_header" , 0 , map [string ]interface {}{"Number" : i + 1 })
37- fmt .Printf ("\n %s\n " , suggestionHeader )
42+ // Separador visual
43+ separator := color .New (color .FgCyan ).Sprint ("━━━━━━━━━━━━━━━━━━━━━━━" )
44+ fmt .Printf ("\n %s\n " , separator )
45+
46+ // Header con número
47+ suggestionHeader := color .New (color .FgMagenta , color .Bold ).Sprintf ("📝 Sugerencia #%d" , i + 1 )
48+ fmt .Printf ("%s\n \n " , suggestionHeader )
3849
39- fmt .Printf ("\n %s\n " , h .t .GetMessage ("gemini_service.code_analysis_prefix" , 0 , nil ))
40- fmt .Printf ("%s %s\n " , h .t .GetMessage ("gemini_service.changes_overview_prefix" , 0 , nil ), suggestion .CodeAnalysis .ChangesOverview )
41- fmt .Printf ("%s %s\n " , h .t .GetMessage ("gemini_service.primary_purpose_prefix" , 0 , nil ), suggestion .CodeAnalysis .PrimaryPurpose )
42- fmt .Printf ("%s %s\n " , h .t .GetMessage ("gemini_service.technical_impact_prefix" , 0 , nil ), suggestion .CodeAnalysis .TechnicalImpact )
50+ // Análisis de Código
51+ sectionColor .Println ("📊 Análisis de Código:" )
52+ ui .PrintKeyValue ("Resumen de Cambios" , suggestion .CodeAnalysis .ChangesOverview )
53+ ui .PrintKeyValue ("Propósito Principal" , suggestion .CodeAnalysis .PrimaryPurpose )
54+ ui .PrintKeyValue ("Impacto Técnico" , suggestion .CodeAnalysis .TechnicalImpact )
55+
56+ fmt .Println ()
57+ fmt .Printf ("%s\n " , separator )
4358
44- fmt .Println ("━━━━━━━━━━━━━━━━━━━━━━━" )
45- fmt .Printf ("Commit: %s\n " , suggestion .CommitTitle )
59+ // Commit title destacado
60+ fmt .Printf ("%s %s\n \n " ,
61+ color .New (color .FgGreen , color .Bold ).Sprint ("✓ Commit:" ),
62+ titleColor .Sprint (suggestion .CommitTitle ),
63+ )
4664
47- fmt .Println (h .t .GetMessage ("gemini_service.modified_files_prefix" , 0 , nil ))
65+ // Archivos modificados con icono
66+ sectionColor .Println ("📄 Archivos modificados:" )
4867 for _ , file := range suggestion .Files {
49- fmt .Printf (" - %s\n " , file )
68+ fmt .Printf (" %s %s\n " , color . CyanString ( "•" ), fileColor . Sprint ( file ) )
5069 }
51- fmt .Printf ("%s %s\n " , h .t .GetMessage ("gemini_service.explanation_prefix" , 0 , nil ), suggestion .Explanation )
52- fmt .Println ()
70+
71+ // Explicación
72+ fmt .Printf ("\n %s %s\n " ,
73+ sectionColor .Sprint ("💬 Explicación:" ),
74+ suggestion .Explanation ,
75+ )
76+ fmt .Println () // Espacio extra
5377
5478 if suggestion .RequirementsAnalysis .CriteriaStatus != "" {
55- fmt .Printf ("%s\n " , h .t .GetMessage ("gemini_service.requirements_analysis_prefix" , 0 , nil ))
56- statusMsg := h .t .GetMessage ("gemini_service.criteria_status_full" , 0 , map [string ]interface {}{
57- "Status" : h .getCriteriaStatusText (suggestion .RequirementsAnalysis .CriteriaStatus ),
58- })
59- fmt .Printf ("%s\n " , statusMsg )
60- fmt .Println ()
61-
62- if len (suggestion .RequirementsAnalysis .MissingCriteria ) > 0 {
63- fmt .Printf ("\n %s" , h .t .GetMessage ("gemini_service.missing_criteria_prefix" , 0 , nil ))
64- for _ , criteria := range suggestion .RequirementsAnalysis .MissingCriteria {
65- fmt .Printf ("\n - %s\n " , criteria )
66- }
67- }
68-
69- if len (suggestion .RequirementsAnalysis .ImprovementSuggestions ) > 0 {
70- fmt .Printf ("\n %s" , h .t .GetMessage ("gemini_service.improvement_suggestions_prefix" , 0 , nil ))
71- for _ , improvement := range suggestion .RequirementsAnalysis .ImprovementSuggestions {
72- fmt .Printf ("\n - %s" , improvement )
73- }
74- fmt .Println ()
75- }
79+ h .displayRequirementsAnalysis (suggestion .RequirementsAnalysis )
7680 } else {
77- fmt .Printf ("%s\n " , h .t .GetMessage ("gemini_service.technical_analysis_section" , 0 , nil ))
78- if len (suggestion .RequirementsAnalysis .ImprovementSuggestions ) > 0 {
79- fmt .Println (h .t .GetMessage ("gemini_service.improvement_suggestions_label" , 0 , nil ))
80- for _ , improvement := range suggestion .RequirementsAnalysis .ImprovementSuggestions {
81- fmt .Printf (" - %s\n " , improvement )
82- }
83- }
81+ h .displayTechnicalAnalysis (suggestion .RequirementsAnalysis )
82+ }
83+
84+ fmt .Printf ("%s\n " , separator )
85+ }
86+
87+ // Opciones de selección con estilo
88+ fmt .Println ()
89+ ui .PrintInfo (h .t .GetMessage ("ui_selection.select_option" , 0 , nil ))
90+ fmt .Printf (" %s %s\n " , color .GreenString ("1-%d:" , len (suggestions )), h .t .GetMessage ("ui_selection.select_suggestion_range" , 0 , nil ))
91+ fmt .Printf (" %s %s\n " , color .RedString ("0:" ), h .t .GetMessage ("ui_selection.cancel_operation" , 0 , nil ))
92+ fmt .Println ()
93+ }
94+
95+ func (h * SuggestionHandler ) displayRequirementsAnalysis (analysis models.RequirementsAnalysis ) {
96+ reqColor := color .New (color .FgMagenta , color .Bold )
97+
98+ fmt .Printf ("%s\n " , reqColor .Sprint ("🎯 Análisis de Requerimientos:" ))
99+
100+ // Status con emoji según el estado
101+ statusText := h .getCriteriaStatusText (analysis .CriteriaStatus )
102+ statusEmoji := h .getCriteriaStatusEmoji (analysis .CriteriaStatus )
103+ statusColor := h .getCriteriaStatusColor (analysis .CriteriaStatus )
104+
105+ fmt .Printf (" %s %s %s\n " , statusEmoji , color .New (color .FgHiBlack ).Sprint ("Estado:" ),
106+ statusColor .Sprint (statusText ))
107+
108+ if len (analysis .MissingCriteria ) > 0 {
109+ fmt .Printf ("\n %s %s\n " , color .RedString ("❌" ), color .New (color .FgRed ,
110+ color .Bold ).Sprint ("Criterios Faltantes:" ))
111+ for _ , criteria := range analysis .MissingCriteria {
112+ fmt .Printf (" %s %s\n " , color .RedString ("•" ), criteria )
113+ }
114+ }
115+
116+ if len (analysis .ImprovementSuggestions ) > 0 {
117+ fmt .Printf ("\n %s %s\n " , color .YellowString ("💡" ), color .New (color .FgYellow ,
118+ color .Bold ).Sprint ("Sugerencias de Mejora:" ))
119+ for _ , improvement := range analysis .ImprovementSuggestions {
120+ fmt .Printf (" %s %s\n " , color .YellowString ("•" ), improvement )
121+ }
122+ fmt .Println ()
123+ }
124+ }
125+
126+ func (h * SuggestionHandler ) displayTechnicalAnalysis (analysis models.RequirementsAnalysis ) {
127+ if len (analysis .ImprovementSuggestions ) > 0 {
128+ techColor := color .New (color .FgBlue , color .Bold )
129+ fmt .Printf ("%s\n " , techColor .Sprint ("🔧 Análisis Técnico:" ))
130+ for _ , improvement := range analysis .ImprovementSuggestions {
131+ fmt .Printf (" %s %s\n " , color .CyanString ("•" ), improvement )
84132 }
133+ fmt .Println ()
134+ }
135+ }
85136
86- fmt .Println ("━━━━━━━━━━━━━━━━━━━━━━━" )
137+ func (h * SuggestionHandler ) getCriteriaStatusEmoji (status models.CriteriaStatus ) string {
138+ switch status {
139+ case models .CriteriaFullyMet :
140+ return "✅"
141+ case models .CriteriaPartiallyMet :
142+ return "⚠️"
143+ case models .CriteriaNotMet :
144+ return "❌"
145+ default :
146+ return "❓"
87147 }
148+ }
88149
89- fmt .Println (h .t .GetMessage ("commit.select_option_prompt" , 0 , nil ))
90- fmt .Println (h .t .GetMessage ("commit.option_commit" , 0 , nil ))
91- fmt .Println (h .t .GetMessage ("commit.option_exit" , 0 , nil ))
150+ func (h * SuggestionHandler ) getCriteriaStatusColor (status models.CriteriaStatus ) * color.Color {
151+ switch status {
152+ case models .CriteriaFullyMet :
153+ return color .New (color .FgGreen , color .Bold )
154+ case models .CriteriaPartiallyMet :
155+ return color .New (color .FgYellow , color .Bold )
156+ case models .CriteriaNotMet :
157+ return color .New (color .FgRed , color .Bold )
158+ default :
159+ return color .New (color .FgHiBlack )
160+ }
92161}
93162
94163func (h * SuggestionHandler ) getCriteriaStatusText (status models.CriteriaStatus ) string {
@@ -111,48 +180,97 @@ func (h *SuggestionHandler) getCriteriaStatusText(status models.CriteriaStatus)
111180
112181func (h * SuggestionHandler ) handleCommitSelection (ctx context.Context , suggestions []models.CommitSuggestion ) error {
113182 var selection int
114- fmt .Print (h .t .GetMessage ("commit.prompt_selection" , 0 , nil ))
183+
184+ // Prompt con color
185+ prompt := color .New (color .FgCyan , color .Bold ).Sprint ("Selecciona una opción: " )
186+ fmt .Print (prompt )
187+
115188 if _ , err := fmt .Scan (& selection ); err != nil {
116189 msg := h .t .GetMessage ("commit.error_reading_selection" , 0 , map [string ]interface {}{"Error" : err })
190+ ui .PrintError (msg )
117191 return fmt .Errorf ("%s" , msg )
118192 }
119193
120194 if selection == 0 {
121- fmt . Println (h .t .GetMessage ("commit.operation_canceled" , 0 , nil ))
195+ ui . PrintWarning (h .t .GetMessage ("commit.operation_canceled" , 0 , nil ))
122196 return nil
123197 }
124198
125199 if selection < 1 || selection > len (suggestions ) {
126200 msg := h .t .GetMessage ("commit.invalid_selection" , 0 , map [string ]interface {}{"Number" : len (suggestions )})
201+ ui .PrintError (msg )
127202 return fmt .Errorf ("%s" , msg )
128203 }
129204
130205 return h .processCommit (ctx , suggestions [selection - 1 ], h .gitService )
131206}
132207
133- func (h * SuggestionHandler ) processCommit (ctx context.Context , suggestion models.CommitSuggestion , gitService ports.GitService ) error {
208+ func (h * SuggestionHandler ) processCommit (ctx context.Context , suggestion models.CommitSuggestion ,
209+ gitService ports.GitService ) error {
134210 commitTitle := strings .TrimSpace (strings .TrimPrefix (suggestion .CommitTitle , "Commit: " ))
135211
212+ // Mostrar resumen del commit seleccionado
213+ fmt .Println ()
214+ ui .PrintInfo (h .t .GetMessage ("ui_preview.commit_selected" , 0 , map [string ]interface {}{
215+ "Title" : commitTitle ,
216+ }))
217+ ui .PrintInfo (h .t .GetMessage ("ui_preview.files_count" , 0 , map [string ]interface {}{
218+ "Count" : len (suggestion .Files ),
219+ }))
220+
221+ // Preguntar si quiere ver diff
222+ if ui .AskConfirmation (h .t .GetMessage ("ui_preview.ask_show_diff" , 0 , nil )) {
223+ fmt .Println ()
224+ if err := ui .ShowDiff (suggestion .Files ); err != nil {
225+ ui .PrintWarning (h .t .GetMessage ("ui_preview.error_showing_diff" , 0 , map [string ]interface {}{
226+ "Error" : err ,
227+ }))
228+ }
229+ }
230+
231+ // Confirmación final
232+ if ! ui .AskConfirmation (h .t .GetMessage ("ui_preview.ask_confirm_commit" , 0 , nil )) {
233+ ui .PrintWarning (h .t .GetMessage ("ui_preview.commit_cancelled" , 0 , nil ))
234+ return nil
235+ }
236+
237+ // Spinner para staging
238+ spinner := ui .NewSmartSpinner (h .t .GetMessage ("ui.adding_to_staging" , 0 , nil ))
239+ spinner .Start ()
240+
136241 for _ , file := range suggestion .Files {
137242 if err := gitService .AddFileToStaging (ctx , file ); err != nil {
243+ spinner .Error (fmt .Sprintf ("Error al agregar %s" , file ))
138244 msg := h .t .GetMessage ("commit.error_add_file_staging" , 0 , map [string ]interface {}{
139245 "File" : file ,
140246 "Error" : err ,
141247 })
142248 return fmt .Errorf ("%s" , msg )
143249 }
144- msg := h .t .GetMessage ("commit.add_file_to_staging" , 0 , map [string ]interface {}{"File" : file })
145- fmt .Printf ("%s" , msg )
146250 }
147251
252+ spinner .Success (h .t .GetMessage ("ui.files_added_to_staging" , 0 , map [string ]interface {}{
253+ "Count" : len (suggestion .Files ),
254+ }))
255+
256+ // Spinner para commit
257+ commitSpinner := ui .NewSmartSpinner (h .t .GetMessage ("ui.creating_commit" , 0 , nil ))
258+ commitSpinner .Start ()
259+
148260 if err := gitService .CreateCommit (ctx , commitTitle ); err != nil {
261+ commitSpinner .Error ("Error al crear el commit" )
149262 msg := h .t .GetMessage ("commit.error_creating_commit" , 0 , map [string ]interface {}{
150263 "Commit" : commitTitle ,
151264 "Error" : err ,
152265 })
153266 return fmt .Errorf ("%s" , msg )
154267 }
155268
156- fmt .Printf ("%s\n " , h .t .GetMessage ("commit.commit_successful" , 0 , map [string ]interface {}{"CommitTitle" : commitTitle }))
269+ commitSpinner .Stop ()
270+
271+ // Mensaje de éxito con estilo
272+ ui .PrintSuccess (h .t .GetMessage ("ui.commit_created_successfully" , 0 , nil ))
273+ fmt .Printf ("\n %s\n \n " , color .New (color .FgCyan ).Sprint (commitTitle ))
274+
157275 return nil
158276}
0 commit comments