Skip to main content

leptos_next_metadata/analytics/
mod.rs

1//! Analytics Integration for Metadata Usage Tracking
2//!
3//! Provides comprehensive analytics and insights for metadata performance,
4//! usage patterns, and optimization recommendations.
5
6pub mod handlers;
7pub mod integration;
8#[cfg(target_arch = "wasm32")]
9pub mod wasm;
10
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13use std::time::{SystemTime, UNIX_EPOCH};
14
15use crate::error::{ErrorKind, MetadataError};
16
17/// Analytics event types
18#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
19pub enum AnalyticsEventType {
20    /// Metadata was generated
21    MetadataGenerated,
22    /// OG image was created
23    OgImageGenerated,
24    /// Theme was applied
25    ThemeApplied,
26    /// Metadata was validated
27    MetadataValidated,
28    /// Performance measurement
29    PerformanceMeasured,
30    /// Error occurred
31    ErrorOccurred,
32    /// User interaction
33    UserInteraction,
34    /// Custom event
35    Custom(String),
36}
37
38impl std::fmt::Display for AnalyticsEventType {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        match self {
41            AnalyticsEventType::MetadataGenerated => write!(f, "metadata_generated"),
42            AnalyticsEventType::OgImageGenerated => write!(f, "og_image_generated"),
43            AnalyticsEventType::ThemeApplied => write!(f, "theme_applied"),
44            AnalyticsEventType::MetadataValidated => write!(f, "metadata_validated"),
45            AnalyticsEventType::PerformanceMeasured => write!(f, "performance_measured"),
46            AnalyticsEventType::ErrorOccurred => write!(f, "error_occurred"),
47            AnalyticsEventType::UserInteraction => write!(f, "user_interaction"),
48            AnalyticsEventType::Custom(name) => write!(f, "custom_{}", name),
49        }
50    }
51}
52
53/// Analytics event with metadata
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct AnalyticsEvent {
56    /// Event type
57    pub event_type: AnalyticsEventType,
58    /// Event timestamp (Unix timestamp)
59    pub timestamp: u64,
60    /// Event duration in milliseconds (for performance events)
61    pub duration_ms: Option<u64>,
62    /// Event properties/metadata
63    pub properties: HashMap<String, serde_json::Value>,
64    /// User/session identifier
65    pub session_id: Option<String>,
66    /// Page/route identifier
67    pub page_id: Option<String>,
68    /// Error details (if applicable)
69    pub error: Option<ErrorDetails>,
70}
71
72/// Error details for analytics
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct ErrorDetails {
75    /// Error message
76    pub message: String,
77    /// Error kind
78    pub kind: String,
79    /// Stack trace (if available)
80    pub stack_trace: Option<String>,
81    /// Context information
82    pub context: HashMap<String, serde_json::Value>,
83}
84
85/// Performance metrics
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct PerformanceMetrics {
88    /// Generation time in milliseconds
89    pub generation_time_ms: u64,
90    /// Memory usage in bytes
91    pub memory_usage_bytes: Option<u64>,
92    /// Cache hit rate (0.0 to 1.0)
93    pub cache_hit_rate: Option<f64>,
94    /// Success rate (0.0 to 1.0)
95    pub success_rate: f64,
96    /// Error count
97    pub error_count: u32,
98    /// Total operations
99    pub total_operations: u32,
100}
101
102/// Analytics session
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct AnalyticsSession {
105    /// Session ID
106    pub session_id: String,
107    /// Session start time
108    pub start_time: u64,
109    /// Session end time (if ended)
110    pub end_time: Option<u64>,
111    /// User agent
112    pub user_agent: Option<String>,
113    /// Page views
114    pub page_views: u32,
115    /// Events in this session
116    pub events: Vec<AnalyticsEvent>,
117    /// Performance metrics
118    pub performance: PerformanceMetrics,
119}
120
121/// Analytics configuration
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct AnalyticsConfig {
124    /// Enable analytics tracking
125    pub enabled: bool,
126    /// Batch size for sending events
127    pub batch_size: usize,
128    /// Flush interval in seconds
129    pub flush_interval_seconds: u64,
130    /// Maximum events to store locally
131    pub max_local_events: usize,
132    /// Enable performance tracking
133    pub track_performance: bool,
134    /// Enable error tracking
135    pub track_errors: bool,
136    /// Enable user interaction tracking
137    pub track_interactions: bool,
138    /// Custom event types to track
139    pub custom_event_types: Vec<String>,
140    /// Privacy settings
141    pub privacy: PrivacySettings,
142}
143
144/// Privacy settings for analytics
145#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct PrivacySettings {
147    /// Anonymize IP addresses
148    pub anonymize_ip: bool,
149    /// Hash user identifiers
150    pub hash_identifiers: bool,
151    /// Collect user agent
152    pub collect_user_agent: bool,
153    /// Collect page URLs
154    pub collect_page_urls: bool,
155    /// Data retention period in days
156    pub retention_days: u32,
157}
158
159impl Default for PrivacySettings {
160    fn default() -> Self {
161        Self {
162            anonymize_ip: true,
163            hash_identifiers: true,
164            collect_user_agent: true,
165            collect_page_urls: true,
166            retention_days: 90,
167        }
168    }
169}
170
171impl Default for AnalyticsConfig {
172    fn default() -> Self {
173        Self {
174            enabled: true,
175            batch_size: 10,
176            flush_interval_seconds: 30,
177            max_local_events: 1000,
178            track_performance: true,
179            track_errors: true,
180            track_interactions: true,
181            custom_event_types: vec![],
182            privacy: PrivacySettings::default(),
183        }
184    }
185}
186
187/// Analytics insights and recommendations
188#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct AnalyticsInsights {
190    /// Performance insights
191    pub performance: PerformanceInsights,
192    /// Usage patterns
193    pub usage: UsageInsights,
194    /// Error analysis
195    pub errors: ErrorInsights,
196    /// Recommendations
197    pub recommendations: Vec<Recommendation>,
198    /// Generated at timestamp
199    pub generated_at: u64,
200}
201
202/// Performance insights
203#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct PerformanceInsights {
205    /// Average generation time
206    pub avg_generation_time_ms: f64,
207    /// Slowest operations
208    pub slowest_operations: Vec<SlowOperation>,
209    /// Performance trends
210    pub trends: PerformanceTrends,
211    /// Optimization opportunities
212    pub optimization_opportunities: Vec<String>,
213}
214
215/// Slow operation details
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct SlowOperation {
218    /// Operation type
219    pub operation_type: String,
220    /// Average duration
221    pub avg_duration_ms: f64,
222    /// Occurrence count
223    pub count: u32,
224    /// Last occurrence
225    pub last_occurrence: u64,
226}
227
228/// Performance trends
229#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct PerformanceTrends {
231    /// Trend direction (improving, declining, stable)
232    pub direction: TrendDirection,
233    /// Change percentage
234    pub change_percentage: f64,
235    /// Time period
236    pub time_period: String,
237}
238
239/// Trend direction
240#[derive(Debug, Clone, Serialize, Deserialize)]
241pub enum TrendDirection {
242    Improving,
243    Declining,
244    Stable,
245}
246
247/// Usage insights
248#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct UsageInsights {
250    /// Most used features
251    pub popular_features: Vec<FeatureUsage>,
252    /// Usage patterns by time
253    pub time_patterns: TimePatterns,
254    /// User engagement metrics
255    pub engagement: EngagementMetrics,
256    /// Feature adoption
257    pub adoption: FeatureAdoption,
258}
259
260/// Feature usage statistics
261#[derive(Debug, Clone, Serialize, Deserialize)]
262pub struct FeatureUsage {
263    /// Feature name
264    pub feature_name: String,
265    /// Usage count
266    pub usage_count: u32,
267    /// Usage percentage
268    pub usage_percentage: f64,
269    /// Last used
270    pub last_used: u64,
271}
272
273/// Time-based usage patterns
274#[derive(Debug, Clone, Serialize, Deserialize)]
275pub struct TimePatterns {
276    /// Peak usage hours
277    pub peak_hours: Vec<u8>,
278    /// Usage by day of week
279    pub day_of_week: HashMap<String, u32>,
280    /// Usage by month
281    pub monthly: HashMap<String, u32>,
282}
283
284/// User engagement metrics
285#[derive(Debug, Clone, Serialize, Deserialize)]
286pub struct EngagementMetrics {
287    /// Average session duration
288    pub avg_session_duration_ms: f64,
289    /// Bounce rate
290    pub bounce_rate: f64,
291    /// Return user rate
292    pub return_user_rate: f64,
293    /// Feature depth (how many features used per session)
294    pub feature_depth: f64,
295}
296
297/// Feature adoption metrics
298#[derive(Debug, Clone, Serialize, Deserialize)]
299pub struct FeatureAdoption {
300    /// New features adopted
301    pub new_features: Vec<String>,
302    /// Adoption rate
303    pub adoption_rate: f64,
304    /// Time to adoption (days)
305    pub time_to_adoption_days: f64,
306}
307
308/// Error insights
309#[derive(Debug, Clone, Serialize, Deserialize)]
310pub struct ErrorInsights {
311    /// Most common errors
312    pub common_errors: Vec<CommonError>,
313    /// Error trends
314    pub error_trends: ErrorTrends,
315    /// Error resolution
316    pub resolution: ErrorResolution,
317}
318
319/// Common error details
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct CommonError {
322    /// Error type
323    pub error_type: String,
324    /// Error count
325    pub count: u32,
326    /// Error rate
327    pub rate: f64,
328    /// Last occurrence
329    pub last_occurrence: u64,
330    /// Common context
331    pub common_context: HashMap<String, serde_json::Value>,
332}
333
334/// Error trends
335#[derive(Debug, Clone, Serialize, Deserialize)]
336pub struct ErrorTrends {
337    /// Overall error rate trend
338    pub overall_trend: TrendDirection,
339    /// Error rate change
340    pub rate_change: f64,
341    /// New error types
342    pub new_error_types: Vec<String>,
343}
344
345/// Error resolution metrics
346#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct ErrorResolution {
348    /// Auto-resolved errors
349    pub auto_resolved: u32,
350    /// Manual resolution rate
351    pub manual_resolution_rate: f64,
352    /// Average resolution time
353    pub avg_resolution_time_ms: f64,
354}
355
356/// Analytics recommendation
357#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct Recommendation {
359    /// Recommendation type
360    pub recommendation_type: RecommendationType,
361    /// Priority level
362    pub priority: Priority,
363    /// Title
364    pub title: String,
365    /// Description
366    pub description: String,
367    /// Action items
368    pub action_items: Vec<String>,
369    /// Expected impact
370    pub expected_impact: String,
371    /// Implementation effort
372    pub implementation_effort: EffortLevel,
373}
374
375/// Recommendation types
376#[derive(Debug, Clone, Serialize, Deserialize)]
377pub enum RecommendationType {
378    Performance,
379    ErrorReduction,
380    FeatureUsage,
381    UserExperience,
382    Security,
383    CostOptimization,
384}
385
386/// Priority levels
387#[derive(Debug, Clone, Serialize, Deserialize)]
388pub enum Priority {
389    Low,
390    Medium,
391    High,
392    Critical,
393}
394
395/// Implementation effort levels
396#[derive(Debug, Clone, Serialize, Deserialize)]
397pub enum EffortLevel {
398    Low,
399    Medium,
400    High,
401}
402
403/// Analytics manager for tracking and insights
404pub struct AnalyticsManager {
405    /// Analytics configuration
406    config: AnalyticsConfig,
407    /// Current session
408    current_session: Option<AnalyticsSession>,
409    /// Event queue
410    event_queue: Vec<AnalyticsEvent>,
411    /// Performance metrics
412    performance_metrics: PerformanceMetrics,
413    /// Event handlers
414    event_handlers: Vec<Box<dyn AnalyticsEventHandler>>,
415}
416
417/// Trait for analytics event handlers
418pub trait AnalyticsEventHandler: Send + Sync {
419    /// Handle an analytics event
420    fn handle_event(&self, event: &AnalyticsEvent) -> Result<(), MetadataError>;
421
422    /// Handle a batch of events
423    fn handle_batch(&self, events: &[AnalyticsEvent]) -> Result<(), MetadataError>;
424
425    /// Get handler name
426    fn name(&self) -> &str;
427}
428
429impl AnalyticsManager {
430    /// Create a new analytics manager
431    pub fn new(config: AnalyticsConfig) -> Self {
432        Self {
433            config,
434            current_session: None,
435            event_queue: Vec::new(),
436            performance_metrics: PerformanceMetrics {
437                generation_time_ms: 0,
438                memory_usage_bytes: None,
439                cache_hit_rate: None,
440                success_rate: 1.0,
441                error_count: 0,
442                total_operations: 0,
443            },
444            event_handlers: Vec::new(),
445        }
446    }
447
448    /// Start a new analytics session
449    pub fn start_session(
450        &mut self,
451        session_id: String,
452        user_agent: Option<String>,
453    ) -> Result<(), MetadataError> {
454        if !self.config.enabled {
455            return Ok(());
456        }
457
458        let current_time = SystemTime::now()
459            .duration_since(UNIX_EPOCH)
460            .map_err(|e| MetadataError::new(ErrorKind::Unknown, e.to_string()))?
461            .as_secs();
462
463        self.current_session = Some(AnalyticsSession {
464            session_id,
465            start_time: current_time,
466            end_time: None,
467            user_agent,
468            page_views: 0,
469            events: Vec::new(),
470            performance: self.performance_metrics.clone(),
471        });
472
473        Ok(())
474    }
475
476    /// End the current session
477    pub fn end_session(&mut self) -> Result<(), MetadataError> {
478        if !self.config.enabled {
479            return Ok(());
480        }
481
482        if let Some(session) = &mut self.current_session {
483            let current_time = SystemTime::now()
484                .duration_since(UNIX_EPOCH)
485                .map_err(|e| MetadataError::new(ErrorKind::Unknown, e.to_string()))?
486                .as_secs();
487
488            session.end_time = Some(current_time);
489
490            // Flush remaining events
491            self.flush_events()?;
492        }
493
494        self.current_session = None;
495        Ok(())
496    }
497
498    /// Track an analytics event
499    pub fn track_event(
500        &mut self,
501        event_type: AnalyticsEventType,
502        properties: HashMap<String, serde_json::Value>,
503        duration_ms: Option<u64>,
504    ) -> Result<(), MetadataError> {
505        if !self.config.enabled {
506            return Ok(());
507        }
508
509        let current_time = SystemTime::now()
510            .duration_since(UNIX_EPOCH)
511            .map_err(|e| MetadataError::new(ErrorKind::Unknown, e.to_string()))?
512            .as_secs();
513
514        let event = AnalyticsEvent {
515            event_type,
516            timestamp: current_time,
517            duration_ms,
518            properties,
519            session_id: self.current_session.as_ref().map(|s| s.session_id.clone()),
520            page_id: None,
521            error: None,
522        };
523
524        self.add_event(event)?;
525        Ok(())
526    }
527
528    /// Track a performance event
529    pub fn track_performance(
530        &mut self,
531        operation_type: &str,
532        duration_ms: u64,
533        success: bool,
534        memory_usage_bytes: Option<u64>,
535    ) -> Result<(), MetadataError> {
536        if !self.config.enabled || !self.config.track_performance {
537            return Ok(());
538        }
539
540        let mut properties = HashMap::new();
541        properties.insert(
542            "operation_type".to_string(),
543            serde_json::Value::String(operation_type.to_string()),
544        );
545        properties.insert("success".to_string(), serde_json::Value::Bool(success));
546
547        if let Some(memory) = memory_usage_bytes {
548            properties.insert(
549                "memory_usage_bytes".to_string(),
550                serde_json::Value::Number(serde_json::Number::from(memory)),
551            );
552        }
553
554        // Update performance metrics
555        self.performance_metrics.total_operations += 1;
556        if !success {
557            self.performance_metrics.error_count += 1;
558        }
559
560        self.performance_metrics.success_rate = (self.performance_metrics.total_operations
561            - self.performance_metrics.error_count)
562            as f64
563            / self.performance_metrics.total_operations as f64;
564
565        self.track_event(
566            AnalyticsEventType::PerformanceMeasured,
567            properties,
568            Some(duration_ms),
569        )?;
570        Ok(())
571    }
572
573    /// Track an error event
574    pub fn track_error(
575        &mut self,
576        error: MetadataError,
577        context: HashMap<String, serde_json::Value>,
578    ) -> Result<(), MetadataError> {
579        if !self.config.enabled || !self.config.track_errors {
580            return Ok(());
581        }
582
583        let error_details = ErrorDetails {
584            message: error.message.clone(),
585            kind: format!("{:?}", error.kind),
586            stack_trace: None, // Would be populated in a real implementation
587            context,
588        };
589
590        let mut properties = HashMap::new();
591        properties.insert(
592            "error_message".to_string(),
593            serde_json::Value::String(error.message),
594        );
595        properties.insert(
596            "error_kind".to_string(),
597            serde_json::Value::String(format!("{:?}", error.kind)),
598        );
599
600        let event = AnalyticsEvent {
601            event_type: AnalyticsEventType::ErrorOccurred,
602            timestamp: SystemTime::now()
603                .duration_since(UNIX_EPOCH)
604                .map_err(|e| MetadataError::new(ErrorKind::Unknown, e.to_string()))?
605                .as_secs(),
606            duration_ms: None,
607            properties,
608            session_id: self.current_session.as_ref().map(|s| s.session_id.clone()),
609            page_id: None,
610            error: Some(error_details),
611        };
612
613        self.add_event(event)?;
614        Ok(())
615    }
616
617    /// Add an event to the queue
618    fn add_event(&mut self, event: AnalyticsEvent) -> Result<(), MetadataError> {
619        self.event_queue.push(event);
620
621        // Add to current session if available
622        if let Some(session) = &mut self.current_session {
623            session
624                .events
625                .push(self.event_queue.last().unwrap().clone());
626        }
627
628        // Flush if batch size reached
629        if self.event_queue.len() >= self.config.batch_size {
630            self.flush_events()?;
631        }
632
633        Ok(())
634    }
635
636    /// Flush events to handlers
637    fn flush_events(&mut self) -> Result<(), MetadataError> {
638        if self.event_queue.is_empty() {
639            return Ok(());
640        }
641
642        let events = self.event_queue.clone();
643        self.event_queue.clear();
644
645        // Send to all handlers
646        for handler in &self.event_handlers {
647            if let Err(e) = handler.handle_batch(&events) {
648                eprintln!("Analytics handler {} failed: {}", handler.name(), e.message);
649            }
650        }
651
652        Ok(())
653    }
654
655    /// Add an event handler
656    pub fn add_handler(&mut self, handler: Box<dyn AnalyticsEventHandler>) {
657        self.event_handlers.push(handler);
658    }
659
660    /// Generate analytics insights
661    pub fn generate_insights(&self) -> Result<AnalyticsInsights, MetadataError> {
662        let current_time = SystemTime::now()
663            .duration_since(UNIX_EPOCH)
664            .map_err(|e| MetadataError::new(ErrorKind::Unknown, e.to_string()))?
665            .as_secs();
666
667        // Collect all events from current session
668        let mut all_events = Vec::new();
669        if let Some(session) = &self.current_session {
670            all_events.extend(session.events.clone());
671        }
672        all_events.extend(self.event_queue.clone());
673
674        let performance = self.analyze_performance(&all_events);
675        let usage = self.analyze_usage(&all_events);
676        let errors = self.analyze_errors(&all_events);
677        let recommendations = self.generate_recommendations(&performance, &usage, &errors);
678
679        Ok(AnalyticsInsights {
680            performance,
681            usage,
682            errors,
683            recommendations,
684            generated_at: current_time,
685        })
686    }
687
688    /// Analyze performance metrics
689    fn analyze_performance(&self, events: &[AnalyticsEvent]) -> PerformanceInsights {
690        let performance_events: Vec<_> = events
691            .iter()
692            .filter(|e| matches!(e.event_type, AnalyticsEventType::PerformanceMeasured))
693            .collect();
694
695        let avg_generation_time = if !performance_events.is_empty() {
696            let total_time: u64 = performance_events
697                .iter()
698                .filter_map(|e| e.duration_ms)
699                .sum();
700            total_time as f64 / performance_events.len() as f64
701        } else {
702            0.0
703        };
704
705        let slowest_operations = self.identify_slow_operations(&performance_events);
706        let trends = self.calculate_performance_trends(&performance_events);
707        let optimization_opportunities =
708            self.identify_optimization_opportunities(&performance_events);
709
710        PerformanceInsights {
711            avg_generation_time_ms: avg_generation_time,
712            slowest_operations,
713            trends,
714            optimization_opportunities,
715        }
716    }
717
718    /// Analyze usage patterns
719    fn analyze_usage(&self, events: &[AnalyticsEvent]) -> UsageInsights {
720        let popular_features = self.identify_popular_features(events);
721        let time_patterns = self.analyze_time_patterns(events);
722        let engagement = self.calculate_engagement_metrics(events);
723        let adoption = self.calculate_feature_adoption(events);
724
725        UsageInsights {
726            popular_features,
727            time_patterns,
728            engagement,
729            adoption,
730        }
731    }
732
733    /// Analyze error patterns
734    fn analyze_errors(&self, events: &[AnalyticsEvent]) -> ErrorInsights {
735        let error_events: Vec<_> = events
736            .iter()
737            .filter(|e| matches!(e.event_type, AnalyticsEventType::ErrorOccurred))
738            .collect();
739
740        let common_errors = self.identify_common_errors(&error_events);
741        let error_trends = self.calculate_error_trends(&error_events);
742        let resolution = self.calculate_error_resolution(&error_events);
743
744        ErrorInsights {
745            common_errors,
746            error_trends,
747            resolution,
748        }
749    }
750
751    /// Identify slow operations
752    fn identify_slow_operations(&self, events: &[&AnalyticsEvent]) -> Vec<SlowOperation> {
753        let mut operation_times: HashMap<String, Vec<u64>> = HashMap::new();
754
755        for event in events {
756            if let Some(duration) = event.duration_ms {
757                if let Some(operation_type) = event.properties.get("operation_type") {
758                    if let Some(op_type) = operation_type.as_str() {
759                        operation_times
760                            .entry(op_type.to_string())
761                            .or_default()
762                            .push(duration);
763                    }
764                }
765            }
766        }
767
768        let mut slow_operations = Vec::new();
769        for (operation_type, times) in operation_times {
770            let avg_duration = times.iter().sum::<u64>() as f64 / times.len() as f64;
771            let last_occurrence = events
772                .iter()
773                .filter(|e| {
774                    e.properties.get("operation_type").and_then(|v| v.as_str())
775                        == Some(&operation_type)
776                })
777                .map(|e| e.timestamp)
778                .max()
779                .unwrap_or(0);
780
781            slow_operations.push(SlowOperation {
782                operation_type,
783                avg_duration_ms: avg_duration,
784                count: times.len() as u32,
785                last_occurrence,
786            });
787        }
788
789        slow_operations.sort_by(|a, b| b.avg_duration_ms.partial_cmp(&a.avg_duration_ms).unwrap());
790        slow_operations.truncate(5); // Top 5 slowest operations
791        slow_operations
792    }
793
794    /// Calculate performance trends
795    fn calculate_performance_trends(&self, events: &[&AnalyticsEvent]) -> PerformanceTrends {
796        if events.len() < 2 {
797            return PerformanceTrends {
798                direction: TrendDirection::Stable,
799                change_percentage: 0.0,
800                time_period: "insufficient_data".to_string(),
801            };
802        }
803
804        let mut sorted_events = events.to_vec();
805        sorted_events.sort_by_key(|e| e.timestamp);
806
807        let first_half = &sorted_events[..sorted_events.len() / 2];
808        let second_half = &sorted_events[sorted_events.len() / 2..];
809
810        let first_avg = first_half.iter().filter_map(|e| e.duration_ms).sum::<u64>() as f64
811            / first_half.len() as f64;
812        let second_avg = second_half
813            .iter()
814            .filter_map(|e| e.duration_ms)
815            .sum::<u64>() as f64
816            / second_half.len() as f64;
817
818        let change_percentage = if first_avg > 0.0 {
819            ((second_avg - first_avg) / first_avg) * 100.0
820        } else {
821            0.0
822        };
823
824        let direction = if change_percentage > 5.0 {
825            TrendDirection::Declining
826        } else if change_percentage < -5.0 {
827            TrendDirection::Improving
828        } else {
829            TrendDirection::Stable
830        };
831
832        PerformanceTrends {
833            direction,
834            change_percentage,
835            time_period: "recent".to_string(),
836        }
837    }
838
839    /// Identify optimization opportunities
840    fn identify_optimization_opportunities(&self, events: &[&AnalyticsEvent]) -> Vec<String> {
841        let mut opportunities = Vec::new();
842
843        // Check for slow operations
844        let slow_operations = self.identify_slow_operations(events);
845        for op in slow_operations {
846            if op.avg_duration_ms > 1000.0 {
847                opportunities.push(format!(
848                    "Optimize {} - currently taking {:.0}ms on average",
849                    op.operation_type, op.avg_duration_ms
850                ));
851            }
852        }
853
854        // Check for high error rates
855        let total_events = events.len();
856        let error_events = events
857            .iter()
858            .filter(|e| e.properties.get("success").and_then(|v| v.as_bool()) == Some(false))
859            .count();
860
861        if total_events > 0 {
862            let error_rate = error_events as f64 / total_events as f64;
863            if error_rate > 0.1 {
864                opportunities.push(format!(
865                    "High error rate detected: {:.1}% - investigate error causes",
866                    error_rate * 100.0
867                ));
868            }
869        }
870
871        opportunities
872    }
873
874    /// Identify popular features
875    fn identify_popular_features(&self, events: &[AnalyticsEvent]) -> Vec<FeatureUsage> {
876        let mut feature_counts: HashMap<String, u32> = HashMap::new();
877        let mut feature_last_used: HashMap<String, u64> = HashMap::new();
878
879        for event in events {
880            let feature_name = match &event.event_type {
881                AnalyticsEventType::MetadataGenerated => "metadata_generation",
882                AnalyticsEventType::OgImageGenerated => "og_image_generation",
883                AnalyticsEventType::ThemeApplied => "theme_application",
884                AnalyticsEventType::MetadataValidated => "metadata_validation",
885                AnalyticsEventType::PerformanceMeasured => "performance_tracking",
886                AnalyticsEventType::ErrorOccurred => "error_handling",
887                AnalyticsEventType::UserInteraction => "user_interaction",
888                AnalyticsEventType::Custom(name) => name,
889            };
890
891            *feature_counts.entry(feature_name.to_string()).or_insert(0) += 1;
892            feature_last_used.insert(feature_name.to_string(), event.timestamp);
893        }
894
895        let total_events = events.len() as f64;
896        let mut features: Vec<FeatureUsage> = feature_counts
897            .into_iter()
898            .map(|(name, count)| FeatureUsage {
899                usage_percentage: (count as f64 / total_events) * 100.0,
900                last_used: feature_last_used.get(&name).copied().unwrap_or(0),
901                feature_name: name,
902                usage_count: count,
903            })
904            .collect();
905
906        features.sort_by(|a, b| b.usage_count.cmp(&a.usage_count));
907        features.truncate(10); // Top 10 features
908        features
909    }
910
911    /// Analyze time patterns
912    fn analyze_time_patterns(&self, events: &[AnalyticsEvent]) -> TimePatterns {
913        let mut hourly_counts = [0u32; 24];
914        let mut day_counts: HashMap<String, u32> = HashMap::new();
915        let mut monthly_counts: HashMap<String, u32> = HashMap::new();
916
917        for event in events {
918            // Extract hour from timestamp (simplified)
919            let hour = (event.timestamp / 3600) % 24;
920            hourly_counts[hour as usize] += 1;
921
922            // Extract day of week (simplified)
923            let day_of_week = (event.timestamp / 86400) % 7;
924            let day_name = match day_of_week {
925                0 => "Sunday",
926                1 => "Monday",
927                2 => "Tuesday",
928                3 => "Wednesday",
929                4 => "Thursday",
930                5 => "Friday",
931                6 => "Saturday",
932                _ => "Unknown",
933            };
934            *day_counts.entry(day_name.to_string()).or_insert(0) += 1;
935
936            // Extract month (simplified)
937            let month = (event.timestamp / 2629746) % 12; // Approximate seconds in a month
938            let month_name = format!("Month_{}", month + 1);
939            *monthly_counts.entry(month_name).or_insert(0) += 1;
940        }
941
942        // Find peak hours
943        let mut peak_hours = Vec::new();
944        let max_hourly_count = hourly_counts.iter().max().copied().unwrap_or(0);
945        for (hour, &count) in hourly_counts.iter().enumerate() {
946            if count >= max_hourly_count * 3 / 4 {
947                peak_hours.push(hour as u8);
948            }
949        }
950
951        TimePatterns {
952            peak_hours,
953            day_of_week: day_counts,
954            monthly: monthly_counts,
955        }
956    }
957
958    /// Calculate engagement metrics
959    fn calculate_engagement_metrics(&self, events: &[AnalyticsEvent]) -> EngagementMetrics {
960        let session_duration = if let Some(session) = &self.current_session {
961            if let Some(end_time) = session.end_time {
962                end_time - session.start_time
963            } else {
964                SystemTime::now()
965                    .duration_since(UNIX_EPOCH)
966                    .unwrap_or_default()
967                    .as_secs()
968                    - session.start_time
969            }
970        } else {
971            0
972        };
973
974        let unique_features = events
975            .iter()
976            .map(|e| format!("{:?}", e.event_type))
977            .collect::<std::collections::HashSet<_>>()
978            .len();
979
980        EngagementMetrics {
981            avg_session_duration_ms: session_duration as f64 * 1000.0,
982            bounce_rate: if events.len() < 2 { 1.0 } else { 0.0 },
983            return_user_rate: 0.0, // Would need session history to calculate
984            feature_depth: unique_features as f64,
985        }
986    }
987
988    /// Calculate feature adoption
989    fn calculate_feature_adoption(&self, events: &[AnalyticsEvent]) -> FeatureAdoption {
990        let new_features = events
991            .iter()
992            .filter_map(|e| match &e.event_type {
993                AnalyticsEventType::Custom(name) => Some(name.clone()),
994                _ => None,
995            })
996            .collect::<std::collections::HashSet<_>>()
997            .into_iter()
998            .collect();
999
1000        FeatureAdoption {
1001            new_features,
1002            adoption_rate: 0.8,         // Placeholder
1003            time_to_adoption_days: 7.0, // Placeholder
1004        }
1005    }
1006
1007    /// Identify common errors
1008    fn identify_common_errors(&self, events: &[&AnalyticsEvent]) -> Vec<CommonError> {
1009        let mut error_counts: HashMap<String, u32> = HashMap::new();
1010        let mut error_last_occurrence: HashMap<String, u64> = HashMap::new();
1011        let mut error_contexts: HashMap<String, HashMap<String, serde_json::Value>> =
1012            HashMap::new();
1013
1014        for event in events {
1015            if let Some(error) = &event.error {
1016                let error_key = format!("{}:{}", error.kind, error.message);
1017                *error_counts.entry(error_key.clone()).or_insert(0) += 1;
1018                error_last_occurrence.insert(error_key.clone(), event.timestamp);
1019                error_contexts.insert(error_key.clone(), error.context.clone());
1020            }
1021        }
1022
1023        let total_errors = events.len() as f64;
1024        let mut common_errors: Vec<CommonError> = error_counts
1025            .into_iter()
1026            .map(|(error_key, count)| {
1027                let parts: Vec<&str> = error_key.splitn(2, ':').collect();
1028                let error_type = parts.get(0).unwrap_or(&"Unknown").to_string();
1029                let _error_message = parts.get(1).unwrap_or(&"Unknown").to_string();
1030
1031                CommonError {
1032                    error_type,
1033                    count,
1034                    rate: (count as f64 / total_errors) * 100.0,
1035                    last_occurrence: error_last_occurrence.get(&error_key).copied().unwrap_or(0),
1036                    common_context: error_contexts.get(&error_key).cloned().unwrap_or_default(),
1037                }
1038            })
1039            .collect();
1040
1041        common_errors.sort_by(|a, b| b.count.cmp(&a.count));
1042        common_errors.truncate(5); // Top 5 common errors
1043        common_errors
1044    }
1045
1046    /// Calculate error trends
1047    fn calculate_error_trends(&self, events: &[&AnalyticsEvent]) -> ErrorTrends {
1048        if events.len() < 2 {
1049            return ErrorTrends {
1050                overall_trend: TrendDirection::Stable,
1051                rate_change: 0.0,
1052                new_error_types: vec![],
1053            };
1054        }
1055
1056        let mut sorted_events = events.to_vec();
1057        sorted_events.sort_by_key(|e| e.timestamp);
1058
1059        let first_half = &sorted_events[..sorted_events.len() / 2];
1060        let second_half = &sorted_events[sorted_events.len() / 2..];
1061
1062        let first_rate = first_half.len() as f64;
1063        let second_rate = second_half.len() as f64;
1064
1065        let rate_change = if first_rate > 0.0 {
1066            ((second_rate - first_rate) / first_rate) * 100.0
1067        } else {
1068            0.0
1069        };
1070
1071        let overall_trend = if rate_change > 10.0 {
1072            TrendDirection::Declining
1073        } else if rate_change < -10.0 {
1074            TrendDirection::Improving
1075        } else {
1076            TrendDirection::Stable
1077        };
1078
1079        // Identify new error types (simplified)
1080        let mut new_error_types = Vec::new();
1081        let first_half_types: std::collections::HashSet<String> = first_half
1082            .iter()
1083            .filter_map(|e| e.error.as_ref().map(|err| err.kind.clone()))
1084            .collect();
1085
1086        for event in second_half {
1087            if let Some(error) = &event.error {
1088                if !first_half_types.contains(&error.kind) {
1089                    new_error_types.push(error.kind.clone());
1090                }
1091            }
1092        }
1093
1094        ErrorTrends {
1095            overall_trend,
1096            rate_change,
1097            new_error_types,
1098        }
1099    }
1100
1101    /// Calculate error resolution metrics
1102    fn calculate_error_resolution(&self, events: &[&AnalyticsEvent]) -> ErrorResolution {
1103        let total_errors = events.len() as u32;
1104        let auto_resolved = events
1105            .iter()
1106            .filter(|e| e.properties.get("auto_resolved").and_then(|v| v.as_bool()) == Some(true))
1107            .count() as u32;
1108
1109        ErrorResolution {
1110            auto_resolved,
1111            manual_resolution_rate: if total_errors > 0 {
1112                (total_errors - auto_resolved) as f64 / total_errors as f64
1113            } else {
1114                0.0
1115            },
1116            avg_resolution_time_ms: 1000.0, // Placeholder
1117        }
1118    }
1119
1120    /// Generate recommendations
1121    fn generate_recommendations(
1122        &self,
1123        performance: &PerformanceInsights,
1124        usage: &UsageInsights,
1125        errors: &ErrorInsights,
1126    ) -> Vec<Recommendation> {
1127        let mut recommendations = Vec::new();
1128
1129        // Performance recommendations
1130        if performance.avg_generation_time_ms > 500.0 {
1131            recommendations.push(Recommendation {
1132                recommendation_type: RecommendationType::Performance,
1133                priority: Priority::High,
1134                title: "Optimize Generation Performance".to_string(),
1135                description: "Metadata generation is taking longer than expected".to_string(),
1136                action_items: vec![
1137                    "Implement caching for frequently generated metadata".to_string(),
1138                    "Optimize image processing algorithms".to_string(),
1139                    "Consider using Web Workers for heavy operations".to_string(),
1140                ],
1141                expected_impact: "Reduce generation time by 30-50%".to_string(),
1142                implementation_effort: EffortLevel::Medium,
1143            });
1144        }
1145
1146        // Error reduction recommendations
1147        if errors.common_errors.iter().any(|e| e.rate > 5.0) {
1148            recommendations.push(Recommendation {
1149                recommendation_type: RecommendationType::ErrorReduction,
1150                priority: Priority::High,
1151                title: "Address Common Errors".to_string(),
1152                description: "High error rates detected in metadata operations".to_string(),
1153                action_items: vec![
1154                    "Add better input validation".to_string(),
1155                    "Improve error handling and recovery".to_string(),
1156                    "Add retry mechanisms for transient failures".to_string(),
1157                ],
1158                expected_impact: "Reduce error rate by 50-80%".to_string(),
1159                implementation_effort: EffortLevel::Medium,
1160            });
1161        }
1162
1163        // Feature usage recommendations
1164        if usage.adoption.adoption_rate < 0.5 {
1165            recommendations.push(Recommendation {
1166                recommendation_type: RecommendationType::FeatureUsage,
1167                priority: Priority::Medium,
1168                title: "Improve Feature Adoption".to_string(),
1169                description: "Low feature adoption rates detected".to_string(),
1170                action_items: vec![
1171                    "Add feature discovery mechanisms".to_string(),
1172                    "Improve documentation and examples".to_string(),
1173                    "Add progressive disclosure for advanced features".to_string(),
1174                ],
1175                expected_impact: "Increase feature adoption by 25-40%".to_string(),
1176                implementation_effort: EffortLevel::Low,
1177            });
1178        }
1179
1180        recommendations
1181    }
1182
1183    /// Get current performance metrics
1184    pub fn get_performance_metrics(&self) -> &PerformanceMetrics {
1185        &self.performance_metrics
1186    }
1187
1188    /// Get analytics configuration
1189    pub fn get_config(&self) -> &AnalyticsConfig {
1190        &self.config
1191    }
1192
1193    /// Update analytics configuration
1194    pub fn update_config(&mut self, config: AnalyticsConfig) {
1195        self.config = config;
1196    }
1197}
1198
1199impl Default for AnalyticsManager {
1200    fn default() -> Self {
1201        Self::new(AnalyticsConfig::default())
1202    }
1203}