//! Navigation Analytics Integration
//!
//! Integrates with the existing navigation tracking system to provide
//! unified analytics and monitoring capabilities.

use super::{AnalyticsEvent, EventLevel, LogSource, generate_event_id};
use anyhow::{Context, Result};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use tokio::sync::mpsc;
use tokio_stream::{wrappers::LinesStream, StreamExt};

pub mod cache_monitor;
pub mod route_analytics;
pub mod tracker_integration;

pub use cache_monitor::CacheMonitor;
pub use route_analytics::RouteAnalyzer;
pub use tracker_integration::TrackerIntegration;

/// Navigation event from the existing JSONL logs
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NavigationLogEvent {
    pub session_id: String,
    pub timestamp: u64,
    pub event_type: String,
    pub source_path: String,
    pub target_path: Option<String>,
    pub current_lang: String,
    pub target_lang: Option<String>,
    pub resolution_time_ms: u64,
    pub cache_hit: bool,
    pub component: Option<String>,
    pub errors: Vec<String>,
    pub fallback_used: bool,
    pub additional_data: HashMap<String, String>,
}

/// Navigation collector that reads from existing navigation logs
pub struct NavigationCollector {
    sender: mpsc::UnboundedSender<AnalyticsEvent>,
    log_path: PathBuf,
    cache_monitor: CacheMonitor,
    route_analyzer: RouteAnalyzer,
}

impl NavigationCollector {
    /// Create new navigation collector
    pub async fn new(sender: mpsc::UnboundedSender<AnalyticsEvent>) -> Result<Self> {
        let log_path = PathBuf::from("logs/navigation.jsonl");

        // Verify log file exists or can be created
        if !log_path.exists() {
            if let Some(parent) = log_path.parent() {
                tokio::fs::create_dir_all(parent).await
                    .context("Failed to create navigation logs directory")?;
            }
        }

        let cache_monitor = CacheMonitor::new();
        let route_analyzer = RouteAnalyzer::new();

        Ok(Self {
            sender,
            log_path,
            cache_monitor,
            route_analyzer,
        })
    }

    /// Start monitoring navigation logs
    pub async fn start_monitoring(&mut self) -> Result<()> {
        tracing::info!("Starting navigation log monitoring...");

        // Start watching the navigation log file
        self.watch_navigation_log().await?;

        // Start cache monitoring
        let sender_clone = self.sender.clone();
        self.cache_monitor.start_monitoring(sender_clone).await?;

        // Start route analysis
        let sender_clone = self.sender.clone();
        self.route_analyzer.start_analysis(sender_clone).await?;

        tracing::info!("Navigation monitoring started");
        Ok(())
    }

    /// Watch navigation JSONL log file for new entries
    async fn watch_navigation_log(&self) -> Result<()> {
        let log_path = self.log_path.clone();
        let sender = self.sender.clone();

        tokio::spawn(async move {
            let mut processed_lines = 0usize;

            loop {
                match Self::process_navigation_log(&log_path, processed_lines, &sender).await {
                    Ok(new_lines) => {
                        processed_lines += new_lines;
                        if new_lines > 0 {
                            tracing::debug!("Processed {} new navigation log entries", new_lines);
                        }
                    }
                    Err(e) => {
                        tracing::error!("Failed to process navigation log: {}", e);
                    }
                }

                // Check for new entries every 5 seconds
                tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
            }
        });

        Ok(())
    }

    /// Process navigation log file and convert to analytics events
    async fn process_navigation_log(
        log_path: &Path,
        skip_lines: usize,
        sender: &mpsc::UnboundedSender<AnalyticsEvent>,
    ) -> Result<usize> {
        if !log_path.exists() {
            return Ok(0);
        }

        let file = tokio::fs::File::open(log_path).await?;
        let reader = tokio::io::BufReader::new(file);
        let mut lines = LinesStream::new(reader.lines());

        let mut processed = 0;
        let mut line_count = 0;

        while let Some(line) = lines.next().await {
            let line = line?;

            // Skip already processed lines
            if line_count < skip_lines {
                line_count += 1;
                continue;
            }

            if line.trim().is_empty() {
                line_count += 1;
                continue;
            }

            // Parse navigation event
            match serde_json::from_str::<NavigationLogEvent>(&line) {
                Ok(nav_event) => {
                    // Convert to analytics event
                    let analytics_event = Self::convert_navigation_event(nav_event)?;

                    // Send to analytics collector
                    if let Err(e) = sender.send(analytics_event) {
                        tracing::error!("Failed to send analytics event: {}", e);
                    }

                    processed += 1;
                }
                Err(e) => {
                    tracing::warn!("Failed to parse navigation log line: {} - Error: {}", line, e);
                }
            }

            line_count += 1;
        }

        Ok(processed)
    }

    /// Convert navigation log event to analytics event
    fn convert_navigation_event(nav_event: NavigationLogEvent) -> Result<AnalyticsEvent> {
        let timestamp = DateTime::from_timestamp_millis(nav_event.timestamp as i64)
            .unwrap_or_else(|| Utc::now());

        let level = if !nav_event.errors.is_empty() {
            EventLevel::Error
        } else if nav_event.fallback_used {
            EventLevel::Warn
        } else {
            EventLevel::Info
        };

        let mut metadata = HashMap::new();
        metadata.insert("cache_hit".to_string(),
            serde_json::Value::Bool(nav_event.cache_hit));
        metadata.insert("fallback_used".to_string(),
            serde_json::Value::Bool(nav_event.fallback_used));

        if let Some(component) = &nav_event.component {
            metadata.insert("component".to_string(),
                serde_json::Value::String(component.clone()));
        }

        if let Some(target_lang) = &nav_event.target_lang {
            metadata.insert("target_language".to_string(),
                serde_json::Value::String(target_lang.clone()));
        }

        // Add additional data
        for (key, value) in nav_event.additional_data {
            metadata.insert(key, serde_json::Value::String(value));
        }

        let message = if let Some(target) = &nav_event.target_path {
            format!("{} navigation: {} -> {} ({}ms)",
                nav_event.event_type, nav_event.source_path, target, nav_event.resolution_time_ms)
        } else {
            format!("{} navigation: {} ({}ms)",
                nav_event.event_type, nav_event.source_path, nav_event.resolution_time_ms)
        };

        Ok(AnalyticsEvent {
            id: generate_event_id(),
            timestamp,
            source: LogSource::Navigation,
            event_type: nav_event.event_type,
            session_id: Some(nav_event.session_id),
            path: Some(nav_event.source_path),
            level,
            message,
            metadata,
            duration_ms: Some(nav_event.resolution_time_ms),
            errors: nav_event.errors,
        })
    }

    /// Get navigation statistics
    pub async fn get_navigation_stats(&self) -> Result<NavigationStats> {
        // Analyze recent navigation patterns
        let mut stats = NavigationStats::default();

        // Read recent entries from navigation log
        if self.log_path.exists() {
            let content = tokio::fs::read_to_string(&self.log_path).await?;
            let lines: Vec<&str> = content.lines().collect();

            // Analyze last 1000 entries for stats
            let recent_lines = if lines.len() > 1000 {
                &lines[lines.len() - 1000..]
            } else {
                &lines[..]
            };

            for line in recent_lines {
                if let Ok(nav_event) = serde_json::from_str::<NavigationLogEvent>(line) {
                    stats.total_events += 1;

                    match nav_event.event_type.as_str() {
                        "RouteResolution" => stats.route_resolutions += 1,
                        "LanguageSwitch" => stats.language_switches += 1,
                        "CacheEvent" => {
                            stats.cache_events += 1;
                            if nav_event.cache_hit {
                                stats.cache_hits += 1;
                            }
                        }
                        _ => {}
                    }

                    if !nav_event.errors.is_empty() {
                        stats.error_events += 1;
                    }

                    if nav_event.resolution_time_ms > 10 {
                        stats.slow_events += 1;
                    }

                    stats.total_resolution_time += nav_event.resolution_time_ms;
                }
            }

            // Calculate averages
            if stats.total_events > 0 {
                stats.avg_resolution_time = stats.total_resolution_time as f64 / stats.total_events as f64;
            }

            if stats.cache_events > 0 {
                stats.cache_hit_rate = stats.cache_hits as f64 / stats.cache_events as f64;
            }
        }

        Ok(stats)
    }
}

/// Navigation statistics summary
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct NavigationStats {
    pub total_events: u64,
    pub route_resolutions: u64,
    pub language_switches: u64,
    pub cache_events: u64,
    pub cache_hits: u64,
    pub cache_hit_rate: f64,
    pub error_events: u64,
    pub slow_events: u64,
    pub avg_resolution_time: f64,
    pub total_resolution_time: u64,
}

impl NavigationStats {
    /// Get performance summary
    pub fn performance_summary(&self) -> String {
        format!(
            "Navigation Performance: {:.1}ms avg, {:.1}% cache hit rate, {} slow routes, {} errors",
            self.avg_resolution_time,
            self.cache_hit_rate * 100.0,
            self.slow_events,
            self.error_events
        )
    }

    /// Check if performance is degraded
    pub fn is_performance_degraded(&self) -> bool {
        self.avg_resolution_time > 50.0 ||
        self.cache_hit_rate < 0.5 ||
        (self.error_events as f64 / self.total_events as f64) > 0.05
    }
}
