//! Browser Error Detection
//!
//! Detects and analyzes browser-side errors including:
//! - JavaScript runtime errors
//! - Unhandled promise rejections
//! - Resource loading failures
//! - Network request errors

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

/// Error detection patterns
#[derive(Debug, Clone)]
pub struct ErrorPattern {
    pub pattern: String,
    pub error_type: ErrorType,
    pub severity: ErrorSeverity,
    pub actionable: bool,
}

/// Error types
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ErrorType {
    RuntimeError,
    ReferenceError,
    TypeError,
    SyntaxError,
    NetworkError,
    ResourceError,
    PermissionError,
    SecurityError,
    UnhandledPromise,
}

/// Error severity levels
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ErrorSeverity {
    Low,
    Medium,
    High,
    Critical,
}

/// Error statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorStats {
    pub total_errors: u64,
    pub error_types: HashMap<String, u64>,
    pub error_sources: HashMap<String, u64>,
    pub critical_errors: u64,
    pub actionable_errors: u64,
    pub recent_error_rate: f64, // errors per minute
}

impl Default for ErrorStats {
    fn default() -> Self {
        Self {
            total_errors: 0,
            error_types: HashMap::new(),
            error_sources: HashMap::new(),
            critical_errors: 0,
            actionable_errors: 0,
            recent_error_rate: 0.0,
        }
    }
}

/// Browser error detector
pub struct ErrorDetector {
    patterns: Vec<ErrorPattern>,
    monitoring_interval: u64,
}

impl ErrorDetector {
    /// Create new error detector
    pub fn new() -> Self {
        let patterns = Self::create_error_patterns();

        Self {
            patterns,
            monitoring_interval: 15, // 15 seconds
        }
    }

    /// Create error detection patterns
    fn create_error_patterns() -> Vec<ErrorPattern> {
        vec![
            ErrorPattern {
                pattern: "ReferenceError".to_string(),
                error_type: ErrorType::ReferenceError,
                severity: ErrorSeverity::High,
                actionable: true,
            },
            ErrorPattern {
                pattern: "TypeError".to_string(),
                error_type: ErrorType::TypeError,
                severity: ErrorSeverity::Medium,
                actionable: true,
            },
            ErrorPattern {
                pattern: "SyntaxError".to_string(),
                error_type: ErrorType::SyntaxError,
                severity: ErrorSeverity::Critical,
                actionable: true,
            },
            ErrorPattern {
                pattern: "NetworkError".to_string(),
                error_type: ErrorType::NetworkError,
                severity: ErrorSeverity::Medium,
                actionable: false,
            },
            ErrorPattern {
                pattern: "Failed to load resource".to_string(),
                error_type: ErrorType::ResourceError,
                severity: ErrorSeverity::Medium,
                actionable: true,
            },
            ErrorPattern {
                pattern: "Permission denied".to_string(),
                error_type: ErrorType::PermissionError,
                severity: ErrorSeverity::High,
                actionable: true,
            },
            ErrorPattern {
                pattern: "Content Security Policy".to_string(),
                error_type: ErrorType::SecurityError,
                severity: ErrorSeverity::High,
                actionable: true,
            },
            ErrorPattern {
                pattern: "Unhandled promise rejection".to_string(),
                error_type: ErrorType::UnhandledPromise,
                severity: ErrorSeverity::High,
                actionable: true,
            },
        ]
    }

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

        let patterns = self.patterns.clone();
        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 error detection
                // In a real implementation, this would:
                // - Listen to browser error events
                // - Monitor unhandled promise rejections
                // - Track network failures
                // - Parse console error messages

                if let Ok(errors) = Self::detect_errors().await {
                    for error in errors {
                        let pattern = Self::match_error_pattern(&error, &patterns);
                        let event = Self::create_error_event(error, pattern);

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

        tracing::info!("Error detection started");
        Ok(())
    }

    /// Detect browser errors (simulated)
    async fn detect_errors() -> Result<Vec<DetectedError>> {
        let mut errors = Vec::new();

        // Simulate error detection with realistic patterns
        if rand::random::<f64>() < 0.2 { // 20% chance of detecting errors
            let error_scenarios = vec![
                DetectedError {
                    message: "ReferenceError: variable is not defined".to_string(),
                    source: "/js/main.js".to_string(),
                    line: 145,
                    column: 23,
                    timestamp: Utc::now(),
                    stack_trace: Some("at Object.<anonymous> (/js/main.js:145:23)".to_string()),
                    url: "/current/page".to_string(),
                },
                DetectedError {
                    message: "Failed to load resource: net::ERR_CONNECTION_REFUSED".to_string(),
                    source: "/api/data".to_string(),
                    line: 0,
                    column: 0,
                    timestamp: Utc::now(),
                    stack_trace: None,
                    url: "/api/data".to_string(),
                },
                DetectedError {
                    message: "Unhandled promise rejection: timeout".to_string(),
                    source: "/js/async.js".to_string(),
                    line: 67,
                    column: 12,
                    timestamp: Utc::now(),
                    stack_trace: Some("at fetchData (/js/async.js:67:12)".to_string()),
                    url: "/current/page".to_string(),
                },
            ];

            let selected_error = &error_scenarios[rand::random::<usize>() % error_scenarios.len()];
            errors.push(selected_error.clone());
        }

        Ok(errors)
    }

    /// Match error against patterns
    fn match_error_pattern(error: &DetectedError, patterns: &[ErrorPattern]) -> Option<ErrorPattern> {
        for pattern in patterns {
            if error.message.contains(&pattern.pattern) {
                return Some(pattern.clone());
            }
        }
        None
    }

    /// Create analytics event from detected error
    fn create_error_event(error: DetectedError, pattern: Option<ErrorPattern>) -> AnalyticsEvent {
        let mut metadata = HashMap::new();
        metadata.insert("source".to_string(), serde_json::Value::String(error.source.clone()));
        metadata.insert("line".to_string(), serde_json::Value::Number(error.line.into()));
        metadata.insert("column".to_string(), serde_json::Value::Number(error.column.into()));
        metadata.insert("url".to_string(), serde_json::Value::String(error.url.clone()));

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

        let (error_type, severity, actionable) = if let Some(ref p) = pattern {
            (
                format!("{:?}", p.error_type),
                p.severity.clone(),
                p.actionable,
            )
        } else {
            ("UnknownError".to_string(), ErrorSeverity::Medium, false)
        };

        metadata.insert("error_type".to_string(), serde_json::Value::String(error_type));
        metadata.insert("severity".to_string(), serde_json::Value::String(format!("{:?}", severity)));
        metadata.insert("actionable".to_string(), serde_json::Value::Bool(actionable));

        let level = match severity {
            ErrorSeverity::Critical => EventLevel::Critical,
            ErrorSeverity::High => EventLevel::Error,
            ErrorSeverity::Medium => EventLevel::Warn,
            ErrorSeverity::Low => EventLevel::Info,
        };

        let event_type = if actionable {
            "actionable_browser_error"
        } else {
            "browser_error"
        }.to_string();

        AnalyticsEvent {
            id: generate_event_id(),
            timestamp: error.timestamp,
            source: LogSource::Browser,
            event_type,
            session_id: None,
            path: Some(error.url),
            level,
            message: error.message.clone(),
            metadata,
            duration_ms: None,
            errors: vec![error.message],
        }
    }

    /// Generate error analysis report
    pub fn generate_error_report(stats: &ErrorStats) -> String {
        let mut report = String::from("🚨 Browser Error Analysis\n\n");

        report.push_str(&format!("Total Errors: {}\n", stats.total_errors));
        report.push_str(&format!("Critical Errors: {}\n", stats.critical_errors));
        report.push_str(&format!("Actionable Errors: {}\n", stats.actionable_errors));
        report.push_str(&format!("Error Rate: {:.2} errors/minute\n\n", stats.recent_error_rate));

        if !stats.error_types.is_empty() {
            report.push_str("Error Types:\n");
            let mut types: Vec<_> = stats.error_types.iter().collect();
            types.sort_by(|a, b| b.1.cmp(a.1));
            for (error_type, count) in types.iter().take(5) {
                report.push_str(&format!("  {}: {}\n", error_type, count));
            }
            report.push('\n');
        }

        if !stats.error_sources.is_empty() {
            report.push_str("Top Error Sources:\n");
            let mut sources: Vec<_> = stats.error_sources.iter().collect();
            sources.sort_by(|a, b| b.1.cmp(a.1));
            for (source, count) in sources.iter().take(3) {
                report.push_str(&format!("  {}: {}\n", source, count));
            }
        }

        // Add recommendations
        report.push_str("\n📋 Recommendations:\n");
        if stats.critical_errors > 0 {
            report.push_str("  🔴 Fix critical syntax errors immediately\n");
        }
        if stats.actionable_errors > stats.total_errors / 2 {
            report.push_str("  🟡 Focus on actionable errors for quick wins\n");
        }
        if stats.recent_error_rate > 5.0 {
            report.push_str("  🟠 High error rate detected - investigate error patterns\n");
        }

        report
    }
}

/// Detected browser error
#[derive(Debug, Clone)]
pub struct DetectedError {
    pub message: String,
    pub source: String,
    pub line: u32,
    pub column: u32,
    pub timestamp: chrono::DateTime<chrono::Utc>,
    pub stack_trace: Option<String>,
    pub url: String,
}
