#![cfg_attr(coverage_nightly, coverage(off))]
use crate::services::defect_probability::DefectScore;
use anyhow::Result;
use std::fmt::Write;
pub fn format_defect_summary(predictions: &[(String, DefectScore)]) -> Result<String> {
let mut output = String::new();
writeln!(&mut output, "# Defect Prediction Summary\n")?;
writeln!(
&mut output,
"**Total files analyzed**: {}",
predictions.len()
)?;
let high_risk = predictions
.iter()
.filter(|(_, s)| s.probability > 0.7)
.count();
let medium_risk = predictions
.iter()
.filter(|(_, s)| s.probability > 0.4 && s.probability <= 0.7)
.count();
let low_risk = predictions
.iter()
.filter(|(_, s)| s.probability <= 0.4)
.count();
writeln!(&mut output, "\n## Risk Distribution:")?;
writeln!(&mut output, "- 🔴 High Risk (>70%): {high_risk} files")?;
writeln!(
&mut output,
"- 🟡 Medium Risk (40-70%): {medium_risk} files"
)?;
writeln!(&mut output, "- 🟢 Low Risk (<40%): {low_risk} files")?;
if !predictions.is_empty() {
writeln!(&mut output, "\n## Top 10 High-Risk Files:")?;
for (i, (file, score)) in predictions.iter().take(10).enumerate() {
writeln!(
&mut output,
"{}. {} - {:.1}% probability",
i + 1,
file,
score.probability * 100.0
)?;
}
}
Ok(output)
}
pub fn format_defect_markdown(
predictions: &[(String, DefectScore)],
include_recommendations: bool,
) -> Result<String> {
let mut output = String::new();
writeln!(&mut output, "# Defect Prediction Report\n")?;
write_summary_section(&mut output, predictions)?;
write_risk_distribution_table(&mut output, predictions)?;
write_detailed_predictions(&mut output, predictions, include_recommendations)?;
Ok(output)
}
pub(crate) fn write_summary_section(
output: &mut String,
predictions: &[(String, DefectScore)],
) -> Result<()> {
writeln!(output, "## Summary\n")?;
writeln!(output, "**Total files analyzed**: {}", predictions.len())?;
Ok(())
}
pub(crate) fn write_risk_distribution_table(
output: &mut String,
predictions: &[(String, DefectScore)],
) -> Result<()> {
let (high_risk, medium_risk, low_risk) = calculate_risk_counts(predictions);
let total = predictions.len() as f64;
writeln!(output, "\n### Risk Distribution")?;
writeln!(output, "| Risk Level | Count | Percentage |")?;
writeln!(output, "|------------|-------|------------|")?;
write_risk_row(output, "High (>70%)", high_risk, total)?;
write_risk_row(output, "Medium (40-70%)", medium_risk, total)?;
write_risk_row(output, "Low (<40%)", low_risk, total)?;
Ok(())
}
pub(crate) fn calculate_risk_counts(
predictions: &[(String, DefectScore)],
) -> (usize, usize, usize) {
let high_risk = predictions
.iter()
.filter(|(_, s)| s.probability > 0.7)
.count();
let medium_risk = predictions
.iter()
.filter(|(_, s)| s.probability > 0.4 && s.probability <= 0.7)
.count();
let low_risk = predictions
.iter()
.filter(|(_, s)| s.probability <= 0.4)
.count();
(high_risk, medium_risk, low_risk)
}
pub(crate) fn write_risk_row(
output: &mut String,
label: &str,
count: usize,
total: f64,
) -> Result<()> {
writeln!(
output,
"| {} | {} | {:.1}% |",
label,
count,
(count as f64 / total) * 100.0
)?;
Ok(())
}
pub(crate) fn write_detailed_predictions(
output: &mut String,
predictions: &[(String, DefectScore)],
include_recommendations: bool,
) -> Result<()> {
writeln!(output, "\n## Detailed Predictions\n")?;
for (file, score) in predictions.iter().take(20) {
write_single_prediction(output, file, score, include_recommendations)?;
}
Ok(())
}
pub(crate) fn write_single_prediction(
output: &mut String,
file: &str,
score: &DefectScore,
include_recommendations: bool,
) -> Result<()> {
writeln!(output, "### {file}\n")?;
write_prediction_metrics(output, score)?;
if include_recommendations {
write_recommendations(output, f64::from(score.probability))?;
}
writeln!(output)?;
Ok(())
}
pub(crate) fn write_prediction_metrics(output: &mut String, score: &DefectScore) -> Result<()> {
writeln!(
output,
"- **Probability**: {:.1}%",
f64::from(score.probability) * 100.0
)?;
writeln!(
output,
"- **Confidence**: {:.1}%",
f64::from(score.confidence) * 100.0
)?;
writeln!(
output,
"- **Risk Factors**: {:?}",
score.contributing_factors
)?;
Ok(())
}
pub(crate) fn write_recommendations(output: &mut String, probability: f64) -> Result<()> {
writeln!(output, "\n#### Recommendations:")?;
if probability > 0.7 {
writeln!(output, "- 🔴 High priority for code review")?;
writeln!(output, "- Add comprehensive test coverage")?;
writeln!(output, "- Consider refactoring to reduce complexity")?;
} else if probability > 0.4 {
writeln!(output, "- 🟡 Schedule for regular review")?;
writeln!(output, "- Improve test coverage")?;
} else {
writeln!(output, "- 🟢 Monitor during regular maintenance")?;
}
Ok(())
}