use std::io::{self, Write};
use sysinfo::System;
use console::Style;
use crate::error::OaResult;
const OFFICE_PROCESSES: &[&str] = &["POWERPNT.EXE", "EXCEL.EXE"];
const PID_COL: usize = 40;
pub fn run_clean(force: bool) -> OaResult<()> {
let s_dim = Style::new().dim();
let s_ok = Style::new().green();
let s_count = Style::new().white().bold();
let s_name = Style::new().yellow();
let mut sys = System::new();
sys.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
let mut found: Vec<(sysinfo::Pid, String)> = Vec::new();
for process in sys.processes().values() {
let name = process.name().to_string_lossy().to_string();
if OFFICE_PROCESSES.iter().any(|&p| name.eq_ignore_ascii_case(p)) {
found.push((process.pid(), name));
}
}
let count_label = if found.len() == 1 { "Office process" } else { "Office processes" };
println!();
println!(" {} {} {}",
s_dim.apply_to("Found"),
s_count.apply_to(found.len()),
s_dim.apply_to(count_label));
if found.is_empty() {
println!();
println!(" {} {}", s_ok.apply_to("✓"), s_ok.apply_to("No Office processes found"));
return Ok(());
}
println!();
for (pid, name) in &found {
print_process_row("", name, pid, &s_name, &s_dim, &s_count);
}
if !force {
println!();
print!(" {} ", s_name.apply_to("Kill all? [y/N]"));
io::stdout().flush()?;
let mut input = String::new();
io::stdin().read_line(&mut input)?;
if !input.trim().eq_ignore_ascii_case("y") {
println!();
println!(" {} {}",
s_ok.apply_to("✓"),
s_dim.apply_to("cancelled — no processes killed"));
return Ok(());
}
}
let mut killed = 0;
let mut sys2 = System::new();
sys2.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
println!();
for (pid, name) in &found {
if let Some(process) = sys2.process(*pid) {
process.kill();
killed += 1;
print_process_row(
&format!("{} ", s_ok.apply_to("✓ Killed")),
name, pid, &s_name, &s_dim, &s_count,
);
}
}
let kill_label = if killed == 1 { "process killed" } else { "processes killed" };
println!();
println!(" {} {} {} {} {}",
s_ok.apply_to("✓"),
s_ok.apply_to("cleaned"),
s_dim.apply_to("·"),
s_count.apply_to(killed),
s_dim.apply_to(kill_label));
Ok(())
}
fn print_process_row(
prefix: &str,
name: &str,
pid: &sysinfo::Pid,
s_name: &Style,
s_dim: &Style,
s_count: &Style,
) {
let indent = " ";
let prefix_visible_len = if prefix.is_empty() { 0 } else {
console::measure_text_width(prefix)
};
let display_len = indent.len() + prefix_visible_len + name.len();
let leader_len = PID_COL.saturating_sub(display_len + 1);
let leaders = "·".repeat(leader_len);
println!("{}{}{} {} {} {}",
indent,
prefix,
s_name.apply_to(name),
s_dim.apply_to(&leaders),
s_dim.apply_to("PID"),
s_count.apply_to(pid));
}