use crate::commands::doctor::types::{Diagnostic, Severity};
use std::collections::HashMap;
use std::time::Duration;
pub const ERROR_PENALTY: usize = 20;
pub const WARNING_PENALTY: usize = 5;
pub const SUGGESTION_PENALTY: usize = 1;
pub const MAX_PENALTY: usize = 100;
#[derive(Debug)]
pub struct CheckResult {
pub name: String,
pub description: String,
#[allow(dead_code)]
pub category: String,
pub duration: Duration,
pub diagnostics: Vec<Diagnostic>,
}
#[derive(Debug)]
pub struct DiagnosticReport {
pub results: Vec<CheckResult>,
pub total_duration: Duration,
}
impl DiagnosticReport {
pub fn new() -> Self {
Self {
results: Vec::new(),
total_duration: Duration::from_secs(0),
}
}
pub fn add_result(&mut self, result: CheckResult) {
self.total_duration += result.duration;
self.results.push(result);
}
pub fn diagnostics_by_severity(&self, severity: Severity) -> Vec<&Diagnostic> {
self.results
.iter()
.flat_map(|r| &r.diagnostics)
.filter(|d| d.severity == severity)
.collect()
}
pub fn diagnostics_by_category(&self) -> HashMap<&str, Vec<&Diagnostic>> {
let mut map = HashMap::new();
for result in &self.results {
for diagnostic in &result.diagnostics {
map.entry(diagnostic.category.as_str())
.or_insert_with(Vec::new)
.push(diagnostic);
}
}
map
}
pub fn health_score(&self) -> u8 {
let error_count = self.diagnostics_by_severity(Severity::Error).len();
let warning_count = self.diagnostics_by_severity(Severity::Warning).len();
let suggestion_count = self.diagnostics_by_severity(Severity::Suggestion).len();
let total_checks = self.results.len();
if total_checks == 0 {
return 100;
}
let penalty = (error_count * ERROR_PENALTY
+ warning_count * WARNING_PENALTY
+ suggestion_count * SUGGESTION_PENALTY)
.min(MAX_PENALTY);
100 - penalty as u8
}
pub fn statistics(&self) -> DiagnosticStatistics {
DiagnosticStatistics {
total_checks: self.results.len(),
total_diagnostics: self.results.iter().map(|r| r.diagnostics.len()).sum(),
errors: self.diagnostics_by_severity(Severity::Error).len(),
warnings: self.diagnostics_by_severity(Severity::Warning).len(),
suggestions: self.diagnostics_by_severity(Severity::Suggestion).len(),
info: self.diagnostics_by_severity(Severity::Info).len(),
health_score: self.health_score(),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct DiagnosticStatistics {
pub total_checks: usize,
#[allow(dead_code)]
pub total_diagnostics: usize,
pub errors: usize,
pub warnings: usize,
pub suggestions: usize,
pub info: usize,
pub health_score: u8,
}