//! Server Log Analytics
//!
//! Collects and analyzes server-side logs including:
//! - Rust panics and errors
//! - Request/response performance
//! - Resource usage monitoring
//! - Application-specific metrics

use super::{AnalyticsEvent, EventLevel, LogSource, generate_event_id};
use anyhow::Result;
use chrono::Utc;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;
use tokio::sync::mpsc;

pub mod panic_detector;
pub mod performance_monitor;

pub use panic_detector::PanicDetector;
pub use performance_monitor::PerformanceMonitor;

/// Server log entry structure
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerLogEntry {
    pub timestamp: String,
    pub level: String,
    pub target: String,
    pub message: String,
    pub fields: HashMap<String, serde_json::Value>,
}

/// Server metrics collection
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerMetrics {
    /// Total requests processed
    pub total_requests: u64,
    /// Error count
    pub error_count: u64,
    /// Panic count
    pub panic_count: u64,
    /// Average response time
    pub avg_response_time_ms: f64,
    /// Memory usage in MB
    pub memory_usage_mb: Option<f64>,
    /// CPU usage percentage
    pub cpu_usage_percent: Option<f64>,
    /// Active connections
    pub active_connections: Option<u64>,
    /// Uptime in seconds
    pub uptime_seconds: u64,
}

impl Default for ServerMetrics {
    fn default() -> Self {
        Self {
            total_requests: 0,
            error_count: 0,
            panic_count: 0,
            avg_response_time_ms: 0.0,
            memory_usage_mb: None,
            cpu_usage_percent: None,
            active_connections: None,
            uptime_seconds: 0,
        }
    }
}

/// Server log collector and analyzer
pub struct ServerCollector {
    sender: mpsc::UnboundedSender<AnalyticsEvent>,
    log_paths: Vec<PathBuf>,
    panic_detector: PanicDetector,
    performance_monitor: PerformanceMonitor,
    metrics: ServerMetrics,
}

impl ServerCollector {
    /// Create new server collector with default configuration
    pub fn new(sender: mpsc::UnboundedSender<AnalyticsEvent>) -> Self {
        let log_paths = vec![
            PathBuf::from("logs/server.log"),
            PathBuf::from("logs/application.log"),
            PathBuf::from("logs/leptos.log"),
        ];

        let panic_detector = PanicDetector::new();
        let performance_monitor = PerformanceMonitor::new();

        Self {
            sender,
            log_paths,
            panic_detector,
            performance_monitor,
            metrics: ServerMetrics::default(),
        }
    }

    /// Create with custom log paths
    pub fn with_log_paths(sender: mpsc::UnboundedSender<AnalyticsEvent>, log_paths: Vec<PathBuf>) -> Self {
        let panic_detector = PanicDetector::new();
        let performance_monitor = PerformanceMonitor::new();

        Self {
            sender,
            log_paths,
            panic_detector,
            performance_monitor,
            metrics: ServerMetrics::default(),
        }
    }

    /// Start server log collection
    pub async fn start_collection(&mut self) -> Result<()> {
        tracing::info!("Starting server log collection...");

        // Start panic detection
        let sender_clone = self.sender.clone();
        self.panic_detector.start_monitoring(sender_clone).await?;

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

        // Start log file watching
        self.start_log_watching().await?;

        tracing::info!("Server log collection started");
        Ok(())
    }

    /// Watch server log files
    async fn start_log_watching(&self) -> Result<()> {
        for log_path in &self.log_paths {
            if !log_path.exists() {
                tracing::warn!("Server log file does not exist: {:?}", log_path);
                continue;
            }

            let log_path = log_path.clone();
            let sender = self.sender.clone();

            tokio::spawn(async move {
                Self::watch_log_file(log_path, sender).await;
            });
        }

        Ok(())
    }

    /// Watch a single log file for new entries
    async fn watch_log_file(log_path: PathBuf, sender: mpsc::UnboundedSender<AnalyticsEvent>) {
        let mut last_size = 0;

        loop {
            match tokio::fs::metadata(&log_path).await {
                Ok(metadata) => {
                    let current_size = metadata.len();
                    if current_size > last_size {
                        // File has grown, read new content
                        if let Ok(content) = tokio::fs::read_to_string(&log_path).await {
                            let new_content = if last_size > 0 {
                                content.chars().skip(last_size as usize).collect()
                            } else {
                                content
                            };

                            // Process new log entries
                            for line in new_content.lines() {
                                if let Ok(event) = Self::parse_log_line(line) {
                                    if let Err(e) = sender.send(event) {
                                        tracing::error!("Failed to send server log event: {}", e);
                                        return;
                                    }
                                }
                            }
                        }
                        last_size = current_size;
                    }
                }
                Err(_) => {
                    // Log file might not exist yet
                    last_size = 0;
                }
            }

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

    /// Parse log line and convert to analytics event
    fn parse_log_line(line: &str) -> Result<AnalyticsEvent> {
        // Try to parse as structured log first (JSON)
        if let Ok(entry) = serde_json::from_str::<ServerLogEntry>(line) {
            return Self::convert_structured_log(entry);
        }

        // Fall back to parsing unstructured logs
        Self::parse_unstructured_log(line)
    }

    /// Convert structured log entry to analytics event
    fn convert_structured_log(entry: ServerLogEntry) -> Result<AnalyticsEvent> {
        let level = match entry.level.to_lowercase().as_str() {
            "trace" => EventLevel::Trace,
            "debug" => EventLevel::Debug,
            "info" => EventLevel::Info,
            "warn" => EventLevel::Warn,
            "error" => EventLevel::Error,
            _ => EventLevel::Info,
        };

        let event_type = if entry.message.contains("panic") {
            "panic".to_string()
        } else if entry.message.contains("request") {
            "request".to_string()
        } else if entry.message.contains("error") {
            "error".to_string()
        } else {
            "log".to_string()
        };

        let mut metadata = HashMap::new();
        metadata.insert("target".to_string(), serde_json::Value::String(entry.target));
        for (key, value) in entry.fields {
            metadata.insert(key, value);
        }

        Ok(AnalyticsEvent {
            id: generate_event_id(),
            timestamp: Utc::now(),
            source: LogSource::Server,
            event_type,
            session_id: None,
            path: metadata.get("path").and_then(|v| v.as_str()).map(|s| s.to_string()),
            level,
            message: entry.message,
            metadata,
            duration_ms: metadata.get("duration_ms").and_then(|v| v.as_u64()),
            errors: Vec::new(),
        })
    }

    /// Parse unstructured log line
    fn parse_unstructured_log(line: &str) -> Result<AnalyticsEvent> {
        let level = if line.contains("ERROR") || line.contains("error") {
            EventLevel::Error
        } else if line.contains("WARN") || line.contains("warn") {
            EventLevel::Warn
        } else if line.contains("INFO") || line.contains("info") {
            EventLevel::Info
        } else if line.contains("DEBUG") || line.contains("debug") {
            EventLevel::Debug
        } else {
            EventLevel::Info
        };

        let event_type = if line.contains("panic") {
            "panic"
        } else if line.contains("error") {
            "error"
        } else {
            "log"
        }.to_string();

        Ok(AnalyticsEvent {
            id: generate_event_id(),
            timestamp: Utc::now(),
            source: LogSource::Server,
            event_type,
            session_id: None,
            path: None,
            level,
            message: line.to_string(),
            metadata: HashMap::new(),
            duration_ms: None,
            errors: Vec::new(),
        })
    }

    /// Get current server metrics
    pub fn get_metrics(&self) -> &ServerMetrics {
        &self.metrics
    }

    /// Update server metrics
    pub async fn update_metrics(&mut self) -> Result<()> {
        // Collect current system metrics
        if let Ok(system_metrics) = self.performance_monitor.get_system_metrics().await {
            self.metrics.memory_usage_mb = system_metrics.memory_usage_mb;
            self.metrics.cpu_usage_percent = system_metrics.cpu_usage_percent;
            self.metrics.active_connections = system_metrics.active_connections;
        }

        // Send metrics update event
        let event = self.create_metrics_event();
        self.sender.send(event)?;

        Ok(())
    }

    /// Create metrics analytics event
    fn create_metrics_event(&self) -> AnalyticsEvent {
        let mut metadata = HashMap::new();
        metadata.insert("total_requests".to_string(),
            serde_json::Value::Number(self.metrics.total_requests.into()));
        metadata.insert("error_count".to_string(),
            serde_json::Value::Number(self.metrics.error_count.into()));
        metadata.insert("panic_count".to_string(),
            serde_json::Value::Number(self.metrics.panic_count.into()));

        if let Some(memory) = self.metrics.memory_usage_mb {
            metadata.insert("memory_usage_mb".to_string(),
                serde_json::Value::Number(serde_json::Number::from_f64(memory).unwrap()));
        }

        if let Some(cpu) = self.metrics.cpu_usage_percent {
            metadata.insert("cpu_usage_percent".to_string(),
                serde_json::Value::Number(serde_json::Number::from_f64(cpu).unwrap()));
        }

        let level = if self.metrics.error_count > 10 || self.metrics.panic_count > 0 {
            EventLevel::Warn
        } else {
            EventLevel::Info
        };

        let message = format!(
            "Server metrics: {} requests, {} errors, {:.1}MB memory",
            self.metrics.total_requests,
            self.metrics.error_count,
            self.metrics.memory_usage_mb.unwrap_or(0.0)
        );

        AnalyticsEvent {
            id: generate_event_id(),
            timestamp: Utc::now(),
            source: LogSource::Server,
            event_type: "server_metrics".to_string(),
            session_id: None,
            path: None,
            level,
            message,
            metadata,
            duration_ms: None,
            errors: Vec::new(),
        }
    }
}
