use super::types::FixStats;
use crate::validation::Violation;
use crate::{Error, Result};
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
pub fn process_all_files(
violations_by_file: HashMap<PathBuf, Vec<Violation>>,
dry_run: bool,
) -> FixStats {
let mut stats = FixStats {
total_fixed: 0,
total_skipped: 0,
files_modified: 0,
};
for (file_path, file_violations) in violations_by_file {
process_single_file(&file_path, &file_violations, dry_run, &mut stats);
}
stats
}
fn process_single_file(
file_path: &Path,
file_violations: &[Violation],
dry_run: bool,
stats: &mut FixStats,
) {
println!("🔧 Processing: {}", file_path.display());
match fix_file_violations(file_path, file_violations, dry_run) {
Ok(fixed_count) if fixed_count > 0 => {
handle_successful_fix(file_path, fixed_count, dry_run, stats);
}
Ok(_) => {
println!(" ⚠️ No fixes applied");
stats.total_skipped += file_violations.len();
}
Err(e) => {
eprintln!(" ❌ Failed to fix file: {}", e);
stats.total_skipped += file_violations.len();
}
}
}
fn handle_successful_fix(
_file_path: &Path,
fixed_count: usize,
dry_run: bool,
stats: &mut FixStats,
) {
if dry_run {
println!(" ✅ Would fix {} violations", fixed_count);
} else {
println!(" ✅ Fixed {} violations", fixed_count);
stats.files_modified += 1;
}
stats.total_fixed += fixed_count;
}
fn fix_file_violations(file_path: &Path, violations: &[Violation], dry_run: bool) -> Result<usize> {
let content = fs::read_to_string(file_path).map_err(|e| {
Error::validation(format!(
"Failed to read file {}: {}",
file_path.display(),
e
))
})?;
let mut lines: Vec<String> = content.lines().map(|s| s.to_string()).collect();
let preserve_trailing_newline = content.ends_with('\n');
let fixed_count = apply_fixes_to_lines(&mut lines, violations);
if fixed_count > 0 && !dry_run {
write_fixed_content(file_path, &lines, preserve_trailing_newline)?;
}
Ok(fixed_count)
}
fn apply_fixes_to_lines(lines: &mut [String], violations: &[Violation]) -> usize {
let mut fixed_count = 0;
let mut sorted_violations = violations.to_vec();
sorted_violations.sort_by(|a, b| b.line.cmp(&a.line));
for violation in sorted_violations {
if violation.line > 0 && violation.line <= lines.len() {
let line_index = violation.line - 1;
let original_line = &lines[line_index];
if let Some(fixed_line) = try_simple_fix(original_line, &violation)
&& fixed_line != *original_line
{
lines[line_index] = fixed_line;
fixed_count += 1;
}
}
}
fixed_count
}
fn try_simple_fix(_line: &str, violation: &Violation) -> Option<String> {
match violation.violation_type {
crate::validation::ViolationType::LineTooLong => {
None
}
_ => None,
}
}
fn write_fixed_content(
file_path: &Path,
lines: &[String],
preserve_trailing_newline: bool,
) -> Result<()> {
let new_content = lines.join("\n");
let final_content = if preserve_trailing_newline {
format!("{}\n", new_content)
} else {
new_content
};
fs::write(file_path, final_content).map_err(|e| {
Error::validation(format!(
"Failed to write file {}: {}",
file_path.display(),
e
))
})?;
Ok(())
}