//! # Memory Leak Detection System
//!
//! Production-grade memory leak detection and monitoring system for `SciRS2` Core
//! providing comprehensive memory profiling, leak testing, and integration with
//! memory profiling tools for enterprise deployments.
//!
//! ## Features
//!
//! - Real-time memory leak detection with configurable thresholds
//! - Integration with valgrind, AddressSanitizer, and other profiling tools
//! - Automatic leak testing for continuous integration
//! - Memory pattern analysis and anomaly detection
//! - Production-safe monitoring with minimal overhead
//! - Detailed leak reports with call stack information
//! - Integration with existing memory metrics system
//! - Support for custom allocation tracking
//!
//! ## Example
//!
//! ```rust
//! use scirs2_core::memory::leak_detection::{LeakDetector, LeakDetectionConfig};
//!
//! // Configure leak detection
//! let config = LeakDetectionConfig::default()
//!     .with_threshold_mb(100)
//!     .with_samplingrate(0.1);
//!
//! let mut detector = LeakDetector::new(config)?;
//!
//! // Start monitoring a function
//! let checkpoint = detector.create_checkpoint("matrix_operations")?;
//!
//! // Perform operations that might leak memory
//! fn performmatrix_calculations() {
//!     // Example computation that could potentially leak memory
//!     let matrix: Vec<Vec<f64>> = (0..100).map(|i| vec![i as f64; 100]).collect();
//! }
//! performmatrix_calculations();
//!
//! // Check for leaks
//! let report = detector.check_leaks(&checkpoint)?;
//! if report.has_leaks() {
//!     println!("Memory leaks detected: {}", report.summary());
//! }
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```

use crate::error::CoreError;
use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};
use std::time::Duration;
use uuid::Uuid;

#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};

/// Memory leak detection configuration
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct LeakDetectionConfig {
    /// Enable real-time leak detection
    pub enabled: bool,
    /// Memory growth threshold in bytes
    pub growth_threshold_bytes: u64,
    /// Time window for leak detection
    pub detection_window: Duration,
    /// Sampling rate for profiling (0.0 to 1.0)
    pub samplingrate: f64,
    /// Enable call stack collection
    pub collect_call_stacks: bool,
    /// Maximum number of tracked allocations
    pub max_tracked_allocations: usize,
    /// Enable integration with external profilers
    pub enable_external_profilers: bool,
    /// Profiler tools to use
    pub profiler_tools: Vec<ProfilerTool>,
    /// Enable periodic leak checks
    pub enable_periodic_checks: bool,
    /// Periodic check interval
    pub check_interval: Duration,
    /// Enable production monitoring mode
    pub production_mode: bool,
}

impl Default for LeakDetectionConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            growth_threshold_bytes: 100 * 1024 * 1024, // 100MB
            detection_window: Duration::from_secs(300), // 5 minutes
            samplingrate: 0.01,                        // 1% sampling in production
            collect_call_stacks: false,                // Expensive in production
            max_tracked_allocations: 10000,
            enable_external_profilers: false,
            profiler_tools: Vec::new(),
            enable_periodic_checks: true,
            check_interval: Duration::from_secs(60), // 1 minute
            production_mode: true,
        }
    }
}

impl LeakDetectionConfig {
    /// Set memory threshold in megabytes
    pub fn with_threshold_mb(mut self, mb: u64) -> Self {
        self.growth_threshold_bytes = mb * 1024 * 1024;
        self
    }

    /// Set sampling rate
    pub fn with_samplingrate(mut self, rate: f64) -> Self {
        self.samplingrate = rate.clamp(0.0, 1.0);
        self
    }

    /// Enable call stack collection
    pub fn with_call_stacks(mut self, enable: bool) -> Self {
        self.collect_call_stacks = enable;
        self
    }

    /// Enable development mode (more detailed tracking)
    pub fn development_mode(mut self) -> Self {
        self.production_mode = false;
        self.samplingrate = 1.0;
        self.collect_call_stacks = true;
        self.max_tracked_allocations = 100000;
        self
    }
}

/// External profiler tools
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ProfilerTool {
    /// Valgrind memcheck
    Valgrind,
    /// AddressSanitizer
    AddressSanitizer,
    /// Heaptrack
    Heaptrack,
    /// Massif (part of Valgrind)
    Massif,
    /// jemalloc profiling
    Jemalloc,
    /// Custom profiler
    Custom(String),
}

impl ProfilerTool {
    /// Get the tool name
    pub fn name(&self) -> &str {
        match self {
            ProfilerTool::Valgrind => "valgrind",
            ProfilerTool::AddressSanitizer => "asan",
            ProfilerTool::Heaptrack => "heaptrack",
            ProfilerTool::Massif => "massif",
            ProfilerTool::Jemalloc => "jemalloc",
            ProfilerTool::Custom(name) => name,
        }
    }
}

/// Memory checkpoint for leak detection
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct MemoryCheckpoint {
    /// Unique checkpoint identifier
    pub id: Uuid,
    /// Checkpoint name/label
    pub name: String,
    /// Timestamp when checkpoint was created
    pub timestamp: chrono::DateTime<chrono::Utc>,
    /// Memory usage at checkpoint creation
    pub memory_usage: MemoryUsage,
    /// Active allocations at checkpoint
    pub active_allocations: u64,
    /// Call stack when checkpoint was created
    pub call_stack: Option<CallStack>,
    /// Thread ID
    pub thread_id: u64,
    /// Process ID
    pub process_id: u32,
}

/// Memory usage snapshot
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct MemoryUsage {
    /// Resident set size (RSS) in bytes
    pub rss_bytes: u64,
    /// Virtual memory size in bytes
    pub virtual_bytes: u64,
    /// Heap size in bytes
    pub heap_bytes: Option<u64>,
    /// Stack size in bytes
    pub stack_bytes: Option<u64>,
    /// Number of memory mappings
    pub mappings_count: Option<u64>,
    /// Peak memory usage since start
    pub peak_bytes: Option<u64>,
}

/// Call stack information
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct CallStack {
    /// Stack frames
    pub frames: Vec<StackFrame>,
    /// Maximum depth captured
    pub max_depth: usize,
    /// Whether stack was truncated
    pub truncated: bool,
}

/// Individual stack frame
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct StackFrame {
    /// Function name
    pub function: Option<String>,
    /// File name
    pub file: Option<String>,
    /// Line number
    pub line: Option<u32>,
    /// Memory address
    pub address: u64,
    /// Module/library name
    pub module: Option<String>,
}

/// Memory leak report
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct LeakReport {
    /// Checkpoint information
    pub checkpoint: MemoryCheckpoint,
    /// Current memory usage
    pub current_usage: MemoryUsage,
    /// Memory growth since checkpoint
    pub memory_growth: i64,
    /// Detected leaks
    pub leaks: Vec<MemoryLeak>,
    /// Analysis summary
    pub summary: LeakSummary,
    /// Recommendations
    pub recommendations: Vec<String>,
    /// Detection timestamp
    pub detection_time: chrono::DateTime<chrono::Utc>,
}

impl LeakReport {
    /// Check if any leaks were detected
    pub fn has_leaks(&self) -> bool {
        !self.leaks.is_empty()
    }

    /// Get total leaked bytes
    pub fn total_leaked_bytes(&self) -> u64 {
        self.leaks.iter().map(|leak| leak.size_bytes).sum()
    }

    /// Get summary string
    pub fn summary(&self) -> String {
        if self.has_leaks() {
            format!(
                "{} leaks detected totaling {} bytes",
                self.leaks.len(),
                self.total_leaked_bytes()
            )
        } else {
            "No memory leaks detected".to_string()
        }
    }
}

/// Individual memory leak
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct MemoryLeak {
    /// Leak identifier
    pub id: Uuid,
    /// Size of the leak in bytes
    pub size_bytes: u64,
    /// Allocation site call stack
    pub allocation_stack: Option<CallStack>,
    /// Leak type
    pub leak_type: LeakType,
    /// Confidence level
    pub confidence: f64,
    /// First detected timestamp
    pub first_detected: chrono::DateTime<chrono::Utc>,
    /// Last seen timestamp
    pub last_seen: chrono::DateTime<chrono::Utc>,
    /// Allocation count
    pub allocation_count: u64,
}

/// Types of memory leaks
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LeakType {
    /// Definite leak - memory definitely lost
    Definite,
    /// Indirect leak - leak caused by other leaks
    Indirect,
    /// Possible leak - might be intentionally retained
    Possible,
    /// Reachable leak - still reachable but suspicious
    Reachable,
    /// Growth pattern - suspicious growth pattern
    GrowthPattern,
}

impl LeakType {
    /// Get the severity score (0-10)
    pub fn severity(&self) -> u8 {
        match self {
            LeakType::Definite => 10,
            LeakType::Indirect => 8,
            LeakType::Possible => 5,
            LeakType::Reachable => 3,
            LeakType::GrowthPattern => 7,
        }
    }
}

/// Leak detection summary
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct LeakSummary {
    /// Total number of leaks
    pub total_leaks: usize,
    /// Total leaked bytes
    pub total_leaked_bytes: u64,
    /// Leaks by type
    pub leaks_by_type: HashMap<String, usize>,
    /// Highest severity leak
    pub max_severity: u8,
    /// Average confidence
    pub average_confidence: f64,
    /// Memory growth rate (bytes per second)
    pub growth_rate: f64,
}

/// Allocation tracking information
#[derive(Debug, Clone)]
struct AllocationInfo {
    /// Allocation size
    size: u64,
    /// Allocation timestamp
    timestamp: chrono::DateTime<chrono::Utc>,
    /// Call stack at allocation
    call_stack: Option<CallStack>,
    /// Thread ID
    #[allow(dead_code)]
    thread_id: u64,
    /// Allocation ID
    #[allow(dead_code)]
    id: u64,
}

/// Memory leak detector implementation
pub struct LeakDetector {
    /// Configuration
    config: LeakDetectionConfig,
    /// Tracked allocations
    allocations: Arc<RwLock<HashMap<u64, AllocationInfo>>>,
    /// Address to allocation ID mapping
    address_to_id: Arc<RwLock<HashMap<u64, u64>>>,
    /// Checkpoints
    checkpoints: Arc<Mutex<HashMap<Uuid, MemoryCheckpoint>>>,
    /// Detection results
    reports: Arc<Mutex<Vec<LeakReport>>>,
    /// Background monitoring
    monitoring_active: Arc<Mutex<bool>>,
    /// Allocation counter
    allocation_counter: Arc<Mutex<u64>>,
    /// External profiler integrations
    profiler_integrations: Vec<Box<dyn ProfilerIntegration + Send + Sync>>,
}

impl LeakDetector {
    /// Create a new leak detector
    pub fn new(config: LeakDetectionConfig) -> Result<Self, CoreError> {
        let detector = Self {
            config,
            allocations: Arc::new(RwLock::new(HashMap::new())),
            address_to_id: Arc::new(RwLock::new(HashMap::new())),
            checkpoints: Arc::new(Mutex::new(HashMap::new())),
            reports: Arc::new(Mutex::new(Vec::new())),
            monitoring_active: Arc::new(Mutex::new(false)),
            allocation_counter: Arc::new(Mutex::new(0)),
            profiler_integrations: Vec::new(),
        };

        Ok(detector)
    }

    /// Start background monitoring
    pub fn startmonitoring(&self) -> Result<(), CoreError> {
        if !self.config.enabled || !self.config.enable_periodic_checks {
            return Ok(());
        }

        let mut monitoring = self.monitoring_active.lock().map_err(|_| {
            CoreError::ComputationError(crate::error::ErrorContext::new(
                "Failed to acquire monitoring lock".to_string(),
            ))
        })?;

        if *monitoring {
            return Ok(()); // Already monitoring
        }

        *monitoring = true;

        // In a real implementation, you'd spawn a background thread here
        // For now, we'll just mark monitoring as active
        Ok(())
    }

    /// Stop background monitoring
    pub fn stopmonitoring(&self) -> Result<(), CoreError> {
        let mut monitoring = self.monitoring_active.lock().map_err(|_| {
            CoreError::ComputationError(crate::error::ErrorContext::new(
                "Failed to acquire monitoring lock".to_string(),
            ))
        })?;
        *monitoring = false;
        Ok(())
    }

    /// Create a memory checkpoint
    pub fn create_checkpoint(&self, name: &str) -> Result<MemoryCheckpoint, CoreError> {
        let memory_usage = self.get_current_memory_usage()?;
        let call_stack = if self.config.collect_call_stacks {
            Some(self.capture_call_stack()?)
        } else {
            None
        };

        let checkpoint = MemoryCheckpoint {
            id: Uuid::new_v4(),
            name: name.to_string(),
            timestamp: chrono::Utc::now(),
            memory_usage,
            active_allocations: self.get_active_allocation_count()?,
            call_stack,
            thread_id: self.get_thread_id(),
            process_id: std::process::id(),
        };

        let mut checkpoints = self.checkpoints.lock().map_err(|_| {
            CoreError::ComputationError(crate::error::ErrorContext::new(
                "Failed to acquire checkpoints lock".to_string(),
            ))
        })?;
        checkpoints.insert(checkpoint.id, checkpoint.clone());

        Ok(checkpoint)
    }

    /// Check for memory leaks since a checkpoint
    pub fn check_leaks(&self, checkpoint: &MemoryCheckpoint) -> Result<LeakReport, CoreError> {
        let current_usage = self.get_current_memory_usage()?;
        let memory_growth =
            current_usage.rss_bytes as i64 - checkpoint.memory_usage.rss_bytes as i64;

        let mut leaks = Vec::new();

        // Check for threshold violations
        if memory_growth > self.config.growth_threshold_bytes as i64 {
            let leak = MemoryLeak {
                id: Uuid::new_v4(),
                size_bytes: memory_growth as u64,
                allocation_stack: checkpoint.call_stack.clone(),
                leak_type: LeakType::GrowthPattern,
                confidence: 0.8,
                first_detected: checkpoint.timestamp,
                last_seen: chrono::Utc::now(),
                allocation_count: 1,
            };
            leaks.push(leak);
        }

        // Analyze allocation patterns
        leaks.extend(self.analyze_allocation_patterns(checkpoint)?);

        // Run external profiler checks
        leaks.extend(self.run_external_profiler_checks()?);

        let summary = self.create_leak_summary(&leaks, memory_growth);
        let recommendations = self.generate_recommendations(&leaks, memory_growth);

        let report = LeakReport {
            checkpoint: checkpoint.clone(),
            current_usage,
            memory_growth,
            leaks,
            summary,
            recommendations,
            detection_time: chrono::Utc::now(),
        };

        // Store report
        let mut reports = self.reports.lock().map_err(|_| {
            CoreError::ComputationError(crate::error::ErrorContext::new(
                "Failed to acquire reports lock".to_string(),
            ))
        })?;
        reports.push(report.clone());

        Ok(report)
    }

    /// Track a memory allocation
    pub fn track_allocation(&self, size: u64, address: u64) -> Result<(), CoreError> {
        if !self.config.enabled {
            return Ok(());
        }

        // Apply sampling
        if self.config.samplingrate < 1.0 {
            use rand::RngExt;
            let mut rng = rand::rng();
            if rng.random::<f64>() > self.config.samplingrate {
                return Ok(());
            }
        }

        let mut counter = self.allocation_counter.lock().map_err(|_| {
            CoreError::ComputationError(crate::error::ErrorContext::new(
                "Failed to acquire allocation counter".to_string(),
            ))
        })?;
        *counter += 1;
        let allocation_id = *counter;

        let call_stack = if self.config.collect_call_stacks {
            Some(self.capture_call_stack()?)
        } else {
            None
        };

        let allocation_info = AllocationInfo {
            size,
            timestamp: chrono::Utc::now(),
            call_stack,
            thread_id: self.get_thread_id(),
            id: allocation_id,
        };

        let mut allocations = self.allocations.write().map_err(|_| {
            CoreError::ComputationError(crate::error::ErrorContext::new(
                "Failed to acquire allocations lock".to_string(),
            ))
        })?;

        // Prevent memory usage from growing too much
        if allocations.len() >= self.config.max_tracked_allocations {
            // Remove oldest allocation
            if let Some((oldest_id, oldest_info)) = allocations
                .iter()
                .min_by_key(|(_, info)| info.timestamp)
                .map(|(id, info)| (*id, info.clone()))
            {
                allocations.remove(&oldest_id);

                // Also remove from address_to_id mapping
                // Note: We don't have the address stored in AllocationInfo, so we'd need to
                // iterate through address_to_id to find it. In a real implementation,
                // AllocationInfo should store the address.
            }
        }

        allocations.insert(allocation_id, allocation_info);

        // Store address to ID mapping
        let mut address_to_id = self.address_to_id.write().map_err(|_| {
            CoreError::ComputationError(crate::error::ErrorContext::new(
                "Failed to acquire address_to_id lock".to_string(),
            ))
        })?;
        address_to_id.insert(address, allocation_id);

        Ok(())
    }

    /// Track memory deallocation
    pub fn track_deallocation(&self, address: u64) -> Result<(), CoreError> {
        if !self.config.enabled {
            return Ok(());
        }

        // Look up the allocation ID for this address
        let allocation_id = {
            let mut address_to_id = self.address_to_id.write().map_err(|_| {
                CoreError::ComputationError(crate::error::ErrorContext::new(
                    "Failed to acquire address_to_id lock".to_string(),
                ))
            })?;
            address_to_id.remove(&address)
        };

        if let Some(id) = allocation_id {
            let mut allocations = self.allocations.write().map_err(|_| {
                CoreError::ComputationError(crate::error::ErrorContext::new(
                    "Failed to acquire allocations lock".to_string(),
                ))
            })?;
            allocations.remove(&id);
        }

        Ok(())
    }

    /// Get current memory usage of this process.
    ///
    /// Resident and virtual sizes are read from the operating system. Heap
    /// usage is only reported when a real source is available (it is left as
    /// `None` otherwise rather than being fabricated, since the standard
    /// allocator exposes no portable heap-usage query).
    fn get_current_memory_usage(&self) -> Result<MemoryUsage, CoreError> {
        Ok(MemoryUsage {
            rss_bytes: self.get_rss_memory()?,
            virtual_bytes: self.get_virtual_memory()?,
            heap_bytes: self.get_heap_memory(),
            stack_bytes: None,
            mappings_count: None,
            peak_bytes: None,
        })
    }

    /// Get resident set size (RSS) memory in bytes.
    ///
    /// Reads the real value from the OS. On Linux this parses
    /// `/proc/self/status`; on other platforms it uses `sysinfo` when that
    /// feature is enabled. If no real source is available it returns an honest
    /// error instead of a fabricated number.
    fn get_rss_memory(&self) -> Result<u64, CoreError> {
        #[cfg(target_os = "linux")]
        {
            if let Ok(status) = std::fs::read_to_string("/proc/self/status") {
                for line in status.lines() {
                    if line.starts_with("VmRSS:") {
                        if let Some(kb_str) = line.split_whitespace().nth(1) {
                            if let Ok(kb) = kb_str.parse::<u64>() {
                                return Ok(kb * 1024); // Convert KB to bytes
                            }
                        }
                    }
                }
            }
        }

        #[cfg(feature = "sysinfo")]
        {
            use sysinfo::{Pid, ProcessRefreshKind, ProcessesToUpdate, System};
            let pid = Pid::from_u32(std::process::id());
            let mut system = System::new();
            system.refresh_processes_specifics(
                ProcessesToUpdate::Some(&[pid]),
                true,
                ProcessRefreshKind::nothing().with_memory(),
            );
            if let Some(process) = system.process(pid) {
                return Ok(process.memory());
            }
        }

        Err(CoreError::ComputationError(crate::error::ErrorContext::new(
            "Resident memory size is unavailable on this platform (enable the `sysinfo` feature for non-Linux support)".to_string(),
        )))
    }

    /// Get virtual memory size in bytes.
    ///
    /// Reads the real value from the OS (Linux `/proc/self/status`, or
    /// `sysinfo` when enabled). Returns an honest error when no real source is
    /// available rather than fabricating a value.
    fn get_virtual_memory(&self) -> Result<u64, CoreError> {
        #[cfg(target_os = "linux")]
        {
            if let Ok(status) = std::fs::read_to_string("/proc/self/status") {
                for line in status.lines() {
                    if line.starts_with("VmSize:") {
                        if let Some(kb_str) = line.split_whitespace().nth(1) {
                            if let Ok(kb) = kb_str.parse::<u64>() {
                                return Ok(kb * 1024); // Convert KB to bytes
                            }
                        }
                    }
                }
            }
        }

        #[cfg(feature = "sysinfo")]
        {
            use sysinfo::{Pid, ProcessRefreshKind, ProcessesToUpdate, System};
            let pid = Pid::from_u32(std::process::id());
            let mut system = System::new();
            system.refresh_processes_specifics(
                ProcessesToUpdate::Some(&[pid]),
                true,
                ProcessRefreshKind::nothing().with_memory(),
            );
            if let Some(process) = system.process(pid) {
                return Ok(process.virtual_memory());
            }
        }

        Err(CoreError::ComputationError(crate::error::ErrorContext::new(
            "Virtual memory size is unavailable on this platform (enable the `sysinfo` feature for non-Linux support)".to_string(),
        )))
    }

    /// Get heap memory usage in bytes, if a real source is available.
    ///
    /// The Rust standard allocator does not expose a portable heap-usage query,
    /// so this returns `None` unless a real source can be read. Returning a
    /// fabricated value here would corrupt downstream leak accounting, so the
    /// absence of data is reported honestly as `None`.
    fn get_heap_memory(&self) -> Option<u64> {
        // No portable real heap-usage source is wired up. When integrated with
        // an allocator that exposes statistics (e.g. jemalloc's `stats.allocated`),
        // this is where that value would be returned.
        None
    }

    /// Get active allocation count
    fn get_active_allocation_count(&self) -> Result<u64, CoreError> {
        let allocations = self.allocations.read().map_err(|_| {
            CoreError::ComputationError(crate::error::ErrorContext::new(
                "Failed to acquire allocations lock".to_string(),
            ))
        })?;
        Ok(allocations.len() as u64)
    }

    /// Capture the current call stack.
    ///
    /// Uses `std::backtrace::Backtrace`, which is the only backtrace facility
    /// available without pulling in the `backtrace` crate. The standard library
    /// exposes the backtrace as formatted text rather than structured frames, so
    /// each captured line is stored in the frame's `function` field; numeric
    /// addresses are not recoverable through `std` and are reported as `0`
    /// rather than being fabricated.
    ///
    /// If backtrace capture is disabled (e.g. `RUST_BACKTRACE` is unset) or
    /// unsupported on the platform, an empty (but honest) call stack is
    /// returned instead of inventing frames.
    fn capture_call_stack(&self) -> Result<CallStack, CoreError> {
        use std::backtrace::{Backtrace, BacktraceStatus};

        let backtrace = Backtrace::capture();

        if backtrace.status() != BacktraceStatus::Captured {
            // Capturing is disabled or unsupported: report no frames honestly.
            return Ok(CallStack {
                frames: Vec::new(),
                max_depth: 0,
                truncated: false,
            });
        }

        let rendered = backtrace.to_string();
        let mut frames = Vec::new();
        for line in rendered.lines() {
            let trimmed = line.trim();
            if trimmed.is_empty() {
                continue;
            }
            frames.push(StackFrame {
                function: Some(trimmed.to_string()),
                file: None,
                line: None,
                // std does not expose resolved instruction addresses; use 0
                // rather than a fabricated value.
                address: 0,
                module: None,
            });
        }

        let max_depth = frames.len();
        Ok(CallStack {
            frames,
            max_depth,
            truncated: false,
        })
    }

    /// Get current thread ID
    fn get_thread_id(&self) -> u64 {
        // Simplified implementation
        use std::thread;
        format!("{:?}", thread::current().id())
            .chars()
            .filter_map(|c| c.to_digit(10))
            .map(|d| d as u64)
            .fold(0, |acc, d| acc * 10 + d)
    }

    /// Analyze allocation patterns for leaks
    fn analyze_allocation_patterns(
        &self,
        _checkpoint: &MemoryCheckpoint,
    ) -> Result<Vec<MemoryLeak>, CoreError> {
        let mut leaks = Vec::new();

        let allocations = self.allocations.read().map_err(|_| {
            CoreError::ComputationError(crate::error::ErrorContext::new(
                "Failed to acquire allocations lock".to_string(),
            ))
        })?;

        // Look for suspicious patterns
        let now = chrono::Utc::now();
        let old_threshold = now - Duration::from_secs(3600); // 1 hour

        for (_id, allocation) in allocations.iter() {
            if allocation.timestamp < old_threshold && allocation.size > 1024 * 1024 {
                // Large allocation that's been around for a while
                leaks.push(MemoryLeak {
                    id: Uuid::new_v4(),
                    size_bytes: allocation.size,
                    allocation_stack: allocation.call_stack.clone(),
                    leak_type: LeakType::Possible,
                    confidence: 0.6,
                    first_detected: allocation.timestamp,
                    last_seen: now,
                    allocation_count: 1,
                });
            }
        }

        Ok(leaks)
    }

    /// Run external profiler checks
    fn run_external_profiler_checks(&self) -> Result<Vec<MemoryLeak>, CoreError> {
        let mut leaks = Vec::new();

        for integration in &self.profiler_integrations {
            leaks.extend(integration.check_leaks()?);
        }

        Ok(leaks)
    }

    /// Create leak summary
    fn create_leak_summary(&self, leaks: &[MemoryLeak], memorygrowth: i64) -> LeakSummary {
        let total_leaks = leaks.len();
        let total_leaked_bytes = leaks.iter().map(|leak| leak.size_bytes).sum();

        let mut leaks_by_type = HashMap::new();
        for leak in leaks {
            let type_name = format!("{0:?}", leak.leak_type);
            *leaks_by_type.entry(type_name).or_insert(0) += 1;
        }

        let max_severity = leaks
            .iter()
            .map(|leak| leak.leak_type.severity())
            .max()
            .unwrap_or(0);

        let average_confidence = if total_leaks > 0 {
            leaks.iter().map(|leak| leak.confidence).sum::<f64>() / total_leaks as f64
        } else {
            0.0
        };

        let growth_rate = memorygrowth as f64 / 60.0; // bytes per second (assuming 1 minute window)

        LeakSummary {
            total_leaks,
            total_leaked_bytes,
            leaks_by_type,
            max_severity,
            average_confidence,
            growth_rate,
        }
    }

    /// Generate recommendations based on detected leaks
    fn generate_recommendations(&self, leaks: &[MemoryLeak], memorygrowth: i64) -> Vec<String> {
        let mut recommendations = Vec::new();

        if leaks.is_empty() && memorygrowth < 1024 * 1024 {
            recommendations.push("No significant memory issues detected".to_string());
            return recommendations;
        }

        if memorygrowth > self.config.growth_threshold_bytes as i64 {
            recommendations.push(format!(
                "Memory growth of {memorygrowth} bytes exceeds threshold, investigate allocation patterns"
            ));
        }

        let definite_leaks: Vec<_> = leaks
            .iter()
            .filter(|leak| leak.leak_type == LeakType::Definite)
            .collect();

        if !definite_leaks.is_empty() {
            recommendations.push(format!(
                "{} definite leaks detected - fix these immediately",
                definite_leaks.len()
            ));
        }

        let large_leaks: Vec<_> = leaks.iter()
            .filter(|leak| leak.size_bytes > 10 * 1024 * 1024) // > 10MB
            .collect();

        if !large_leaks.is_empty() {
            recommendations.push(format!(
                "{} large leaks (>10MB) detected - prioritize fixing these",
                large_leaks.len()
            ));
        }

        if leaks.iter().any(|leak| leak.confidence > 0.8) {
            recommendations.push("High confidence leaks detected - likely real issues".to_string());
        }

        recommendations.push(
            "Consider running with valgrind or AddressSanitizer for detailed analysis".to_string(),
        );

        recommendations
    }

    /// Get all reports
    pub fn get_reports(&self) -> Result<Vec<LeakReport>, CoreError> {
        let reports = self.reports.lock().map_err(|_| {
            CoreError::ComputationError(crate::error::ErrorContext::new(
                "Failed to acquire reports lock".to_string(),
            ))
        })?;
        Ok(reports.clone())
    }

    /// Clear old reports
    pub fn clear_old_reports(&self, maxage: Duration) -> Result<usize, CoreError> {
        let mut reports = self.reports.lock().map_err(|_| {
            CoreError::ComputationError(crate::error::ErrorContext::new(
                "Failed to acquire reports lock".to_string(),
            ))
        })?;

        let cutoff = chrono::Utc::now()
            - chrono::Duration::from_std(maxage).map_err(|e| {
                CoreError::ComputationError(crate::error::ErrorContext::new(format!(
                    "Invalid duration: {e}"
                )))
            })?;

        let initial_len = reports.len();
        reports.retain(|report| report.detection_time > cutoff);

        Ok(initial_len - reports.len())
    }
}

/// Trait for external profiler integrations
pub trait ProfilerIntegration {
    /// Check for leaks using the external profiler
    fn check_leaks(&self) -> Result<Vec<MemoryLeak>, CoreError>;

    /// Get profiler name
    fn name(&self) -> &str;

    /// Check if profiler is available
    fn is_available(&self) -> bool;
}

/// Valgrind integration
pub struct ValgrindIntegration {
    enabled: bool,
}

impl ValgrindIntegration {
    pub fn new() -> Self {
        Self {
            enabled: Self::check_valgrind_available(),
        }
    }

    fn check_valgrind_available() -> bool {
        // Check if running under valgrind
        std::env::var("VALGRIND_OPTS").is_ok() || std::env::var("RUNNING_ON_VALGRIND").is_ok()
    }
}

impl ProfilerIntegration for ValgrindIntegration {
    fn check_leaks(&self) -> Result<Vec<MemoryLeak>, CoreError> {
        if !self.enabled {
            // Not running under valgrind: there is genuinely nothing to report.
            return Ok(Vec::new());
        }

        // We detected a valgrind environment, but parsing valgrind's leak report
        // (e.g. via the Valgrind client request API or its XML output) is not
        // implemented. Returning an empty list here would falsely claim "no
        // leaks", so report honestly that the integration cannot perform the
        // check rather than fabricating a clean result.
        Err(CoreError::ComputationError(
            crate::error::ErrorContext::new(
                "Valgrind leak parsing is not implemented; cannot report leak results".to_string(),
            ),
        ))
    }

    fn name(&self) -> &str {
        "valgrind"
    }

    fn is_available(&self) -> bool {
        self.enabled
    }
}

impl Default for ValgrindIntegration {
    fn default() -> Self {
        Self::new()
    }
}

/// RAII guard for automatic leak checking
pub struct LeakCheckGuard<'a> {
    detector: &'a LeakDetector,
    checkpoint: MemoryCheckpoint,
    check_on_drop: bool,
}

impl<'a> LeakCheckGuard<'a> {
    /// Create a new leak check guard
    pub fn new(detector: &'a LeakDetector, name: &str) -> Result<Self, CoreError> {
        let checkpoint = detector.create_checkpoint(name)?;
        Ok(Self {
            detector,
            checkpoint,
            check_on_drop: true,
        })
    }

    /// Disable automatic check on drop
    pub fn disable_auto_check(mut self) -> Self {
        self.check_on_drop = false;
        self
    }

    /// Manually check for leaks
    pub fn check_leaks(&self) -> Result<LeakReport, CoreError> {
        self.detector.check_leaks(&self.checkpoint)
    }
}

impl Drop for LeakCheckGuard<'_> {
    fn drop(&mut self) {
        if self.check_on_drop {
            if let Ok(report) = self.detector.check_leaks(&self.checkpoint) {
                if report.has_leaks() {
                    eprintln!(
                        "Memory leaks detected in {}: {}",
                        self.checkpoint.name,
                        report.summary()
                    );
                }
            }
        }
    }
}

/// Convenience macro for leak checking
#[macro_export]
macro_rules! check_leaks {
    ($detector:expr, $name:expr, $block:block) => {{
        let guard = $crate::memory::leak_detection::LeakCheckGuard::new($detector, $name)?;
        $block
    }};
}

/// Global leak detector instance
static GLOBAL_DETECTOR: std::sync::OnceLock<Arc<Mutex<LeakDetector>>> = std::sync::OnceLock::new();

/// Get the global leak detector
#[allow(dead_code)]
pub fn global_leak_detector() -> Arc<Mutex<LeakDetector>> {
    GLOBAL_DETECTOR
        .get_or_init(|| {
            let config = LeakDetectionConfig::default();
            Arc::new(Mutex::new(
                LeakDetector::new(config).expect("Failed to create global leak detector"),
            ))
        })
        .clone()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_leak_detector_creation() {
        let config = LeakDetectionConfig::default();
        let detector = LeakDetector::new(config).expect("Operation failed");

        assert!(!*detector.monitoring_active.lock().expect("Operation failed"));
    }

    // Requires a real RSS source: Linux (/proc/self/status) or the `sysinfo` feature on other platforms.
    #[cfg(any(target_os = "linux", feature = "sysinfo"))]
    #[test]
    fn test_checkpoint_creation() {
        let config = LeakDetectionConfig::default();
        let detector = LeakDetector::new(config).expect("Operation failed");

        let checkpoint = detector
            .create_checkpoint("test")
            .expect("Operation failed");
        assert_eq!(checkpoint.name, "test");
        assert!(checkpoint.memory_usage.rss_bytes > 0);
    }

    #[test]
    fn test_allocation_tracking() {
        let config = LeakDetectionConfig::default().development_mode();
        let detector = LeakDetector::new(config).expect("Operation failed");

        detector
            .track_allocation(1024, 0x12345678)
            .expect("Operation failed");
        detector
            .track_allocation(2048, 0x87654321)
            .expect("Operation failed");

        let count = detector
            .get_active_allocation_count()
            .expect("Operation failed");
        assert_eq!(count, 2);

        detector
            .track_deallocation(0x12345678)
            .expect("Operation failed");
        let count = detector
            .get_active_allocation_count()
            .expect("Operation failed");
        assert_eq!(count, 1);
    }

    // Requires a real RSS source: Linux (/proc/self/status) or the `sysinfo` feature on other platforms.
    #[cfg(any(target_os = "linux", feature = "sysinfo"))]
    #[test]
    fn test_leak_check_guard() {
        let config = LeakDetectionConfig::default();
        let detector = LeakDetector::new(config).expect("Operation failed");

        {
            let guard = LeakCheckGuard::new(&detector, "test_guard").expect("Operation failed");
            // Simulate some work that might leak memory
            detector
                .track_allocation(1024 * 1024, 0x12345678)
                .expect("Operation failed");
        } // Guard drops here and checks for leaks
    }

    #[test]
    fn test_leak_types() {
        assert_eq!(LeakType::Definite.severity(), 10);
        assert_eq!(LeakType::Possible.severity(), 5);
        assert!(LeakType::Definite.severity() > LeakType::Possible.severity());
    }

    #[test]
    fn test_config_builder() {
        let config = LeakDetectionConfig::default()
            .with_threshold_mb(50)
            .with_samplingrate(0.5)
            .with_call_stacks(true);

        assert_eq!(config.growth_threshold_bytes, 50 * 1024 * 1024);
        assert_eq!(config.samplingrate, 0.5);
        assert!(config.collect_call_stacks);
    }

    #[test]
    fn test_profiler_tools() {
        assert_eq!(ProfilerTool::Valgrind.name(), "valgrind");
        assert_eq!(ProfilerTool::AddressSanitizer.name(), "asan");
        assert_eq!(ProfilerTool::Custom("custom".to_string()).name(), "custom");
    }

    #[test]
    fn test_memory_usage() {
        let usage = MemoryUsage {
            rss_bytes: 64 * 1024 * 1024,
            virtual_bytes: 256 * 1024 * 1024,
            heap_bytes: Some(32 * 1024 * 1024),
            stack_bytes: None,
            mappings_count: None,
            peak_bytes: None,
        };

        assert_eq!(usage.rss_bytes, 64 * 1024 * 1024);
        assert!(usage.heap_bytes.is_some());
    }
}
