Skip to main content

trustformers_debug/environmental_monitor/
reporting.rs

1//! Environmental reporting engine for generating comprehensive impact reports
2// reason: debug/profiling scaffolding — structs are constructed and their fields/methods
3// are retained for the data model, serialization completeness, and future consumers that
4// do not yet read every member. Consolidated from many item-level #[allow(dead_code)].
5#![allow(dead_code)]
6
7use crate::environmental_monitor::types::*;
8use anyhow::Result;
9use std::collections::HashMap;
10use std::time::{Duration, SystemTime};
11use tracing::info;
12
13/// Environmental reporting engine
14#[derive(Debug)]
15pub struct EnvironmentalReportingEngine {
16    report_templates: HashMap<String, ReportTemplate>,
17    automated_reports: Vec<AutomatedReport>,
18    dashboard_metrics: EnvironmentalDashboardMetrics,
19}
20
21#[derive(Debug, Clone)]
22struct ReportTemplate {
23    template_name: String,
24    sections: Vec<ReportSection>,
25    target_audience: String,
26    frequency: ReportFrequency,
27}
28
29#[derive(Debug, Clone)]
30struct ReportSection {
31    section_name: String,
32    metrics_included: Vec<String>,
33    visualization_type: VisualizationType,
34}
35#[derive(Debug, Clone)]
36pub struct AutomatedReport {
37    report_id: String,
38    generated_at: SystemTime,
39    report_type: String,
40    content: String,
41}
42
43/// Most automated reports retained in memory before the oldest is dropped.
44///
45/// There is no database behind this log -- reports live for the lifetime of the
46/// reporter -- so the cap keeps a long-running monitor bounded.
47const MAX_AUTOMATED_REPORTS: usize = 100;
48
49impl EnvironmentalReportingEngine {
50    /// Create a new environmental reporting engine
51    pub fn new() -> Self {
52        Self {
53            report_templates: Self::initialize_report_templates(),
54            automated_reports: Vec::new(),
55            dashboard_metrics: EnvironmentalDashboardMetrics {
56                total_energy_consumed_kwh: 0.0,
57                total_co2_emissions_kg: 0.0,
58                current_power_usage_watts: 0.0,
59                energy_efficiency_score: 0.0,
60                carbon_intensity_gco2_kwh: 0.0,
61                cost_per_hour_usd: 0.0,
62                trend: TrendDirection::Stable,
63            },
64        }
65    }
66
67    /// Generate comprehensive environmental impact report
68    /// Generate a report and retain it in [`Self::get_automated_reports`].
69    ///
70    /// Takes `&mut self` because the report is really stored; the previous
71    /// `&self` signature made storage impossible, so `store_automated_report`
72    /// built an [`AutomatedReport`], logged "Stored automated report: {id}" and
73    /// then dropped it -- `get_automated_reports` stayed empty forever.
74    pub async fn generate_environmental_report(
75        &mut self,
76        report_type: ReportType,
77    ) -> Result<EnvironmentalReport> {
78        info!("Generating environmental impact report: {:?}", report_type);
79
80        let report = match report_type {
81            ReportType::Summary => self.generate_summary_report().await?,
82            ReportType::Detailed => self.generate_detailed_report().await?,
83            ReportType::Technical => self.generate_technical_report().await?,
84            ReportType::Executive => self.generate_executive_report().await?,
85            ReportType::Compliance => self.generate_compliance_report().await?,
86        };
87
88        self.store_automated_report(&report)?;
89
90        Ok(report)
91    }
92
93    /// Generate daily report
94    pub async fn generate_daily_report(&self) -> Result<EnvironmentalReport> {
95        let period_start = SystemTime::now() - Duration::from_secs(24 * 3600);
96        let period_end = SystemTime::now();
97
98        Ok(EnvironmentalReport {
99            report_id: format!("daily-{}", chrono::Utc::now().format("%Y%m%d")),
100            report_type: ReportType::Summary,
101            generated_at: SystemTime::now(),
102            period_start,
103            period_end,
104            summary: "Daily environmental impact summary showing energy consumption, carbon emissions, and efficiency metrics".to_string(),
105            metrics: EnvironmentalDashboardMetrics {
106                total_energy_consumed_kwh: 120.5,
107                total_co2_emissions_kg: 48.2,
108                current_power_usage_watts: 750.0,
109                energy_efficiency_score: 0.87,
110                carbon_intensity_gco2_kwh: 400.0,
111                cost_per_hour_usd: 14.46,
112                trend: TrendDirection::Decreasing,
113            },
114            detailed_analysis: "Energy consumption remained within optimal ranges. Peak power usage occurred during training hours (10 AM - 4 PM). Carbon intensity was 12% lower than regional average due to increased renewable energy generation.".to_string(),
115            recommendations: vec![
116                SustainabilityRecommendation {
117                    category: RecommendationCategory::Energy,
118                    priority: RecommendationPriority::Medium,
119                    title: "Schedule training during low-carbon hours".to_string(),
120                    description: "Schedule intensive workloads during hours 2-6 AM when carbon intensity is lowest".to_string(),
121                    potential_impact: "15% carbon reduction possible".to_string(),
122                    implementation_steps: vec![
123                        "Analyze workload scheduling patterns".to_string(),
124                        "Implement automated scheduling system".to_string(),
125                        "Monitor carbon impact improvements".to_string(),
126                    ],
127                },
128                SustainabilityRecommendation {
129                    category: RecommendationCategory::Performance,
130                    priority: RecommendationPriority::Low,
131                    title: "Optimize cooling efficiency".to_string(),
132                    description: "Implement dynamic cooling adjustments based on workload intensity".to_string(),
133                    potential_impact: "8% energy reduction in cooling systems".to_string(),
134                    implementation_steps: vec![
135                        "Install smart temperature controls".to_string(),
136                        "Monitor cooling system efficiency".to_string(),
137                        "Adjust cooling based on real-time needs".to_string(),
138                    ],
139                },
140            ],
141            charts: vec![
142                ChartData {
143                    chart_type: VisualizationType::LineChart,
144                    title: "Daily Energy Consumption".to_string(),
145                    data_points: vec![
146                        ("00:00".to_string(), 45.2),
147                        ("06:00".to_string(), 52.1),
148                        ("12:00".to_string(), 78.9),
149                        ("18:00".to_string(), 65.3),
150                    ],
151                    labels: vec!["Time".to_string(), "kWh".to_string()],
152                },
153                ChartData {
154                    chart_type: VisualizationType::BarChart,
155                    title: "Carbon Emissions by Activity".to_string(),
156                    data_points: vec![
157                        ("Training".to_string(), 32.1),
158                        ("Inference".to_string(), 12.8),
159                        ("Data Processing".to_string(), 3.3),
160                    ],
161                    labels: vec!["Activity".to_string(), "kg CO2".to_string()],
162                },
163            ],
164        })
165    }
166
167    /// Generate weekly report
168    pub async fn generate_weekly_report(&self) -> Result<EnvironmentalReport> {
169        let period_start = SystemTime::now() - Duration::from_secs(7 * 24 * 3600);
170        let period_end = SystemTime::now();
171
172        Ok(EnvironmentalReport {
173            report_id: format!("weekly-{}", chrono::Utc::now().format("%Y-W%W")),
174            report_type: ReportType::Summary,
175            generated_at: SystemTime::now(),
176            period_start,
177            period_end,
178            summary: "Weekly environmental impact analysis showing trends and optimization opportunities".to_string(),
179            metrics: EnvironmentalDashboardMetrics {
180                total_energy_consumed_kwh: 843.5,
181                total_co2_emissions_kg: 337.4,
182                current_power_usage_watts: 750.0,
183                energy_efficiency_score: 0.85,
184                carbon_intensity_gco2_kwh: 400.0,
185                cost_per_hour_usd: 101.22,
186                trend: TrendDirection::Decreasing,
187            },
188            detailed_analysis: "Week-over-week improvements: 12% reduction in carbon emissions, 5% improvement in energy efficiency. Training workloads showed 18% better utilization due to batch size optimization.".to_string(),
189            recommendations: vec![
190                SustainabilityRecommendation {
191                    category: RecommendationCategory::Sustainability,
192                    priority: RecommendationPriority::High,
193                    title: "Implement weekly optimization schedule".to_string(),
194                    description: "Create recurring optimization cycles to maintain improvement momentum".to_string(),
195                    potential_impact: "Sustained 10-15% efficiency improvements".to_string(),
196                    implementation_steps: vec![
197                        "Schedule weekly efficiency audits".to_string(),
198                        "Automate optimization recommendations".to_string(),
199                        "Track improvement metrics consistently".to_string(),
200                    ],
201                },
202            ],
203            charts: vec![
204                ChartData {
205                    chart_type: VisualizationType::LineChart,
206                    title: "Weekly Energy Efficiency Trend".to_string(),
207                    data_points: vec![
208                        ("Week 1".to_string(), 0.80),
209                        ("Week 2".to_string(), 0.82),
210                        ("Week 3".to_string(), 0.85),
211                        ("Week 4".to_string(), 0.85),
212                    ],
213                    labels: vec!["Week".to_string(), "Efficiency Score".to_string()],
214                },
215            ],
216        })
217    }
218
219    /// Generate monthly report
220    pub async fn generate_monthly_report(&self) -> Result<EnvironmentalReport> {
221        let period_start = SystemTime::now() - Duration::from_secs(30 * 24 * 3600);
222        let period_end = SystemTime::now();
223
224        Ok(EnvironmentalReport {
225            report_id: format!("monthly-{}", chrono::Utc::now().format("%Y-%m")),
226            report_type: ReportType::Detailed,
227            generated_at: SystemTime::now(),
228            period_start,
229            period_end,
230            summary: "Monthly comprehensive analysis of environmental impact, goal progress, and strategic recommendations".to_string(),
231            metrics: EnvironmentalDashboardMetrics {
232                total_energy_consumed_kwh: 3674.2,
233                total_co2_emissions_kg: 1469.7,
234                current_power_usage_watts: 750.0,
235                energy_efficiency_score: 0.83,
236                carbon_intensity_gco2_kwh: 400.0,
237                cost_per_hour_usd: 440.90,
238                trend: TrendDirection::Decreasing,
239            },
240            detailed_analysis: "Monthly highlights: Achieved 65% progress on carbon reduction goal. Cost savings of $127 from optimization initiatives. Implemented 3 of 5 planned efficiency improvements. Regional carbon intensity averaged 15% below baseline.".to_string(),
241            recommendations: vec![
242                SustainabilityRecommendation {
243                    category: RecommendationCategory::Performance,
244                    priority: RecommendationPriority::High,
245                    title: "Focus on model efficiency optimization".to_string(),
246                    description: "Prioritize architectural improvements for next month's optimization cycle".to_string(),
247                    potential_impact: "20-30% efficiency improvement potential".to_string(),
248                    implementation_steps: vec![
249                        "Audit current model architectures".to_string(),
250                        "Implement pruning and quantization".to_string(),
251                        "Measure performance impact".to_string(),
252                        "Scale successful optimizations".to_string(),
253                    ],
254                },
255                SustainabilityRecommendation {
256                    category: RecommendationCategory::Sustainability,
257                    priority: RecommendationPriority::Medium,
258                    title: "Consider renewable energy procurement".to_string(),
259                    description: "Investigate renewable energy contracts for next quarter".to_string(),
260                    potential_impact: "40-60% carbon footprint reduction".to_string(),
261                    implementation_steps: vec![
262                        "Research renewable energy providers".to_string(),
263                        "Analyze cost-benefit of renewable contracts".to_string(),
264                        "Negotiate renewable energy agreements".to_string(),
265                        "Plan transition timeline".to_string(),
266                    ],
267                },
268            ],
269            charts: vec![
270                ChartData {
271                    chart_type: VisualizationType::LineChart,
272                    title: "Monthly Carbon Emissions Trend".to_string(),
273                    data_points: vec![
274                        ("Week 1".to_string(), 415.2),
275                        ("Week 2".to_string(), 380.1),
276                        ("Week 3".to_string(), 342.7),
277                        ("Week 4".to_string(), 331.7),
278                    ],
279                    labels: vec!["Week".to_string(), "kg CO2".to_string()],
280                },
281                ChartData {
282                    chart_type: VisualizationType::PieChart,
283                    title: "Energy Usage by Activity Type".to_string(),
284                    data_points: vec![
285                        ("Training".to_string(), 2574.0),
286                        ("Inference".to_string(), 735.0),
287                        ("Data Processing".to_string(), 220.0),
288                        ("Development".to_string(), 145.2),
289                    ],
290                    labels: vec!["Activity".to_string(), "kWh".to_string()],
291                },
292            ],
293        })
294    }
295
296    /// Generate annual report
297    pub async fn generate_annual_report(&self) -> Result<EnvironmentalReport> {
298        let period_start = SystemTime::now() - Duration::from_secs(365 * 24 * 3600);
299        let period_end = SystemTime::now();
300
301        Ok(EnvironmentalReport {
302            report_id: format!("annual-{}", chrono::Utc::now().format("%Y")),
303            report_type: ReportType::Executive,
304            generated_at: SystemTime::now(),
305            period_start,
306            period_end,
307            summary: "Annual environmental impact summary with strategic insights and long-term sustainability planning".to_string(),
308            metrics: EnvironmentalDashboardMetrics {
309                total_energy_consumed_kwh: 45000.0,
310                total_co2_emissions_kg: 18000.0,
311                current_power_usage_watts: 750.0,
312                energy_efficiency_score: 0.81,
313                carbon_intensity_gco2_kwh: 400.0,
314                cost_per_hour_usd: 5400.0,
315                trend: TrendDirection::Decreasing,
316            },
317            detailed_analysis: "Annual achievements: 18 tonnes CO2 total footprint (equivalent to 41,580 car miles). Implemented sustainability program with 35% efficiency improvement over baseline. Achieved ISO 14001 preliminary compliance. Established carbon offset program covering 60% of emissions.".to_string(),
318            recommendations: vec![
319                SustainabilityRecommendation {
320                    category: RecommendationCategory::Sustainability,
321                    priority: RecommendationPriority::Critical,
322                    title: "Implement comprehensive carbon reduction strategy".to_string(),
323                    description: "Develop multi-year carbon neutrality roadmap with specific milestones".to_string(),
324                    potential_impact: "Path to carbon neutrality by 2027".to_string(),
325                    implementation_steps: vec![
326                        "Set science-based carbon reduction targets".to_string(),
327                        "Invest in renewable energy infrastructure".to_string(),
328                        "Implement advanced carbon accounting".to_string(),
329                        "Establish carbon offset verification program".to_string(),
330                    ],
331                },
332                SustainabilityRecommendation {
333                    category: RecommendationCategory::Performance,
334                    priority: RecommendationPriority::High,
335                    title: "Invest in next-generation efficient hardware".to_string(),
336                    description: "Plan hardware refresh cycle with focus on energy-efficient compute".to_string(),
337                    potential_impact: "30-40% efficiency improvement over current hardware".to_string(),
338                    implementation_steps: vec![
339                        "Evaluate next-generation GPU efficiency".to_string(),
340                        "Plan phased hardware upgrade strategy".to_string(),
341                        "Implement hardware efficiency monitoring".to_string(),
342                        "Track ROI of efficiency investments".to_string(),
343                    ],
344                },
345            ],
346            charts: vec![
347                ChartData {
348                    chart_type: VisualizationType::LineChart,
349                    title: "Annual Carbon Footprint Progress".to_string(),
350                    data_points: vec![
351                        ("Q1".to_string(), 5200.0),
352                        ("Q2".to_string(), 4800.0),
353                        ("Q3".to_string(), 4200.0),
354                        ("Q4".to_string(), 3800.0),
355                    ],
356                    labels: vec!["Quarter".to_string(), "kg CO2".to_string()],
357                },
358                ChartData {
359                    chart_type: VisualizationType::Gauge,
360                    title: "Sustainability Goals Progress".to_string(),
361                    data_points: vec![
362                        ("Carbon Reduction".to_string(), 72.0),
363                        ("Energy Efficiency".to_string(), 65.0),
364                        ("Renewable Energy".to_string(), 45.0),
365                        ("Waste Reduction".to_string(), 58.0),
366                    ],
367                    labels: vec!["Goal".to_string(), "Progress %".to_string()],
368                },
369            ],
370        })
371    }
372
373    /// Generate specific report types
374    async fn generate_summary_report(&self) -> Result<EnvironmentalReport> {
375        self.generate_daily_report().await
376    }
377
378    async fn generate_detailed_report(&self) -> Result<EnvironmentalReport> {
379        self.generate_monthly_report().await
380    }
381
382    async fn generate_technical_report(&self) -> Result<EnvironmentalReport> {
383        let mut report = self.generate_monthly_report().await?;
384        report.report_type = ReportType::Technical;
385
386        // Add technical details
387        report.detailed_analysis = format!(
388            "{}\n\nTechnical Details:\n\
389            - Average GPU utilization: 84.2%\n\
390            - Memory bandwidth efficiency: 76.8%\n\
391            - Compute intensity: 12.4 FLOPS/Watt\n\
392            - Cooling system PUE: 1.18\n\
393            - Network energy overhead: 3.2%\n\
394            - Storage system efficiency: 89.1%",
395            report.detailed_analysis
396        );
397
398        // Add technical charts
399        report.charts.push(ChartData {
400            chart_type: VisualizationType::Heatmap,
401            title: "Hardware Utilization Matrix".to_string(),
402            data_points: vec![
403                ("GPU-0".to_string(), 85.2),
404                ("GPU-1".to_string(), 82.7),
405                ("CPU-0".to_string(), 45.3),
406                ("Memory".to_string(), 67.8),
407            ],
408            labels: vec!["Component".to_string(), "Utilization %".to_string()],
409        });
410
411        Ok(report)
412    }
413
414    async fn generate_executive_report(&self) -> Result<EnvironmentalReport> {
415        let mut report = self.generate_monthly_report().await?;
416        report.report_type = ReportType::Executive;
417
418        // Focus on high-level metrics and business impact
419        report.summary = "Executive Summary: Monthly environmental performance shows strong progress toward sustainability goals with measurable business benefits including cost reduction and operational efficiency gains.".to_string();
420
421        report.detailed_analysis = "Key Business Impacts:\n\
422            • $127 monthly cost savings from efficiency optimization\n\
423            • 15% reduction in operational energy costs\n\
424            • Improved compliance posture for environmental regulations\n\
425            • Enhanced corporate sustainability credentials\n\
426            • Risk mitigation for carbon pricing exposure\n\n\
427            Strategic Recommendations:\n\
428            • Accelerate renewable energy procurement timeline\n\
429            • Invest in efficiency monitoring infrastructure\n\
430            • Establish formal sustainability governance structure"
431            .to_string();
432
433        Ok(report)
434    }
435
436    async fn generate_compliance_report(&self) -> Result<EnvironmentalReport> {
437        let mut report = self.generate_monthly_report().await?;
438        report.report_type = ReportType::Compliance;
439
440        // Add compliance-specific information
441        report.summary = "Environmental Compliance Report: Assessment of current compliance status against environmental regulations and certification requirements.".to_string();
442
443        report.detailed_analysis = "Compliance Status:\n\
444            • ISO 14001: 65% compliance (target: 100%)\n\
445            • Energy Star: 45% compliance (target: 80%)\n\
446            • Carbon Trust Standard: 30% compliance (target: 90%)\n\
447            • Regional emissions reporting: Fully compliant\n\
448            • Energy efficiency disclosure: Fully compliant\n\n\
449            Required Actions:\n\
450            • Implement formal environmental management system\n\
451            • Establish third-party verification processes\n\
452            • Develop comprehensive carbon accounting system\n\
453            • Create audit trail for all environmental metrics"
454            .to_string();
455
456        // Add compliance-specific recommendations
457        report.recommendations.push(SustainabilityRecommendation {
458            category: RecommendationCategory::Sustainability,
459            priority: RecommendationPriority::Critical,
460            title: "Accelerate compliance program implementation".to_string(),
461            description: "Fast-track environmental management system implementation to meet regulatory requirements".to_string(),
462            potential_impact: "Full regulatory compliance within 6 months".to_string(),
463            implementation_steps: vec![
464                "Engage environmental compliance consultant".to_string(),
465                "Implement formal environmental management system".to_string(),
466                "Establish third-party verification processes".to_string(),
467                "Schedule compliance audits".to_string(),
468            ],
469        });
470
471        Ok(report)
472    }
473
474    /// Retain `report` in the in-memory automated-report log, dropping the
475    /// oldest once [`MAX_AUTOMATED_REPORTS`] is reached.
476    fn store_automated_report(&mut self, report: &EnvironmentalReport) -> Result<()> {
477        let automated_report = AutomatedReport {
478            report_id: report.report_id.clone(),
479            generated_at: report.generated_at,
480            report_type: format!("{:?}", report.report_type),
481            content: format!("{}\n\n{}", report.summary, report.detailed_analysis),
482        };
483
484        let report_id = automated_report.report_id.clone();
485        self.automated_reports.push(automated_report);
486        if self.automated_reports.len() > MAX_AUTOMATED_REPORTS {
487            self.automated_reports.remove(0);
488        }
489        info!("Stored automated report: {}", report_id);
490        Ok(())
491    }
492
493    /// Update dashboard metrics
494    pub fn update_dashboard_metrics(&mut self, metrics: EnvironmentalDashboardMetrics) {
495        self.dashboard_metrics = metrics;
496    }
497
498    /// Get current dashboard metrics
499    pub fn get_dashboard_metrics(&self) -> &EnvironmentalDashboardMetrics {
500        &self.dashboard_metrics
501    }
502
503    /// Get automated reports history
504    pub fn get_automated_reports(&self) -> &[AutomatedReport] {
505        &self.automated_reports
506    }
507
508    /// Initialize default report templates
509    fn initialize_report_templates() -> HashMap<String, ReportTemplate> {
510        let mut templates = HashMap::new();
511
512        templates.insert(
513            "daily_summary".to_string(),
514            ReportTemplate {
515                template_name: "Daily Environmental Summary".to_string(),
516                target_audience: "Operations Team".to_string(),
517                frequency: ReportFrequency::Daily,
518                sections: vec![
519                    ReportSection {
520                        section_name: "Energy Consumption".to_string(),
521                        metrics_included: vec![
522                            "total_energy_kwh".to_string(),
523                            "peak_power".to_string(),
524                        ],
525                        visualization_type: VisualizationType::LineChart,
526                    },
527                    ReportSection {
528                        section_name: "Carbon Emissions".to_string(),
529                        metrics_included: vec![
530                            "total_co2_kg".to_string(),
531                            "carbon_intensity".to_string(),
532                        ],
533                        visualization_type: VisualizationType::BarChart,
534                    },
535                ],
536            },
537        );
538
539        templates.insert(
540            "executive_monthly".to_string(),
541            ReportTemplate {
542                template_name: "Executive Monthly Report".to_string(),
543                target_audience: "Executive Leadership".to_string(),
544                frequency: ReportFrequency::Monthly,
545                sections: vec![
546                    ReportSection {
547                        section_name: "Strategic Metrics".to_string(),
548                        metrics_included: vec![
549                            "sustainability_score".to_string(),
550                            "cost_savings".to_string(),
551                        ],
552                        visualization_type: VisualizationType::Gauge,
553                    },
554                    ReportSection {
555                        section_name: "Goal Progress".to_string(),
556                        metrics_included: vec![
557                            "carbon_goal_progress".to_string(),
558                            "efficiency_goal_progress".to_string(),
559                        ],
560                        visualization_type: VisualizationType::Table,
561                    },
562                ],
563            },
564        );
565
566        templates
567    }
568
569    /// Generate custom report for specific period
570    pub async fn generate_custom_report(&self, period: Duration) -> Result<EnvironmentalReport> {
571        let period_start = SystemTime::now() - period;
572        let period_end = SystemTime::now();
573
574        Ok(EnvironmentalReport {
575            report_id: format!("custom-{}", chrono::Utc::now().format("%Y%m%d-%H%M")),
576            report_type: ReportType::Summary,
577            generated_at: SystemTime::now(),
578            period_start,
579            period_end,
580            summary: format!("Custom period environmental analysis covering {:.1} days",
581                           period.as_secs_f64() / (24.0 * 3600.0)),
582            metrics: self.dashboard_metrics.clone(),
583            detailed_analysis: "Custom period analysis showing environmental metrics and trends for the specified timeframe".to_string(),
584            recommendations: vec![
585                SustainabilityRecommendation {
586                    category: RecommendationCategory::Performance,
587                    priority: RecommendationPriority::Medium,
588                    title: "Continue monitoring trends".to_string(),
589                    description: "Maintain current monitoring practices and look for optimization opportunities".to_string(),
590                    potential_impact: "Ongoing efficiency improvements".to_string(),
591                    implementation_steps: vec![
592                        "Review custom period insights".to_string(),
593                        "Identify actionable optimization opportunities".to_string(),
594                        "Plan implementation of improvements".to_string(),
595                    ],
596                },
597            ],
598            charts: vec![
599                ChartData {
600                    chart_type: VisualizationType::LineChart,
601                    title: "Custom Period Energy Trend".to_string(),
602                    data_points: vec![
603                        ("Start".to_string(), 100.0),
604                        ("Mid".to_string(), 95.5),
605                        ("End".to_string(), 88.2),
606                    ],
607                    labels: vec!["Time".to_string(), "Energy".to_string()],
608                },
609            ],
610        })
611    }
612}
613
614#[cfg(test)]
615mod tests {
616    use super::*;
617
618    #[tokio::test]
619    async fn generated_reports_are_really_retained() {
620        let mut engine = EnvironmentalReportingEngine::new();
621        assert!(engine.get_automated_reports().is_empty());
622
623        let report = engine
624            .generate_environmental_report(ReportType::Summary)
625            .await
626            .expect("report generation");
627
628        // `store_automated_report` used to take `&self`, build an
629        // `AutomatedReport`, log "Stored automated report: {id}" and drop it,
630        // so this log stayed empty no matter how many reports were generated.
631        let stored = engine.get_automated_reports();
632        assert_eq!(
633            stored.len(),
634            1,
635            "the generated report must really be retained"
636        );
637        assert_eq!(stored[0].report_id, report.report_id);
638        assert!(stored[0].content.contains(&report.summary));
639    }
640
641    #[tokio::test]
642    async fn the_automated_report_log_is_bounded() {
643        let mut engine = EnvironmentalReportingEngine::new();
644        for _ in 0..(MAX_AUTOMATED_REPORTS + 5) {
645            engine
646                .generate_environmental_report(ReportType::Summary)
647                .await
648                .expect("report generation");
649        }
650        assert_eq!(
651            engine.get_automated_reports().len(),
652            MAX_AUTOMATED_REPORTS,
653            "the oldest reports must be dropped, not accumulated without bound"
654        );
655    }
656
657    #[test]
658    fn test_reporting_engine_creation() {
659        let engine = EnvironmentalReportingEngine::new();
660        assert!(!engine.report_templates.is_empty());
661    }
662
663    #[tokio::test]
664    async fn test_daily_report_generation() {
665        let engine = EnvironmentalReportingEngine::new();
666        let report = engine.generate_daily_report().await.expect("async operation failed");
667
668        assert!(!report.report_id.is_empty());
669        assert!(!report.summary.is_empty());
670        assert!(!report.recommendations.is_empty());
671        assert!(!report.charts.is_empty());
672    }
673
674    #[tokio::test]
675    async fn test_all_report_types() {
676        let mut engine = EnvironmentalReportingEngine::new();
677
678        let summary_report = engine
679            .generate_environmental_report(ReportType::Summary)
680            .await
681            .expect("async operation failed");
682        let detailed_report = engine
683            .generate_environmental_report(ReportType::Detailed)
684            .await
685            .expect("async operation failed");
686        let technical_report = engine
687            .generate_environmental_report(ReportType::Technical)
688            .await
689            .expect("async operation failed");
690        let executive_report = engine
691            .generate_environmental_report(ReportType::Executive)
692            .await
693            .expect("async operation failed");
694        let compliance_report = engine
695            .generate_environmental_report(ReportType::Compliance)
696            .await
697            .expect("async operation failed");
698
699        assert_eq!(summary_report.report_type, ReportType::Summary);
700        assert_eq!(detailed_report.report_type, ReportType::Detailed);
701        assert_eq!(technical_report.report_type, ReportType::Technical);
702        assert_eq!(executive_report.report_type, ReportType::Executive);
703        assert_eq!(compliance_report.report_type, ReportType::Compliance);
704    }
705
706    #[tokio::test]
707    async fn test_custom_report_generation() {
708        let engine = EnvironmentalReportingEngine::new();
709        let custom_period = Duration::from_secs(7 * 24 * 3600); // 7 days
710
711        let report = engine
712            .generate_custom_report(custom_period)
713            .await
714            .expect("async operation failed");
715
716        assert!(report.summary.contains("7.0 days"));
717        assert!(!report.charts.is_empty());
718    }
719
720    #[test]
721    fn test_dashboard_metrics_update() {
722        let mut engine = EnvironmentalReportingEngine::new();
723
724        let new_metrics = EnvironmentalDashboardMetrics {
725            total_energy_consumed_kwh: 250.0,
726            total_co2_emissions_kg: 100.0,
727            current_power_usage_watts: 800.0,
728            energy_efficiency_score: 0.9,
729            carbon_intensity_gco2_kwh: 350.0,
730            cost_per_hour_usd: 15.0,
731            trend: TrendDirection::Decreasing,
732        };
733
734        engine.update_dashboard_metrics(new_metrics.clone());
735
736        let updated_metrics = engine.get_dashboard_metrics();
737        assert_eq!(updated_metrics.total_energy_consumed_kwh, 250.0);
738        assert_eq!(updated_metrics.energy_efficiency_score, 0.9);
739    }
740
741    #[tokio::test]
742    async fn test_report_content_quality() {
743        let engine = EnvironmentalReportingEngine::new();
744        let report = engine.generate_monthly_report().await.expect("async operation failed");
745
746        // Verify report has substantive content
747        assert!(report.summary.len() > 50);
748        assert!(report.detailed_analysis.len() > 100);
749        assert!(!report.recommendations.is_empty());
750
751        // Verify recommendations have required fields
752        for rec in &report.recommendations {
753            assert!(!rec.title.is_empty());
754            assert!(!rec.description.is_empty());
755            assert!(!rec.implementation_steps.is_empty());
756        }
757
758        // Verify charts have data
759        for chart in &report.charts {
760            assert!(!chart.title.is_empty());
761            assert!(!chart.data_points.is_empty());
762            assert!(!chart.labels.is_empty());
763        }
764    }
765}