//! Browser Console Log Collector
//!
//! Collects and analyzes browser console messages including:
//! - Console.log, warn, error messages
//! - Unhandled promise rejections
//! - WASM binding errors
//! - Leptos reactive signal issues

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

/// Console message pattern for categorization
#[derive(Debug, Clone)]
pub struct ConsolePattern {
    pub pattern: String,
    pub category: ConsoleCategory,
    pub severity: EventLevel,
}

/// Console message categories
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ConsoleCategory {
    ReactiveGraph,
    Hydration,
    WasmBinding,
    UserCode,
    PerformanceWarning,
    SecurityWarning,
    NetworkError,
    UnhandledPromise,
}

/// Console statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConsoleStats {
    pub total_messages: u64,
    pub errors: u64,
    pub warnings: u64,
    pub info_messages: u64,
    pub debug_messages: u64,
    pub category_counts: HashMap<String, u64>,
    pub top_error_messages: Vec<(String, u64)>,
}

impl Default for ConsoleStats {
    fn default() -> Self {
        Self {
            total_messages: 0,
            errors: 0,
            warnings: 0,
            info_messages: 0,
            debug_messages: 0,
            category_counts: HashMap::new(),
            top_error_messages: Vec::new(),
        }
    }
}

/// Console log collector
pub struct ConsoleCollector {
    patterns: Vec<ConsolePattern>,
    stats: Arc<Mutex<ConsoleStats>>,
    monitoring_interval: u64,
}

impl ConsoleCollector {
    /// Create new console collector
    pub fn new() -> Self {
        let patterns = Self::create_default_patterns();

        Self {
            patterns,
            stats: Arc::new(Mutex::new(ConsoleStats::default())),
            monitoring_interval: 10, // 10 seconds
        }
    }

    /// Create default console message patterns
    fn create_default_patterns() -> Vec<ConsolePattern> {
        vec![
            // Leptos reactive graph issues
            ConsolePattern {
                pattern: "reactive_graph".to_string(),
                category: ConsoleCategory::ReactiveGraph,
                severity: EventLevel::Error,
            },
            ConsolePattern {
                pattern: "signal".to_string(),
                category: ConsoleCategory::ReactiveGraph,
                severity: EventLevel::Warn,
            },
            ConsolePattern {
                pattern: "memo".to_string(),
                category: ConsoleCategory::ReactiveGraph,
                severity: EventLevel::Warn,
            },

            // Hydration issues
            ConsolePattern {
                pattern: "hydration".to_string(),
                category: ConsoleCategory::Hydration,
                severity: EventLevel::Error,
            },
            ConsolePattern {
                pattern: "mismatch".to_string(),
                category: ConsoleCategory::Hydration,
                severity: EventLevel::Error,
            },

            // WASM binding errors
            ConsolePattern {
                pattern: "wasm".to_string(),
                category: ConsoleCategory::WasmBinding,
                severity: EventLevel::Error,
            },
            ConsolePattern {
                pattern: "bindgen".to_string(),
                category: ConsoleCategory::WasmBinding,
                severity: EventLevel::Error,
            },

            // Network errors
            ConsolePattern {
                pattern: "fetch".to_string(),
                category: ConsoleCategory::NetworkError,
                severity: EventLevel::Warn,
            },
            ConsolePattern {
                pattern: "XMLHttpRequest".to_string(),
                category: ConsoleCategory::NetworkError,
                severity: EventLevel::Warn,
            },

            // Unhandled promises
            ConsolePattern {
                pattern: "Unhandled promise rejection".to_string(),
                category: ConsoleCategory::UnhandledPromise,
                severity: EventLevel::Error,
            },

            // Performance warnings
            ConsolePattern {
                pattern: "performance".to_string(),
                category: ConsoleCategory::PerformanceWarning,
                severity: EventLevel::Warn,
            },

            // Security warnings
            ConsolePattern {
                pattern: "security".to_string(),
                category: ConsoleCategory::SecurityWarning,
                severity: EventLevel::Warn,
            },
        ]
    }

    /// Start console message monitoring
    pub async fn start_monitoring(&self, sender: mpsc::UnboundedSender<AnalyticsEvent>) -> Result<()> {
        tracing::info!("Starting browser console monitoring...");

        let patterns = self.patterns.clone();
        let stats = Arc::clone(&self.stats);
        let interval = self.monitoring_interval;

        tokio::spawn(async move {
            let mut interval_timer = tokio::time::interval(
                tokio::time::Duration::from_secs(interval)
            );

            loop {
                interval_timer.tick().await;

                // Simulate console message collection
                // In a real implementation, this would interface with:
                // - MCP browser-tools
                // - Browser WebSocket connection
                // - Log file monitoring
                // - Browser extension API

                if let Ok(messages) = Self::collect_console_messages().await {
                    for message in messages {
                        // Categorize message
                        let category = Self::categorize_message(&message, &patterns);

                        // Update statistics
                        Self::update_stats(&stats, &message, &category);

                        // Create analytics event
                        let event = Self::create_console_event(message, category);

                        if let Err(e) = sender.send(event) {
                            tracing::error!("Failed to send console event: {}", e);
                            break;
                        }
                    }
                }
            }
        });

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

    /// Collect console messages (simulated)
    async fn collect_console_messages() -> Result<Vec<ConsoleMessage>> {
        let mut messages = Vec::new();

        // Simulate different types of console messages
        if rand::random::<f64>() < 0.3 { // 30% chance of messages
            let message_types = vec![
                ("reactive_graph error: signal accessed outside of reactive context", BrowserLogLevel::Error),
                ("hydration mismatch detected on element", BrowserLogLevel::Error),
                ("WASM binding error: function not found", BrowserLogLevel::Error),
                ("Performance warning: large DOM update", BrowserLogLevel::Warn),
                ("Unhandled promise rejection: network timeout", BrowserLogLevel::Error),
                ("Info: page loaded successfully", BrowserLogLevel::Info),
                ("Debug: component rendered", BrowserLogLevel::Debug),
            ];

            let (message_text, level) = message_types[rand::random::<usize>() % message_types.len()];

            messages.push(ConsoleMessage {
                message: message_text.to_string(),
                level,
                timestamp: Utc::now(),
                source: "browser".to_string(),
                line: Some(rand::random::<u32>() % 1000 + 1),
                column: Some(rand::random::<u32>() % 50 + 1),
                url: "/current/page".to_string(),
                stack_trace: None,
            });
        }

        Ok(messages)
    }

    /// Categorize console message based on patterns
    fn categorize_message(message: &ConsoleMessage, patterns: &[ConsolePattern]) -> ConsoleCategory {
        let message_lower = message.message.to_lowercase();

        for pattern in patterns {
            if message_lower.contains(&pattern.pattern.to_lowercase()) {
                return pattern.category.clone();
            }
        }

        ConsoleCategory::UserCode
    }

    /// Update console statistics
    fn update_stats(stats: &Arc<Mutex<ConsoleStats>>, message: &ConsoleMessage, category: &ConsoleCategory) {
        if let Ok(mut stats_guard) = stats.lock() {
            stats_guard.total_messages += 1;

            match message.level {
                BrowserLogLevel::Error | BrowserLogLevel::Assert => stats_guard.errors += 1,
                BrowserLogLevel::Warn => stats_guard.warnings += 1,
                BrowserLogLevel::Info => stats_guard.info_messages += 1,
                BrowserLogLevel::Debug | BrowserLogLevel::Trace => stats_guard.debug_messages += 1,
            }

            // Update category counts
            let category_key = format!("{:?}", category);
            *stats_guard.category_counts.entry(category_key).or_insert(0) += 1;

            // Track top error messages
            if matches!(message.level, BrowserLogLevel::Error | BrowserLogLevel::Assert) {
                let mut found = false;
                for (msg, count) in &mut stats_guard.top_error_messages {
                    if msg == &message.message {
                        *count += 1;
                        found = true;
                        break;
                    }
                }

                if !found {
                    stats_guard.top_error_messages.push((message.message.clone(), 1));
                }

                // Keep only top 10 error messages
                stats_guard.top_error_messages.sort_by(|a, b| b.1.cmp(&a.1));
                stats_guard.top_error_messages.truncate(10);
            }
        }
    }

    /// Create analytics event from console message
    fn create_console_event(message: ConsoleMessage, category: ConsoleCategory) -> AnalyticsEvent {
        let mut metadata = HashMap::new();
        metadata.insert("source".to_string(), serde_json::Value::String(message.source.clone()));
        metadata.insert("category".to_string(), serde_json::Value::String(format!("{:?}", category)));
        metadata.insert("browser_level".to_string(), serde_json::Value::String(format!("{:?}", message.level)));

        if let Some(line) = message.line {
            metadata.insert("line".to_string(), serde_json::Value::Number(line.into()));
        }

        if let Some(column) = message.column {
            metadata.insert("column".to_string(), serde_json::Value::Number(column.into()));
        }

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

        let event_type = match category {
            ConsoleCategory::ReactiveGraph => "reactive_graph_issue",
            ConsoleCategory::Hydration => "hydration_error",
            ConsoleCategory::WasmBinding => "wasm_error",
            ConsoleCategory::NetworkError => "network_error",
            ConsoleCategory::UnhandledPromise => "unhandled_promise",
            ConsoleCategory::PerformanceWarning => "performance_warning",
            ConsoleCategory::SecurityWarning => "security_warning",
            ConsoleCategory::UserCode => "console_message",
        }.to_string();

        let level: EventLevel = match message.level {
            BrowserLogLevel::Error | BrowserLogLevel::Assert => EventLevel::Error,
            BrowserLogLevel::Warn => EventLevel::Warn,
            BrowserLogLevel::Info => EventLevel::Info,
            BrowserLogLevel::Debug | BrowserLogLevel::Trace => EventLevel::Debug,
        };

        AnalyticsEvent {
            id: generate_event_id(),
            timestamp: message.timestamp,
            source: LogSource::Browser,
            event_type,
            session_id: None,
            path: Some(message.url.clone()),
            level,
            message: message.message,
            metadata,
            duration_ms: None,
            errors: if matches!(message.level, BrowserLogLevel::Error | BrowserLogLevel::Assert) {
                vec![message.message.clone()]
            } else {
                Vec::new()
            },
        }
    }

    /// Get current console statistics
    pub fn get_stats(&self) -> ConsoleStats {
        self.stats.lock().unwrap().clone()
    }

    /// Generate console analysis report
    pub fn generate_console_report(&self) -> String {
        let stats = self.get_stats();

        let mut report = String::from("🖥️ Browser Console Analysis\n\n");

        report.push_str(&format!("Total Messages: {}\n", stats.total_messages));
        report.push_str(&format!("Errors: {} ({:.1}%)\n",
            stats.errors,
            if stats.total_messages > 0 {
                stats.errors as f64 / stats.total_messages as f64 * 100.0
            } else { 0.0 }
        ));
        report.push_str(&format!("Warnings: {} ({:.1}%)\n",
            stats.warnings,
            if stats.total_messages > 0 {
                stats.warnings as f64 / stats.total_messages as f64 * 100.0
            } else { 0.0 }
        ));

        if !stats.category_counts.is_empty() {
            report.push_str("\nMessage Categories:\n");
            let mut categories: Vec<_> = stats.category_counts.iter().collect();
            categories.sort_by(|a, b| b.1.cmp(a.1));
            for (category, count) in categories.iter().take(5) {
                report.push_str(&format!("  {}: {}\n", category, count));
            }
        }

        if !stats.top_error_messages.is_empty() {
            report.push_str("\nTop Error Messages:\n");
            for (message, count) in stats.top_error_messages.iter().take(3) {
                let truncated = if message.len() > 60 {
                    format!("{}...", &message[..57])
                } else {
                    message.clone()
                };
                report.push_str(&format!("  {} ({}x)\n", truncated, count));
            }
        }

        report
    }
}

/// Console message structure
#[derive(Debug, Clone)]
pub struct ConsoleMessage {
    pub message: String,
    pub level: BrowserLogLevel,
    pub timestamp: chrono::DateTime<chrono::Utc>,
    pub source: String,
    pub line: Option<u32>,
    pub column: Option<u32>,
    pub url: String,
    pub stack_trace: Option<String>,
}
