use crate::security_analyzer::{SecurityReport, SecurityFinding, RiskLevel};
use chrono::{DateTime, Utc};
use serde::Serialize;
use std::path::PathBuf;
#[derive(Debug, Serialize)]
pub struct ComprehensiveReport {
pub timestamp: DateTime<Utc>,
pub security_findings: SecurityReport,
pub access_statistics: AccessStatistics,
pub system_health: SystemHealth,
}
#[derive(Debug, Serialize)]
pub struct AccessStatistics {
pub total_requests: u64,
pub successful_requests: u64,
pub failed_requests: u64,
pub unique_users: u32,
pub most_accessed_resources: Vec<ResourceUsage>,
}
#[derive(Debug, Serialize)]
pub struct ResourceUsage {
pub resource: String,
pub access_count: u64,
pub success_rate: f64,
}
#[derive(Debug, Serialize)]
pub struct SystemHealth {
pub cache_hit_rate: f64,
pub average_response_time: f64,
pub error_rate: f64,
}
pub struct ReportGenerator {
output_dir: PathBuf,
}
impl ReportGenerator {
pub fn new(output_dir: PathBuf) -> Self {
Self { output_dir }
}
pub async fn generate_report(&self, report: ComprehensiveReport) -> Result<PathBuf, std::io::Error> {
let json = serde_json::to_string_pretty(&report)?;
let filename = format!(
"security_report_{}.json",
report.timestamp.format("%Y%m%d_%H%M%S")
);
let file_path = self.output_dir.join(filename);
tokio::fs::write(&file_path, json).await?;
self.generate_html_report(&report).await?;
Ok(file_path)
}
async fn generate_html_report(&self, report: &ComprehensiveReport) -> Result<PathBuf, std::io::Error> {
let html = self.format_html_report(report);
let filename = format!(
"security_report_{}.html",
report.timestamp.format("%Y%m%d_%H%M%S")
);
let file_path = self.output_dir.join(filename);
tokio::fs::write(&file_path, html).await?;
Ok(file_path)
}
fn format_html_report(&self, report: &ComprehensiveReport) -> String {
format!(
r#"
<!DOCTYPE html>
<html>
<head>
<title>Security Report - {}</title>
<style>
body {{ font-family: Arial, sans-serif; }}
.critical {{ color: red; }}
.high {{ color: orange; }}
.medium {{ color: yellow; }}
.low {{ color: green; }}
</style>
</head>
<body>
<h1>Security Report</h1>
<h2>Overview</h2>
<p>Generated at: {}</p>
<p>Risk Level: {}</p>
{}
</body>
</html>
"#,
report.timestamp.format("%Y-%m-%d %H:%M:%S"),
report.timestamp.format("%Y-%m-%d %H:%M:%S"),
format!("{:?}", report.security_findings.risk_level),
self.format_findings_html(&report.security_findings.findings)
)
}
fn format_findings_html(&self, findings: &[SecurityFinding]) -> String {
let mut html = String::from("<h2>Security Findings</h2><ul>");
for finding in findings {
html.push_str(&format!(
r#"<li class="{}">
<strong>{:?}</strong>: {}
<br>Affected Users: {}
<br>Affected Resources: {}
</li>"#,
format!("{:?}", finding.severity).to_lowercase(),
finding.finding_type,
finding.description,
finding.affected_users.join(", "),
finding.affected_resources.join(", ")
));
}
html.push_str("</ul>");
html
}
}