ai_code_buddy/widget_states/
reports.rs

1use crate::core::review::Review;
2use bevy::prelude::*;
3use serde_json;
4
5#[derive(Debug, Clone, Resource)]
6pub struct ReportsWidgetState {
7    pub review: Option<Review>,
8    pub selected_format: ReportFormat,
9    pub export_status: ExportStatus,
10    pub generated_report: Option<String>,
11    pub view_mode: ViewMode,
12}
13
14#[derive(Debug, Clone, PartialEq)]
15pub enum ViewMode {
16    Selection, // Format selection and preview
17    Report,    // Full report display
18}
19
20#[derive(Debug, Clone, PartialEq)]
21pub enum ReportFormat {
22    Summary,
23    Detailed,
24    Json,
25    Markdown,
26}
27
28#[derive(Debug, Clone)]
29pub enum ExportStatus {
30    None,
31    Exporting(String), // format
32    Success(String),   // path
33}
34
35impl Default for ReportsWidgetState {
36    fn default() -> Self {
37        Self {
38            review: None,
39            selected_format: ReportFormat::Summary,
40            export_status: ExportStatus::None,
41            generated_report: None,
42            view_mode: ViewMode::Selection,
43        }
44    }
45}
46
47impl ReportsWidgetState {
48    pub fn set_review(&mut self, review: Review) {
49        self.review = Some(review);
50    }
51
52    pub fn next_format(&mut self) {
53        self.selected_format = match self.selected_format {
54            ReportFormat::Summary => ReportFormat::Detailed,
55            ReportFormat::Detailed => ReportFormat::Json,
56            ReportFormat::Json => ReportFormat::Markdown,
57            ReportFormat::Markdown => ReportFormat::Summary,
58        };
59    }
60
61    pub fn previous_format(&mut self) {
62        self.selected_format = match self.selected_format {
63            ReportFormat::Summary => ReportFormat::Markdown,
64            ReportFormat::Detailed => ReportFormat::Summary,
65            ReportFormat::Json => ReportFormat::Detailed,
66            ReportFormat::Markdown => ReportFormat::Json,
67        };
68    }
69
70    pub fn start_export(&mut self, format: String) {
71        self.export_status = ExportStatus::Exporting(format);
72    }
73
74    pub fn complete_export(&mut self, path: String) {
75        self.export_status = ExportStatus::Success(path);
76    }
77
78    pub fn generate_report(&mut self) -> Option<String> {
79        if let Some(review) = &self.review {
80            let report_content = match self.selected_format {
81                ReportFormat::Summary => self.generate_summary_report(review),
82                ReportFormat::Detailed => self.generate_detailed_report(review),
83                ReportFormat::Json => self.generate_json_report(review),
84                ReportFormat::Markdown => self.generate_markdown_report(review),
85            };
86            self.generated_report = Some(report_content.clone());
87            self.view_mode = ViewMode::Report;
88            Some(report_content)
89        } else {
90            None
91        }
92    }
93
94    pub fn back_to_selection(&mut self) {
95        self.view_mode = ViewMode::Selection;
96    }
97
98    fn generate_summary_report(&self, review: &Review) -> String {
99        format!(
100            "šŸ¤– AI Code Review Summary\n\
101             ========================\n\n\
102             šŸ“Š Analysis Results:\n\
103             • Files analyzed: {}\n\
104             • Total issues found: {}\n\n\
105             🚨 Issue Breakdown:\n\
106             • Critical: {} issues\n\
107             • High: {} issues\n\
108             • Medium: {} issues\n\
109             • Low: {} issues\n\n\
110             šŸ“‹ Recommendations:\n\
111             {} Focus on addressing Critical and High severity issues first.\n\
112             {} Review Medium issues for code quality improvements.\n\
113             {} Low severity issues can be addressed as time permits.\n\n\
114             šŸŽÆ Next Steps:\n\
115             1. Review each Critical issue immediately\n\
116             2. Plan fixes for High severity issues\n\
117             3. Consider Medium issues for future iterations\n\
118             4. Use the detailed report for specific guidance",
119            review.files_count,
120            review.issues_count,
121            review.critical_issues,
122            review.high_issues,
123            review.medium_issues,
124            review.low_issues,
125            if review.critical_issues > 0 {
126                "āš ļø"
127            } else {
128                "āœ…"
129            },
130            if review.medium_issues > 0 {
131                "šŸ“"
132            } else {
133                "āœ…"
134            },
135            if review.low_issues > 0 { "šŸ’”" } else { "āœ…" }
136        )
137    }
138
139    fn generate_detailed_report(&self, review: &Review) -> String {
140        let mut report = format!(
141            "šŸ¤– AI Code Review - Detailed Report\n\
142             ===================================\n\n\
143             šŸ“Š Overview:\n\
144             • Repository analyzed\n\
145             • Files processed: {}\n\
146             • Total issues: {}\n\n",
147            review.files_count, review.issues_count
148        );
149
150        if review.issues.is_empty() {
151            report.push_str("šŸŽ‰ No issues found! Your code looks great!\n");
152            return report;
153        }
154
155        // Group issues by severity
156        let mut critical_issues = Vec::new();
157        let mut high_issues = Vec::new();
158        let mut medium_issues = Vec::new();
159        let mut low_issues = Vec::new();
160
161        for issue in &review.issues {
162            match issue.severity.as_str() {
163                "Critical" => critical_issues.push(issue),
164                "High" => high_issues.push(issue),
165                "Medium" => medium_issues.push(issue),
166                "Low" => low_issues.push(issue),
167                _ => low_issues.push(issue),
168            }
169        }
170
171        // Critical issues
172        if !critical_issues.is_empty() {
173            report.push_str("🚨 CRITICAL ISSUES (Immediate Action Required):\n");
174            report.push_str("=====================================================\n\n");
175            for (i, issue) in critical_issues.iter().enumerate() {
176                report.push_str(&format!(
177                    "{}. File: {}\n   Line: {}\n   Category: {}\n   Issue: {}\n\n",
178                    i + 1,
179                    issue.file,
180                    issue.line,
181                    issue.category,
182                    issue.description
183                ));
184            }
185        }
186
187        // High issues
188        if !high_issues.is_empty() {
189            report.push_str("āš ļø  HIGH PRIORITY ISSUES:\n");
190            report.push_str("=========================\n\n");
191            for (i, issue) in high_issues.iter().enumerate() {
192                report.push_str(&format!(
193                    "{}. File: {}\n   Line: {}\n   Category: {}\n   Issue: {}\n\n",
194                    i + 1,
195                    issue.file,
196                    issue.line,
197                    issue.category,
198                    issue.description
199                ));
200            }
201        }
202
203        // Medium issues
204        if !medium_issues.is_empty() {
205            report.push_str("šŸ”¶ MEDIUM PRIORITY ISSUES:\n");
206            report.push_str("==========================\n\n");
207            for (i, issue) in medium_issues.iter().enumerate() {
208                report.push_str(&format!(
209                    "{}. File: {}\n   Line: {}\n   Category: {}\n   Issue: {}\n\n",
210                    i + 1,
211                    issue.file,
212                    issue.line,
213                    issue.category,
214                    issue.description
215                ));
216            }
217        }
218
219        // Low issues
220        if !low_issues.is_empty() {
221            report.push_str("ā„¹ļø  LOW PRIORITY ISSUES:\n");
222            report.push_str("========================\n\n");
223            for (i, issue) in low_issues.iter().enumerate() {
224                report.push_str(&format!(
225                    "{}. File: {}\n   Line: {}\n   Category: {}\n   Issue: {}\n\n",
226                    i + 1,
227                    issue.file,
228                    issue.line,
229                    issue.category,
230                    issue.description
231                ));
232            }
233        }
234
235        report.push_str("\nšŸ“ End of Report\n");
236        report
237    }
238
239    fn generate_json_report(&self, review: &Review) -> String {
240        // Use serde to generate proper JSON
241        match serde_json::to_string_pretty(review) {
242            Ok(json) => json,
243            Err(_) => "Error generating JSON report".to_string(),
244        }
245    }
246
247    fn generate_markdown_report(&self, review: &Review) -> String {
248        let mut report = format!(
249            "# šŸ¤– AI Code Review Report\n\n\
250             ## šŸ“Š Summary\n\n\
251             - **Files analyzed:** {}\n\
252             - **Total issues:** {}\n\
253             - **Critical issues:** {}\n\
254             - **High priority:** {}\n\
255             - **Medium priority:** {}\n\
256             - **Low priority:** {}\n\n",
257            review.files_count,
258            review.issues_count,
259            review.critical_issues,
260            review.high_issues,
261            review.medium_issues,
262            review.low_issues
263        );
264
265        if review.issues.is_empty() {
266            report.push_str("## šŸŽ‰ Results\n\nNo issues found! Your code looks great!\n");
267            return report;
268        }
269
270        report.push_str("## šŸ“‹ Issues by Severity\n\n");
271
272        // Group and display issues by severity
273        for severity in ["Critical", "High", "Medium", "Low"] {
274            let severity_issues: Vec<_> = review
275                .issues
276                .iter()
277                .filter(|issue| issue.severity == severity)
278                .collect();
279
280            if !severity_issues.is_empty() {
281                let icon = match severity {
282                    "Critical" => "🚨",
283                    "High" => "āš ļø",
284                    "Medium" => "šŸ”¶",
285                    "Low" => "ā„¹ļø",
286                    _ => "šŸ“",
287                };
288
289                report.push_str(&format!("### {icon} {severity} Priority Issues\n\n"));
290
291                for issue in severity_issues {
292                    report.push_str(&format!(
293                        "- **File:** `{}`\n  **Line:** {}\n  **Category:** {}\n  **Issue:** {}\n\n",
294                        issue.file, issue.line, issue.category, issue.description
295                    ));
296                }
297            }
298        }
299
300        report.push_str("---\n\n*Report generated by AI Code Buddy*\n");
301        report
302    }
303}