use crate::cli::args::{AuditFormat, ShredMethod};
use chrono::{DateTime, Utc};
use serde::Serialize;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
#[derive(Debug, Serialize, Clone)]
pub struct ShredEvent {
pub path: PathBuf,
pub timestamp: DateTime<Utc>,
pub method: ShredMethod,
pub success: bool,
pub error: Option<String>,
}
#[derive(Debug, Serialize, Clone)]
pub struct ShredReport {
pub generated_at: DateTime<Utc>,
pub total_files: usize,
pub success_count: usize,
pub failure_count: usize,
pub events: Vec<ShredEvent>,
}
impl ShredReport {
pub fn new(events: Vec<ShredEvent>) -> Self {
let total = events.len();
let success_count = events.iter().filter(|e| e.success).count();
let failure_count = total - success_count;
Self {
generated_at: Utc::now(),
total_files: total,
success_count,
failure_count,
events,
}
}
pub fn save(&self, path: &Path, format: AuditFormat) -> std::io::Result<()> {
let content = match format {
AuditFormat::Json => {
serde_json::to_string_pretty(self).map_err(std::io::Error::other)?
}
AuditFormat::Text => self.to_text(),
};
let mut file = File::create(path)?;
file.write_all(content.as_bytes())?;
Ok(())
}
fn to_text(&self) -> String {
let mut text = String::new();
text.push_str("=== sys-shred Forensic Audit Report ===\n");
text.push_str(&format!("Generated at: {}\n", self.generated_at));
text.push_str(&format!("Total Files: {}\n", self.total_files));
text.push_str(&format!("Successes: {}\n", self.success_count));
text.push_str(&format!("Failures: {}\n", self.failure_count));
text.push_str("========================================\n\n");
for event in &self.events {
let status = if event.success { "SUCCESS" } else { "FAILURE" };
text.push_str(&format!(
"[{}] {:?} - {} ({:?})\n",
event.timestamp.format("%Y-%m-%d %H:%M:%S"),
event.path,
status,
event.method
));
if let Some(ref err) = event.error {
text.push_str(&format!(" Error: {}\n", err));
}
}
text
}
}