use crate::services::defect_probability::DefectScore;
use anyhow::Result;
pub(crate) fn format_defect_json(
predictions: &[(String, DefectScore)],
elapsed: std::time::Duration,
) -> Result<String> {
let report = serde_json::json!({
"analysis_type": "defect_prediction",
"summary": {
"total_files_analyzed": predictions.len(),
"high_risk_files": predictions.iter().filter(|(_, s)| s.probability > 0.7).count(),
"medium_risk_files": predictions.iter().filter(|(_, s)| s.probability > 0.3 && s.probability <= 0.7).count(),
"low_risk_files": predictions.iter().filter(|(_, s)| s.probability <= 0.3).count(),
"analysis_time_ms": elapsed.as_millis(),
},
"predictions": predictions.iter().map(|(file, score)| {
serde_json::json!({
"file": file,
"probability": score.probability,
"confidence": score.confidence,
"risk_level": format!("{:?}", score.risk_level),
"contributing_factors": score.contributing_factors,
"recommendations": score.recommendations,
})
}).collect::<Vec<_>>(),
});
Ok(serde_json::to_string_pretty(&report)?)
}
pub(crate) fn format_defect_detailed(
predictions: &[(String, DefectScore)],
elapsed: std::time::Duration,
include_recommendations: bool,
) -> Result<String> {
let mut output = String::new();
write_detailed_header(&mut output)?;
for (file, score) in predictions {
write_file_details(&mut output, file, score, include_recommendations)?;
}
write_analysis_footer(&mut output, elapsed)?;
Ok(output)
}
pub(crate) fn write_detailed_header(output: &mut String) -> Result<()> {
use std::fmt::Write;
writeln!(output, "🔮 Defect Prediction Detailed Report")?;
writeln!(output, "===================================")?;
writeln!(output)?;
Ok(())
}
pub(crate) fn write_file_details(
output: &mut String,
file: &str,
score: &DefectScore,
include_recommendations: bool,
) -> Result<()> {
use std::fmt::Write;
writeln!(output, "📄 File: {file}")?;
write_risk_level(output, score)?;
write_confidence_level(output, score)?;
write_contributing_factors(output, score)?;
if include_recommendations {
write_recommendations(output, score)?;
}
writeln!(output)?;
Ok(())
}
pub(crate) fn write_risk_level(output: &mut String, score: &DefectScore) -> Result<()> {
use std::fmt::Write;
let risk_display = format_risk_level_display(&score.risk_level);
writeln!(
output,
" Risk Level: {} ({:.1}%)",
risk_display,
score.probability * 100.0
)?;
Ok(())
}
pub(crate) fn format_risk_level_display(
risk_level: &crate::services::defect_probability::RiskLevel,
) -> &'static str {
match risk_level {
crate::services::defect_probability::RiskLevel::High => "🔴 HIGH",
crate::services::defect_probability::RiskLevel::Medium => "🟡 MEDIUM",
crate::services::defect_probability::RiskLevel::Low => "🟢 LOW",
}
}
pub(crate) fn write_confidence_level(output: &mut String, score: &DefectScore) -> Result<()> {
use std::fmt::Write;
writeln!(output, " Confidence: {:.1}%", score.confidence * 100.0)?;
Ok(())
}
pub(crate) fn write_contributing_factors(output: &mut String, score: &DefectScore) -> Result<()> {
use std::fmt::Write;
if score.contributing_factors.is_empty() {
return Ok(());
}
writeln!(output, " Contributing Factors:")?;
for (factor, weight) in &score.contributing_factors {
writeln!(output, " - {}: {:.1}%", factor, weight * 100.0)?;
}
Ok(())
}
pub(crate) fn write_recommendations(output: &mut String, score: &DefectScore) -> Result<()> {
use std::fmt::Write;
if score.recommendations.is_empty() {
return Ok(());
}
writeln!(output, " Recommendations:")?;
for rec in &score.recommendations {
writeln!(output, " • {rec}")?;
}
Ok(())
}
pub(crate) fn write_analysis_footer(
output: &mut String,
elapsed: std::time::Duration,
) -> Result<()> {
use std::fmt::Write;
writeln!(output, "⏱️ Analysis time: {elapsed:.2?}")?;
Ok(())
}