impl EnhancedReportingService {
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn new() -> Result<Self> {
Ok(Self {
renderer: crate::services::renderer::TemplateRenderer::new()?,
})
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub async fn generate_report(
&self,
config: ReportConfig,
analysis_results: AnalysisResults,
) -> Result<UnifiedAnalysisReport> {
info!("📊 Generating enhanced analysis report");
info!("📂 Project: {}", config.project_path.display());
info!("📄 Format: {:?}", config.output_format);
let start_time = std::time::Instant::now();
let metadata = self.build_metadata(&config, &analysis_results)?;
let executive_summary = self.generate_executive_summary(&analysis_results)?;
let sections = self.build_sections(&analysis_results, &config)?;
let recommendations = self.generate_recommendations(&analysis_results, §ions)?;
let visualizations = if config.include_visualizations {
self.create_visualizations(&analysis_results, §ions)?
} else {
Vec::new()
};
let report = UnifiedAnalysisReport {
metadata,
executive_summary,
sections,
recommendations,
visualizations,
};
let duration = start_time.elapsed();
info!("✅ Report generated in {:?}", duration);
Ok(report)
}
fn build_metadata(
&self,
config: &ReportConfig,
results: &AnalysisResults,
) -> Result<ReportMetadata> {
Ok(ReportMetadata {
project_name: config
.project_path
.file_name()
.unwrap_or_default()
.to_string_lossy()
.to_string(),
project_path: config.project_path.display().to_string(),
report_date: chrono::Utc::now().to_rfc3339(),
tool_version: env!("CARGO_PKG_VERSION").to_string(),
analysis_duration: results.total_duration.as_secs_f64(),
analyzed_files: results.analyzed_files,
total_lines: results.total_lines,
})
}
fn generate_executive_summary(&self, results: &AnalysisResults) -> Result<ExecutiveSummary> {
let overall_health_score = self.calculate_health_score(results);
let critical_issues = self.count_issues_by_severity(results, Severity::Critical);
let high_priority_issues = self.count_issues_by_severity(results, Severity::High);
let key_findings = self.extract_key_findings(results);
let risk_assessment = self.assess_overall_risk(results);
Ok(ExecutiveSummary {
overall_health_score,
critical_issues,
high_priority_issues,
key_findings,
risk_assessment,
})
}
fn calculate_health_score(&self, results: &AnalysisResults) -> f64 {
let mut score = 100.0;
if let Some(complexity) = &results.complexity_analysis {
let avg_complexity =
f64::from(complexity.total_cyclomatic) / complexity.functions as f64;
if avg_complexity > 10.0 {
score -= (avg_complexity - 10.0).min(20.0);
}
}
if let Some(dead_code) = &results.dead_code_analysis {
let dead_code_ratio = dead_code.dead_lines as f64 / results.total_lines as f64;
score -= (dead_code_ratio * 100.0).min(15.0);
}
if let Some(duplication) = &results.duplication_analysis {
let duplication_ratio =
duplication.duplicated_lines as f64 / results.total_lines as f64;
score -= (duplication_ratio * 100.0).min(15.0);
}
if let Some(tdg) = &results.tdg_analysis {
if tdg.average_tdg > 3.0 {
score -= ((tdg.average_tdg - 3.0) * 5.0).min(20.0);
}
}
score.max(0.0)
}
fn count_issues_by_severity(&self, _results: &AnalysisResults, _severity: Severity) -> usize {
0
}
fn extract_key_findings(&self, results: &AnalysisResults) -> Vec<String> {
let mut findings = Vec::new();
if let Some(complexity) = &results.complexity_analysis {
if complexity.max_cyclomatic > 20 {
findings.push(format!(
"Found {} functions with high complexity (CC > 20)",
complexity.high_complexity_functions
));
}
}
if let Some(dead_code) = &results.dead_code_analysis {
if dead_code.dead_functions > 10 {
findings.push(format!(
"Detected {} unused functions that could be removed",
dead_code.dead_functions
));
}
}
if let Some(duplication) = &results.duplication_analysis {
if duplication.duplicate_blocks > 20 {
findings.push(format!(
"Found {} duplicate code blocks affecting maintainability",
duplication.duplicate_blocks
));
}
}
findings
}
fn assess_overall_risk(&self, results: &AnalysisResults) -> RiskLevel {
let health_score = self.calculate_health_score(results);
match health_score {
s if s >= 80.0 => RiskLevel::Low,
s if s >= 60.0 => RiskLevel::Medium,
s if s >= 40.0 => RiskLevel::High,
_ => RiskLevel::Critical,
}
}
}