//! Variable Registry - Simple HashMap-based variable name tracking
//!
//! This module provides a lightweight alternative to log-based tracking,
//! using a global HashMap to store variable address -> variable info mappings.

use crate::core::{MemScopeError, MemScopeResult};
use rayon::prelude::*;
use std::collections::HashMap;
use std::sync::{Arc, Mutex, OnceLock};

/// Variable information stored in registry
#[derive(Debug, Clone, serde::Serialize)]
pub struct VariableInfo {
    /// User-defined variable name
    pub var_name: String,
    /// Type name of the variable
    pub type_name: String,
    /// Timestamp when variable was registered
    pub timestamp: u64,
    /// Estimated size of the variable
    pub size: usize,
    /// Thread ID that created this variable
    pub thread_id: usize,
    /// Memory usage of this variable
    pub memory_usage: u64,
}

/// Global variable registry using HashMap for fast lookups
static GLOBAL_VARIABLE_REGISTRY: OnceLock<Arc<Mutex<HashMap<usize, VariableInfo>>>> =
    OnceLock::new();

/// Get or initialize the global variable registry
fn get_global_registry() -> Arc<Mutex<HashMap<usize, VariableInfo>>> {
    GLOBAL_VARIABLE_REGISTRY
        .get_or_init(|| Arc::new(Mutex::new(HashMap::new())))
        .clone()
}

/// Variable Registry - manages variable address to name mappings
pub struct VariableRegistry;

impl VariableRegistry {
    /// Register a variable with its address and information.
    ///
    /// # Thread Safety
    /// This function uses a try-lock on the global registry. If the lock is
    /// unavailable (high contention), registration is silently skipped.
    /// In debug builds, a warning is printed to stderr in this case.
    ///
    /// # Return Value
    /// Returns `Ok(())` on success. Note: due to lock-free design,
    /// registration failures are silently ignored to avoid blocking.
    pub fn register_variable(
        address: usize,
        var_name: String,
        type_name: String,
        size: usize,
    ) -> MemScopeResult<()> {
        let thread_id = {
            // Use a simple atomic counter for thread IDs instead of hash
            static THREAD_COUNTER: std::sync::atomic::AtomicUsize =
                std::sync::atomic::AtomicUsize::new(1);
            static THREAD_ID_MAP: std::sync::OnceLock<
                std::sync::Mutex<std::collections::HashMap<std::thread::ThreadId, usize>>,
            > = std::sync::OnceLock::new();

            let map = THREAD_ID_MAP
                .get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()));
            let current_thread_id = std::thread::current().id();

            if let Ok(mut map) = map.try_lock() {
                *map.entry(current_thread_id).or_insert_with(|| {
                    THREAD_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
                })
            } else {
                // Fallback if we can't get the lock
                1
            }
        };
        let timestamp = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_nanos() as u64;

        let var_info = VariableInfo {
            var_name,
            type_name,
            timestamp,
            size,
            thread_id,
            memory_usage: size as u64,
        };

        // Retry mechanism to prevent data loss under high contention
        let mut retry_count = 0;
        const MAX_RETRIES: usize = 5;
        const INITIAL_BACKOFF_MS: u64 = 1;

        loop {
            if let Ok(mut registry) = get_global_registry().try_lock() {
                registry.insert(address, var_info);
                break;
            } else {
                retry_count += 1;
                if retry_count >= MAX_RETRIES {
                    tracing::warn!(
                        "Variable registration for '{}' dropped after {} retries due to lock contention. ptr=0x{:x}, size={}",
                        var_info.var_name, MAX_RETRIES, address, size
                    );
                    break;
                }

                // Exponential backoff: 1ms, 2ms, 4ms, 8ms, 16ms
                let backoff_ms = INITIAL_BACKOFF_MS * (1 << (retry_count - 1));
                std::thread::sleep(std::time::Duration::from_millis(backoff_ms));
            }
        }

        Ok(())
    }

    /// Get variable information by address
    pub fn get_variable_info(address: usize) -> Option<VariableInfo> {
        if let Ok(registry) = get_global_registry().try_lock() {
            registry.get(&address).cloned()
        } else {
            None
        }
    }

    /// Mark a variable as destroyed with destruction timestamp
    pub fn mark_variable_destroyed(address: usize, destruction_time: u64) -> MemScopeResult<()> {
        // For now, we keep the variable in registry but could add destruction_time field
        // This method ensures the variable registry is aware of destruction events
        tracing::debug!(
            "Variable at address 0x{:x} destroyed at {}",
            address,
            destruction_time
        );
        Ok(())
    }

    /// Get all variable mappings
    pub fn get_all_variables() -> HashMap<usize, VariableInfo> {
        if let Ok(registry) = get_global_registry().try_lock() {
            registry.clone()
        } else {
            HashMap::new()
        }
    }

    /// Enhance tracker allocations with variable names from registry (optimized with parallel processing)
    pub fn enhance_allocations_with_registry(
        allocations: &[crate::core::types::AllocationInfo],
    ) -> Vec<serde_json::Value> {
        // Early return for small datasets
        if allocations.len() < 100 {
            return Self::enhance_allocations_sequential(allocations);
        }

        tracing::info!(
            "🚀 Processing {} allocations with parallel optimization...",
            allocations.len()
        );

        let registry = Self::get_all_variables();
        let start_time = std::time::Instant::now();

        // Convert to new system allocation types
        let allocations: Vec<crate::capture::types::AllocationInfo> =
            allocations.iter().map(|a| a.clone().into()).collect();

        // Use parallel processing for large datasets
        let enhanced: Vec<serde_json::Value> = allocations
            .par_iter()
            .map(|alloc| Self::classify_single_allocation(alloc, &registry))
            .collect();

        let duration = start_time.elapsed();
        tracing::info!(
            "✅ Parallel processing completed in {:?} ({:.2} allocs/ms)",
            duration,
            allocations.len() as f64 / duration.as_millis() as f64
        );

        enhanced
    }

    /// Sequential processing for small datasets
    fn enhance_allocations_sequential(
        allocations: &[crate::core::types::AllocationInfo],
    ) -> Vec<serde_json::Value> {
        let registry = Self::get_all_variables();

        // Convert to new system allocation types
        let allocations: Vec<crate::capture::types::AllocationInfo> =
            allocations.iter().map(|a| a.clone().into()).collect();

        allocations
            .iter()
            .map(|alloc| Self::classify_single_allocation(alloc, &registry))
            .collect()
    }

    /// Classify and enhance allocations with user/system distinction and scope information
    fn classify_and_enhance_allocations(
        allocations: &[crate::capture::types::allocation::AllocationInfo],
        registry: &HashMap<usize, VariableInfo>,
    ) -> Vec<serde_json::Value> {
        allocations
            .par_iter()
            .map(|alloc| Self::classify_single_allocation(alloc, registry))
            .collect()
    }

    /// Classify a single allocation as user or system with full context
    fn classify_single_allocation(
        alloc: &crate::capture::types::allocation::AllocationInfo,
        registry: &HashMap<usize, VariableInfo>,
    ) -> serde_json::Value {
        // Check if this is a user-tracked variable (highest priority)
        if let Some(var_info) = registry.get(&alloc.ptr) {
            return serde_json::json!({
                "ptr": alloc.ptr,
                "size": alloc.size,
                "timestamp_alloc": alloc.timestamp_alloc,
                "timestamp_dealloc": alloc.timestamp_dealloc,
                "variable_name": var_info.var_name,
                "type_name": var_info.type_name,
                "scope_name": Self::extract_scope_from_var_name(&var_info.var_name),
                "allocation_source": "user",
                "tracking_method": "track_var_macro",
                "registry_timestamp": var_info.timestamp,
                "registry_size": var_info.size,
                "lifetime_ms": alloc.timestamp_dealloc.map(|dealloc|
                    (dealloc.saturating_sub(alloc.timestamp_alloc)) / 1_000_000
                ),
                "current_age_ms": if alloc.timestamp_dealloc.is_none() {
                    // For active allocations, calculate how long they've been alive
                    let current_time = std::time::SystemTime::now()
                        .duration_since(std::time::UNIX_EPOCH)
                        .unwrap_or_default()
                        .as_nanos() as u64;
                    Some((current_time.saturating_sub(alloc.timestamp_alloc)) / 1_000_000)
                } else {
                    None
                },
                "is_active": alloc.timestamp_dealloc.is_none()
            });
        }

        // Check if allocation has explicit variable information (user allocation)
        if let (Some(var_name), Some(type_name)) = (&alloc.var_name, &alloc.type_name) {
            return serde_json::json!({
                "ptr": alloc.ptr,
                "size": alloc.size,
                "timestamp_alloc": alloc.timestamp_alloc,
                "timestamp_dealloc": alloc.timestamp_dealloc,
                "variable_name": var_name,
                "type_name": type_name,
                "scope_name": alloc.scope_name.as_deref().unwrap_or("user_scope"),
                "allocation_source": "user",
                "tracking_method": "explicit_tracking",
                "lifetime_ms": alloc.timestamp_dealloc.map(|dealloc|
                    (dealloc.saturating_sub(alloc.timestamp_alloc)) / 1_000_000
                ),
                "current_age_ms": if alloc.timestamp_dealloc.is_none() {
                    let current_time = std::time::SystemTime::now()
                        .duration_since(std::time::UNIX_EPOCH)
                        .unwrap_or_default()
                        .as_nanos() as u64;
                    Some((current_time.saturating_sub(alloc.timestamp_alloc)) / 1_000_000)
                } else {
                    None
                },
                "is_active": alloc.timestamp_dealloc.is_none()
            });
        }

        // This is a system allocation - apply smart inference
        let (inferred_var_name, inferred_type_name) = Self::infer_allocation_info_cached(alloc);
        let system_category = Self::categorize_system_allocation(alloc);

        serde_json::json!({
            "ptr": alloc.ptr,
            "size": alloc.size,
            "timestamp_alloc": alloc.timestamp_alloc,
            "timestamp_dealloc": alloc.timestamp_dealloc,
            "variable_name": inferred_var_name,
            "type_name": inferred_type_name,
            "scope_name": "system",
            "allocation_source": "system",
            "tracking_method": "automatic_inference",
            "system_category": system_category,
            "lifetime_ms": alloc.timestamp_dealloc.map(|dealloc|
                (dealloc.saturating_sub(alloc.timestamp_alloc)) / 1_000_000
            ),
            "current_age_ms": if alloc.timestamp_dealloc.is_none() {
                let current_time = std::time::SystemTime::now()
                    .duration_since(std::time::UNIX_EPOCH)
                    .unwrap_or_default()
                    .as_nanos() as u64;
                Some((current_time.saturating_sub(alloc.timestamp_alloc)) / 1_000_000)
            } else {
                None
            },
            "is_active": alloc.timestamp_dealloc.is_none()
        })
    }

    /// Extract scope information from variable name and current scope context
    fn extract_scope_from_var_name(var_name: &str) -> String {
        // First, try to get the current scope from the scope tracker
        if let Some(current_scope) = Self::get_current_scope_name() {
            return current_scope;
        }

        // Fallback: Try to extract scope from variable name patterns
        if var_name.contains("::") {
            if let Some(scope_part) = var_name.split("::").next() {
                return scope_part.to_string();
            }
        }

        // Check for common scope patterns
        if var_name.starts_with("main_") {
            "main_function".to_string()
        } else if var_name.starts_with("test_") {
            "test_function".to_string()
        } else if var_name.starts_with("fn_") {
            "user_function".to_string()
        } else if var_name.contains("_vec")
            || var_name.contains("_string")
            || var_name.contains("_data")
            || var_name.starts_with("boxed_")
            || var_name.starts_with("rc_")
            || var_name.starts_with("arc_")
        {
            "user_scope".to_string()
        } else {
            // For user variables, default to user_scope instead of global
            "user_scope".to_string()
        }
    }

    /// Get the current scope name from the scope tracker or infer from call stack
    fn get_current_scope_name() -> Option<String> {
        // First try to get from scope tracker
        if let Some(scope_name) = Self::get_scope_from_tracker() {
            return Some(scope_name);
        }

        // Fallback: Try to infer scope from call stack
        Self::infer_scope_from_call_stack()
    }

    /// Get scope from the scope tracker
    fn get_scope_from_tracker() -> Option<String> {
        use crate::core::scope_tracker::get_global_scope_tracker;

        let scope_tracker = get_global_scope_tracker();
        let thread_id = format!("{:?}", std::thread::current().id());

        if let Some(thread_stack) = scope_tracker
            .scope_stack
            .read()
            .ok()
            .and_then(|s| s.get(&thread_id).cloned())
        {
            if let Some(current_scope_id) = thread_stack.last() {
                if let Some(scope_info) = scope_tracker
                    .active_scopes
                    .read()
                    .ok()
                    .and_then(|s| s.get(current_scope_id).cloned())
                {
                    return Some(scope_info.name);
                }
            }
        }

        None
    }

    /// Infer scope from call stack information
    fn infer_scope_from_call_stack() -> Option<String> {
        // Try to get function name from backtrace
        let backtrace = std::backtrace::Backtrace::capture();
        let backtrace_str = format!("{backtrace:?}");

        // Look for function names in the backtrace
        for line in backtrace_str.lines() {
            if line.contains("::main") {
                return Some("main_function".to_string());
            }
            if line.contains("test_") || line.contains("tests::") {
                return Some("test_function".to_string());
            }
            // Look for user-defined function patterns
            if let Some(func_name) = Self::extract_function_name_from_backtrace(line) {
                return Some(format!("function_{func_name}"));
            }
        }

        // If we can't determine the scope, use a more descriptive default
        Some("user_code_scope".to_string())
    }

    /// Extract function name from backtrace line
    fn extract_function_name_from_backtrace(line: &str) -> Option<String> {
        // Try to extract function names from common patterns
        if let Some(start) = line.find("::") {
            if let Some(end) = line[start + 2..].find("::") {
                let func_name = &line[start + 2..start + 2 + end];
                // Filter out common system functions
                if !func_name.starts_with("_")
                    && !func_name.contains("alloc")
                    && !func_name.contains("std")
                    && !func_name.contains("core")
                    && func_name.len() > 2
                {
                    return Some(func_name.to_string());
                }
            }
        }
        None
    }

    /// Categorize system allocations for better understanding
    fn categorize_system_allocation(
        alloc: &crate::capture::types::allocation::AllocationInfo,
    ) -> String {
        match alloc.size {
            1..=16 => "small_system_alloc",
            17..=64 => "medium_system_alloc",
            65..=1024 => "large_system_alloc",
            1025..=65536 => "buffer_allocation",
            _ => "huge_allocation",
        }
        .to_string()
    }

    /// Group allocations by scope for better organization
    fn group_by_scope(
        active: &[serde_json::Value],
        history: &[serde_json::Value],
    ) -> serde_json::Value {
        let mut scopes: HashMap<String, Vec<&serde_json::Value>> = HashMap::new();

        // Group active allocations
        for alloc in active {
            if let Some(scope) = alloc["scope_name"].as_str() {
                scopes.entry(scope.to_string()).or_default().push(alloc);
            }
        }

        // Group history allocations
        for alloc in history {
            if let Some(scope) = alloc["scope_name"].as_str() {
                scopes.entry(scope.to_string()).or_default().push(alloc);
            }
        }

        let scope_summary: HashMap<String, serde_json::Value> = scopes
            .into_iter()
            .map(|(scope_name, allocations)| {
                let total_size: u64 = allocations
                    .iter()
                    .map(|a| a["size"].as_u64().unwrap_or(0))
                    .sum();

                (
                    scope_name.clone(),
                    serde_json::json!({
                        "scope_name": scope_name,
                        "allocation_count": allocations.len(),
                        "total_size_bytes": total_size,
                        "allocations": allocations
                    }),
                )
            })
            .collect();

        serde_json::json!(scope_summary)
    }

    /// Get scope summary from registry
    fn get_scope_summary(registry: &HashMap<usize, VariableInfo>) -> serde_json::Value {
        let mut scope_counts: HashMap<String, usize> = HashMap::new();

        for var_info in registry.values() {
            let scope = Self::extract_scope_from_var_name(&var_info.var_name);
            *scope_counts.entry(scope).or_insert(0) += 1;
        }

        serde_json::json!(scope_counts)
    }

    /// Analyze lifecycle statistics for lifetime_ms patterns
    fn analyze_lifecycle_statistics(
        user_active: &[serde_json::Value],
        user_history: &[serde_json::Value],
        system_active: &[serde_json::Value],
        system_history: &[serde_json::Value],
    ) -> serde_json::Value {
        // Combine all allocations for analysis
        let all_user: Vec<&serde_json::Value> =
            user_active.iter().chain(user_history.iter()).collect();
        let all_system: Vec<&serde_json::Value> =
            system_active.iter().chain(system_history.iter()).collect();

        // Analyze user allocations - now all should have lifetime_ms values
        let user_lifetimes: Vec<u64> = all_user
            .iter()
            .filter_map(|a| a["lifetime_ms"].as_u64())
            .collect();

        let user_active_count = all_user
            .iter()
            .filter(|a| a["is_active"].as_bool().unwrap_or(false))
            .count();

        let user_deallocated_count = all_user
            .iter()
            .filter(|a| !a["timestamp_dealloc"].is_null())
            .count();

        // Analyze system allocations - now all should have lifetime_ms values
        let system_lifetimes: Vec<u64> = all_system
            .iter()
            .filter_map(|a| a["lifetime_ms"].as_u64())
            .collect();

        let system_active_count = all_system
            .iter()
            .filter(|a| a["is_active"].as_bool().unwrap_or(false))
            .count();

        let system_deallocated_count = all_system
            .iter()
            .filter(|a| !a["timestamp_dealloc"].is_null())
            .count();

        serde_json::json!({
            "user_allocations": {
                "total_count": all_user.len(),
                "active_count": user_active_count,
                "deallocated_count": user_deallocated_count,
                "leaked_count": user_active_count, // active = potentially leaked
                "lifetime_stats": Self::calculate_lifetime_stats(&user_lifetimes),
                "average_lifetime_ms": if !user_lifetimes.is_empty() {
                    user_lifetimes.iter().sum::<u64>() / user_lifetimes.len() as u64
                } else { 0 },
                "max_lifetime_ms": user_lifetimes.iter().max().copied().unwrap_or(0),
                "min_lifetime_ms": user_lifetimes.iter().min().copied().unwrap_or(0)
            },
            "system_allocations": {
                "total_count": all_system.len(),
                "active_count": system_active_count,
                "deallocated_count": system_deallocated_count,
                "leaked_count": system_active_count,
                "lifetime_stats": Self::calculate_lifetime_stats(&system_lifetimes),
                "average_lifetime_ms": if !system_lifetimes.is_empty() {
                    system_lifetimes.iter().sum::<u64>() / system_lifetimes.len() as u64
                } else { 0 },
                "max_lifetime_ms": system_lifetimes.iter().max().copied().unwrap_or(0),
                "min_lifetime_ms": system_lifetimes.iter().min().copied().unwrap_or(0)
            },
            "comparison": {
                "user_vs_system_active_ratio": if system_active_count > 0 {
                    user_active_count as f64 / system_active_count as f64
                } else { 0.0 },
                "user_vs_system_lifetime_ratio": if !system_lifetimes.is_empty() && !user_lifetimes.is_empty() {
                    (user_lifetimes.iter().sum::<u64>() / user_lifetimes.len() as u64) as f64 /
                    (system_lifetimes.iter().sum::<u64>() / system_lifetimes.len() as u64) as f64
                } else { 0.0 }
            }
        })
    }

    /// Analyze deallocation patterns for timestamp_dealloc
    fn analyze_deallocation_patterns(
        user_active: &[serde_json::Value],
        user_history: &[serde_json::Value],
        system_active: &[serde_json::Value],
        system_history: &[serde_json::Value],
    ) -> serde_json::Value {
        let all_user: Vec<&serde_json::Value> =
            user_active.iter().chain(user_history.iter()).collect();
        let all_system: Vec<&serde_json::Value> =
            system_active.iter().chain(system_history.iter()).collect();

        // Analyze deallocation timestamps
        let user_dealloc_times: Vec<u64> = all_user
            .iter()
            .filter_map(|a| a["timestamp_dealloc"].as_u64())
            .collect();

        let system_dealloc_times: Vec<u64> = all_system
            .iter()
            .filter_map(|a| a["timestamp_dealloc"].as_u64())
            .collect();

        // Count null deallocations (active/leaked allocations)
        let user_null_dealloc = all_user
            .iter()
            .filter(|a| a["timestamp_dealloc"].is_null())
            .count();

        let system_null_dealloc = all_system
            .iter()
            .filter(|a| a["timestamp_dealloc"].is_null())
            .count();

        serde_json::json!({
            "user_deallocations": {
                "total_deallocated": user_dealloc_times.len(),
                "still_active": user_null_dealloc,
                "deallocation_rate": if !all_user.is_empty() {
                    user_dealloc_times.len() as f64 / all_user.len() as f64 * 100.0
                } else { 0.0 },
                "earliest_dealloc": user_dealloc_times.iter().min().copied(),
                "latest_dealloc": user_dealloc_times.iter().max().copied(),
                "deallocation_timespan_ms": if user_dealloc_times.len() > 1 {
                    user_dealloc_times.iter().max().unwrap_or(&0) -
                    user_dealloc_times.iter().min().unwrap_or(&0)
                } else { 0 }
            },
            "system_deallocations": {
                "total_deallocated": system_dealloc_times.len(),
                "still_active": system_null_dealloc,
                "deallocation_rate": if !all_system.is_empty() {
                    system_dealloc_times.len() as f64 / all_system.len() as f64 * 100.0
                } else { 0.0 },
                "earliest_dealloc": system_dealloc_times.iter().min().copied(),
                "latest_dealloc": system_dealloc_times.iter().max().copied(),
                "deallocation_timespan_ms": if system_dealloc_times.len() > 1 {
                    system_dealloc_times.iter().max().unwrap_or(&0) -
                    system_dealloc_times.iter().min().unwrap_or(&0)
                } else { 0 }
            },
            "memory_leak_analysis": {
                "user_potential_leaks": user_null_dealloc,
                "system_potential_leaks": system_null_dealloc,
                "total_potential_leaks": user_null_dealloc + system_null_dealloc,
                "user_leak_percentage": if !all_user.is_empty() {
                    user_null_dealloc as f64 / all_user.len() as f64 * 100.0
                } else { 0.0 },
                "system_leak_percentage": if !all_system.is_empty() {
                    system_null_dealloc as f64 / all_system.len() as f64 * 100.0
                } else { 0.0 }
            }
        })
    }

    /// Calculate detailed lifetime statistics
    fn calculate_lifetime_stats(lifetimes: &[u64]) -> serde_json::Value {
        if lifetimes.is_empty() {
            return serde_json::json!({
                "count": 0,
                "categories": {
                    "very_short": 0,    // < 1ms
                    "short": 0,         // 1-10ms
                    "medium": 0,        // 10-100ms
                    "long": 0,          // 100-1000ms
                    "very_long": 0      // > 1000ms
                }
            });
        }

        let mut very_short = 0;
        let mut short = 0;
        let mut medium = 0;
        let mut long = 0;
        let mut very_long = 0;

        for &lifetime in lifetimes {
            match lifetime {
                0..=1 => very_short += 1,
                2..=10 => short += 1,
                11..=100 => medium += 1,
                101..=1000 => long += 1,
                _ => very_long += 1,
            }
        }

        serde_json::json!({
            "count": lifetimes.len(),
            "categories": {
                "very_short": very_short,
                "short": short,
                "medium": medium,
                "long": long,
                "very_long": very_long
            },
            "percentiles": {
                "p50": Self::calculate_percentile(lifetimes, 50.0),
                "p90": Self::calculate_percentile(lifetimes, 90.0),
                "p95": Self::calculate_percentile(lifetimes, 95.0),
                "p99": Self::calculate_percentile(lifetimes, 99.0)
            }
        })
    }

    /// Calculate percentile for lifetime analysis
    fn calculate_percentile(sorted_values: &[u64], percentile: f64) -> u64 {
        if sorted_values.is_empty() {
            return 0;
        }

        let mut values = sorted_values.to_vec();
        values.sort_unstable();

        let index = (percentile / 100.0 * (values.len() - 1) as f64) as usize;
        values[index.min(values.len() - 1)]
    }

    /// Smart inference with caching for better performance
    pub fn infer_allocation_info_cached(
        alloc: &crate::capture::types::allocation::AllocationInfo,
    ) -> (String, String) {
        // Use a simple cache for common sizes to avoid repeated string formatting
        static COMMON_TYPES: &[(usize, &str, &str)] = &[
            (1, "box_u8", "Box<u8>"),
            (2, "box_u16", "Box<u16>"),
            (4, "box_u32", "Box<u32>"),
            (8, "box_u64", "Box<u64>"),
            (16, "small_alloc_16b", "SmallAlloc"),
            (24, "string_alloc", "String"),
            (32, "string_alloc", "String"),
        ];

        // Fast lookup for common sizes
        for &(size, var_prefix, type_name) in COMMON_TYPES {
            if alloc.size == size {
                return (
                    format!("{var_prefix}_{:x}", alloc.ptr),
                    type_name.to_string(),
                );
            }
        }

        // Fallback to original logic for uncommon sizes
        Self::infer_allocation_info(alloc)
    }

    /// Smart inference for system allocations based on size patterns and common allocations
    pub fn infer_allocation_info(
        alloc: &crate::capture::types::allocation::AllocationInfo,
    ) -> (String, String) {
        let size = alloc.size;

        // Common allocation size patterns for type inference
        let (var_name, type_name) = match size {
            // String allocations (common sizes)
            8..=32 if size.is_power_of_two() => (
                format!("string_alloc_{:x}", alloc.ptr),
                "String".to_string(),
            ),
            // Vec allocations (multiples of common element sizes)
            s if s % 8 == 0 && s >= 16 => {
                let elements = s / 8;
                (
                    format!("vec_i64_{elements}elem_{:x}", alloc.ptr),
                    "Vec<i64>".to_string(),
                )
            }
            s if s % 4 == 0 && s >= 8 => {
                let elements = s / 4;
                (
                    format!("vec_i32_{elements}elem_{:x}", alloc.ptr),
                    "Vec<i32>".to_string(),
                )
            }
            // Box allocations (single element sizes)
            1 => (format!("box_u8_{:x}", alloc.ptr), "Box<u8>".to_string()),
            2 => (format!("box_u16_{:x}", alloc.ptr), "Box<u16>".to_string()),
            4 => (format!("box_u32_{:x}", alloc.ptr), "Box<u32>".to_string()),
            8 => (format!("box_u64_{:x}", alloc.ptr), "Box<u64>".to_string()),
            // HashMap/BTreeMap allocations (typically larger, irregular sizes)
            s if s >= 64 && s % 16 == 0 => (
                format!("hashmap_alloc_{:x}", alloc.ptr),
                "HashMap<K,V>".to_string(),
            ),
            // Large allocations (likely buffers or large collections)
            s if s >= 1024 => {
                let kb = s / 1024;
                (
                    format!("large_buffer_{}kb_{:x}", kb, alloc.ptr),
                    "LargeBuffer".to_string(),
                )
            }
            // Small system allocations
            s if s <= 16 => (
                format!("small_alloc_{s}b_{:x}", alloc.ptr),
                "SmallAlloc".to_string(),
            ),
            // Default case with size hint
            _ => (
                format!("system_alloc_{size}b_{:x}", alloc.ptr),
                "SystemAlloc".to_string(),
            ),
        };

        (var_name, type_name)
    }

    /// Generate comprehensive export data with clear separation of system vs user allocations
    pub fn generate_comprehensive_export(
        tracker: &crate::core::tracker::MemoryTracker,
    ) -> MemScopeResult<serde_json::Value> {
        let start_time = std::time::Instant::now();
        tracing::info!(
            "🔄 Starting comprehensive export generation with allocation classification..."
        );

        // Get tracker data
        let active_allocations = tracker.get_active_allocations().map_err(|e| {
            MemScopeError::error(
                "variable_registry",
                "generate_comprehensive_export",
                e.to_string(),
            )
        })?;
        let allocation_history = tracker.get_active_allocations().map_err(|e| {
            MemScopeError::error(
                "variable_registry",
                "generate_comprehensive_export",
                e.to_string(),
            )
        })?;
        let memory_by_type = tracker.get_memory_by_type().map_err(|e| {
            MemScopeError::error(
                "variable_registry",
                "generate_comprehensive_export",
                e.to_string(),
            )
        })?;
        let stats = tracker.get_stats().map_err(|e| {
            MemScopeError::error(
                "variable_registry",
                "generate_comprehensive_export",
                e.to_string(),
            )
        })?;
        let registry = Self::get_all_variables();

        tracing::info!(
            "📊 Data loaded: {} active, {} history, {} registry entries",
            active_allocations.len(),
            allocation_history.len(),
            registry.len()
        );

        // Filter out very small allocations to reduce processing overhead
        let filtered_active: Vec<_> = if active_allocations.len() > 10000 {
            active_allocations
                .into_iter()
                .filter(|alloc| alloc.size >= 8)
                .collect()
        } else {
            active_allocations
        };

        let filtered_history: Vec<_> = if allocation_history.len() > 50000 {
            allocation_history
                .into_iter()
                .filter(|alloc| alloc.size >= 8)
                .collect()
        } else {
            allocation_history
        };

        // Convert to new system allocation types
        let filtered_active: Vec<crate::capture::types::AllocationInfo> = filtered_active
            .into_iter()
            .map(|a: crate::capture::backends::core_types::AllocationInfo| a.into())
            .collect();
        let filtered_history: Vec<crate::capture::types::AllocationInfo> = filtered_history
            .into_iter()
            .map(|a: crate::capture::backends::core_types::AllocationInfo| a.into())
            .collect();

        // Classify and enhance allocations in parallel
        let (classified_active, classified_history) = rayon::join(
            || Self::classify_and_enhance_allocations(&filtered_active, &registry),
            || Self::classify_and_enhance_allocations(&filtered_history, &registry),
        );

        // Separate user and system allocations
        let (user_active, system_active): (Vec<_>, Vec<_>) = classified_active
            .into_iter()
            .partition(|alloc| alloc["allocation_source"] == "user");

        let (user_history, system_history): (Vec<_>, Vec<_>) = classified_history
            .into_iter()
            .partition(|alloc| alloc["allocation_source"] == "user");

        // Group user variables by scope
        let user_scopes = Self::group_by_scope(&user_active, &user_history);

        // Build comprehensive result with clear separation
        let comprehensive_data = serde_json::json!({
            "memory_analysis": {
                "user_allocations": {
                    "active": user_active,
                    "history": user_history,
                    "by_scope": user_scopes,
                    "total_count": user_active.len() + user_history.len()
                },
                "system_allocations": {
                    "active": system_active,
                    "history": system_history,
                    "total_count": system_active.len() + system_history.len()
                },
                "memory_by_type": memory_by_type,
                "statistics": {
                    "overall": stats,
                    "user_vs_system": {
                        "user_active_count": user_active.len(),
                        "system_active_count": system_active.len(),
                        "user_total_size": user_active.iter()
                            .map(|a| a["size"].as_u64().unwrap_or(0))
                            .sum::<u64>(),
                        "system_total_size": system_active.iter()
                            .map(|a| a["size"].as_u64().unwrap_or(0))
                            .sum::<u64>()
                    },
                    "lifecycle_analysis": Self::analyze_lifecycle_statistics(&user_active, &user_history, &system_active, &system_history),
                    "deallocation_analysis": Self::analyze_deallocation_patterns(&user_active, &user_history, &system_active, &system_history)
                }
            },
            "variable_registry": {
                "total_variables": registry.len(),
                "user_variables": registry.values().collect::<Vec<_>>(),
                "scope_summary": Self::get_scope_summary(&registry)
            },
            "export_metadata": {
                "timestamp": std::time::SystemTime::now()
                    .duration_since(std::time::UNIX_EPOCH)
                    .unwrap_or_default()
                    .as_secs(),
                "total_allocations": user_active.len() + user_history.len() + system_active.len() + system_history.len(),
                "processing_time_ms": start_time.elapsed().as_millis(),
                "classification_features": [
                    "user_vs_system_separation",
                    "scope_based_grouping",
                    "allocation_source_tracking",
                    "enhanced_type_inference"
                ]
            }
        });

        let total_time = start_time.elapsed();
        tracing::info!(
            "✅ Export completed in {:?} - User: {}, System: {}",
            total_time,
            user_active.len() + user_history.len(),
            system_active.len() + system_history.len()
        );

        Ok(comprehensive_data)
    }

    /// Clear all variable registrations
    pub fn clear_registry() -> MemScopeResult<()> {
        if let Ok(mut registry) = get_global_registry().try_lock() {
            registry.clear();
        }
        Ok(())
    }

    /// Get registry statistics
    pub fn get_stats() -> (usize, usize) {
        if let Ok(registry) = get_global_registry().try_lock() {
            let total = registry.len();
            let recent = registry
                .values()
                .filter(|v| {
                    let now = std::time::SystemTime::now()
                        .duration_since(std::time::UNIX_EPOCH)
                        .unwrap_or_default()
                        .as_nanos() as u64;
                    now - v.timestamp < 1_000_000_000 // Last 1 second
                })
                .count();
            (total, recent)
        } else {
            (0, 0)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::core::types::AllocationInfo;

    fn create_test_allocation(
        ptr: usize,
        size: usize,
        var_name: Option<String>,
        type_name: Option<String>,
    ) -> AllocationInfo {
        AllocationInfo {
            ptr,
            size,
            var_name,
            type_name,
            scope_name: Some("test_scope".to_string()),
            timestamp_alloc: 1000000,
            timestamp_dealloc: Some(2000000),
            thread_id: "test_thread".to_string(),
            borrow_count: 0,
            stack_trace: Some(vec!["test_function".to_string()]),
            is_leaked: false,
            lifetime_ms: Some(1000),
            borrow_info: None,
            clone_info: None,
            ownership_history_available: false,
            smart_pointer_info: None,
            memory_layout: None,
            generic_info: None,
            dynamic_type_info: None,
            runtime_state: None,
            stack_allocation: None,
            temporary_object: None,
            fragmentation_analysis: None,
            generic_instantiation: None,
            type_relationships: None,
            type_usage: None,
            function_call_tracking: None,
            lifecycle_tracking: None,
            access_tracking: None,
            drop_chain_analysis: None,
        }
    }

    #[test]
    fn test_variable_registry_register_and_get() {
        // Clear registry to avoid interference from other tests
        let _ = VariableRegistry::clear_registry();

        let address = 0x10000; // Use unique address range
        let var_name = "test_var".to_string();
        let type_name = "String".to_string();
        let size = 24;

        // Register variable
        let result =
            VariableRegistry::register_variable(address, var_name.clone(), type_name.clone(), size);
        assert!(result.is_ok());

        // Get variable info
        let var_info = VariableRegistry::get_variable_info(address);
        assert!(var_info.is_some());

        let info = var_info.unwrap();
        assert_eq!(info.var_name, var_name);
        assert_eq!(info.type_name, type_name);
        assert_eq!(info.size, size);
        assert!(info.timestamp > 0);
        assert!(info.thread_id > 0);
        assert_eq!(info.memory_usage, size as u64);
    }

    #[test]
    fn test_variable_registry_mark_destroyed() {
        let address = 0x2000;
        let destruction_time = 5000000;

        let result = VariableRegistry::mark_variable_destroyed(address, destruction_time);
        assert!(result.is_ok());
    }

    #[test]
    fn test_get_all_variables() {
        // Clear registry to avoid interference from other tests
        let _ = VariableRegistry::clear_registry();

        let address1 = 0x30000; // Use unique address range
        let address2 = 0x40000;

        let result1 =
            VariableRegistry::register_variable(address1, "var1".to_string(), "i32".to_string(), 4);
        let result2 = VariableRegistry::register_variable(
            address2,
            "var2".to_string(),
            "String".to_string(),
            24,
        );

        // Ensure registrations were successful
        assert!(result1.is_ok());
        assert!(result2.is_ok());

        let all_vars = VariableRegistry::get_all_variables();
        // Check that we can get variables and at least one of the ones we added exists
        // Use a more robust check that accounts for potential registry state
        assert!(
            all_vars.contains_key(&address1) || all_vars.contains_key(&address2) || !all_vars.is_empty(),
            "Registry should contain at least one variable or the ones we just added. Registry size: {}", 
            all_vars.len()
        );
    }

    #[test]
    fn test_enhance_allocations_with_registry() {
        // Test focuses on the core functionality: classification of allocations
        // We test three scenarios:
        // 1. Allocation with explicit var_name/type_name (should always be "user")
        // 2. Allocation without any info (should always be "system")
        // 3. Registry lookup (may fail in concurrent tests, so we make it optional)

        // First, test allocations with explicit info - these should always work
        let explicit_alloc = create_test_allocation(
            0x60000,
            50,
            Some("explicit_var".to_string()),
            Some("i64".to_string()),
        );

        // System allocation without any info
        let system_alloc = create_test_allocation(0x70000, 200, None, None);

        let allocations = vec![explicit_alloc, system_alloc];
        let enhanced = VariableRegistry::enhance_allocations_with_registry(&allocations);

        assert_eq!(enhanced.len(), 2);

        // Check that we have one user and one system allocation
        let user_count = enhanced
            .iter()
            .filter(|a| a["allocation_source"] == "user")
            .count();
        let system_count = enhanced
            .iter()
            .filter(|a| a["allocation_source"] == "system")
            .count();

        assert_eq!(user_count, 1, "Should have exactly one user allocation");
        assert_eq!(system_count, 1, "Should have exactly one system allocation");

        // Find and verify the explicit allocation (should always be "user")
        let explicit_result = enhanced
            .iter()
            .find(|a| a["ptr"].as_u64().unwrap() as usize == 0x60000)
            .expect("Should find explicit allocation");

        assert_eq!(explicit_result["allocation_source"], "user");
        assert_eq!(explicit_result["variable_name"], "explicit_var");
        assert_eq!(explicit_result["type_name"], "i64");
        assert_eq!(explicit_result["tracking_method"], "explicit_tracking");

        // Find and verify the system allocation
        let system_result = enhanced
            .iter()
            .find(|a| a["ptr"].as_u64().unwrap() as usize == 0x70000)
            .expect("Should find system allocation");

        assert_eq!(system_result["allocation_source"], "system");
        assert_eq!(system_result["tracking_method"], "automatic_inference");
        // System allocations should have inferred names
        assert!(!system_result["variable_name"].as_str().unwrap().is_empty());
        assert!(!system_result["type_name"].as_str().unwrap().is_empty());

        // Optional: Test registry functionality if we can get the lock
        // This part may fail in concurrent tests, so we make it non-critical
        let test_addr = 0x50000;
        if VariableRegistry::clear_registry().is_ok()
            && VariableRegistry::register_variable(
                test_addr,
                "tracked_var".to_string(),
                "Vec<u8>".to_string(),
                100,
            )
            .is_ok()
        {
            // Only test registry lookup if registration succeeded
            let registry_alloc = create_test_allocation(test_addr, 100, None, None);
            let enhanced_with_registry =
                VariableRegistry::enhance_allocations_with_registry(&[registry_alloc]);

            if enhanced_with_registry.len() == 1 {
                let result = &enhanced_with_registry[0];
                // If registry lookup worked, it should be classified as "user"
                if result["allocation_source"] == "user" {
                    assert_eq!(result["variable_name"], "tracked_var");
                    assert_eq!(result["type_name"], "Vec<u8>");
                    assert_eq!(result["tracking_method"], "track_var_macro");
                }
                // If registry lookup failed (concurrent test), it should be "system"
                // This is also acceptable in concurrent testing
            }
        }
    }

    #[test]
    fn test_extract_scope_from_var_name() {
        // Clear registry to avoid interference from other tests
        let _ = VariableRegistry::clear_registry();

        // Test scope extraction - the function prioritizes scope tracker over pattern matching
        // In test environment, it typically returns "user_code_scope" from backtrace inference
        let result1 = VariableRegistry::extract_scope_from_var_name("scope::variable");
        // The function should return a valid scope name
        assert!(!result1.is_empty(), "Scope name should not be empty");
        assert!(
            result1 == "scope"
                || result1 == "user_code_scope"
                || result1 == "user_scope"
                || result1.starts_with("function_")
                || result1 == "main_function"
                || result1 == "test_function",
            "Expected a valid scope name, but got: '{result1}'"
        );

        let result2 = VariableRegistry::extract_scope_from_var_name("my_vec");
        assert!(!result2.is_empty(), "Scope name should not be empty");
        assert!(
            result2 == "user_scope"
                || result2 == "user_code_scope"
                || result2.starts_with("function_")
                || result2 == "main_function"
                || result2 == "test_function",
            "Expected a valid scope name, but got: '{result2}'"
        );

        let result3 = VariableRegistry::extract_scope_from_var_name("main_variable");
        assert!(!result3.is_empty(), "Scope name should not be empty");
        assert!(
            result3 == "main_function"
                || result3 == "user_code_scope"
                || result3 == "user_scope"
                || result3.starts_with("function_")
                || result3 == "test_function",
            "Expected a valid scope name, but got: '{result3}'"
        );

        let result4 = VariableRegistry::extract_scope_from_var_name("test_variable");
        assert!(!result4.is_empty(), "Scope name should not be empty");
        assert!(
            result4 == "test_function"
                || result4 == "user_code_scope"
                || result4 == "user_scope"
                || result4.starts_with("function_")
                || result4 == "main_function",
            "Expected a valid scope name, but got: '{result4}'"
        );
    }

    #[test]
    fn test_calculate_lifetime_stats() {
        let lifetimes = vec![0, 1, 5, 15, 50, 150, 500, 1500];
        let stats = VariableRegistry::calculate_lifetime_stats(&lifetimes);

        assert_eq!(stats["count"], 8);
        assert_eq!(stats["categories"]["very_short"], 2); // 0, 1
        assert_eq!(stats["categories"]["short"], 1); // 5
        assert_eq!(stats["categories"]["medium"], 2); // 15, 50
        assert_eq!(stats["categories"]["long"], 2); // 150, 500
        assert_eq!(stats["categories"]["very_long"], 1); // 1500

        let empty_lifetimes: Vec<u64> = vec![];
        let empty_stats = VariableRegistry::calculate_lifetime_stats(&empty_lifetimes);
        assert_eq!(empty_stats["count"], 0);
    }

    #[test]
    fn test_group_by_scope() {
        let active_allocations = vec![
            serde_json::json!({
                "scope_name": "main_function",
                "size": 100,
                "ptr": 0x1000
            }),
            serde_json::json!({
                "scope_name": "test_function",
                "size": 200,
                "ptr": 0x2000
            }),
        ];

        let history_allocations = vec![serde_json::json!({
            "scope_name": "main_function",
            "size": 150,
            "ptr": 0x3000
        })];

        let grouped = VariableRegistry::group_by_scope(&active_allocations, &history_allocations);

        assert!(
            grouped["main_function"]["allocation_count"]
                .as_u64()
                .unwrap()
                >= 2
        );
        assert!(
            grouped["test_function"]["allocation_count"]
                .as_u64()
                .unwrap()
                >= 1
        );
        assert!(
            grouped["main_function"]["total_size_bytes"]
                .as_u64()
                .unwrap()
                >= 250
        );
    }

    #[test]
    fn test_get_scope_summary() {
        let mut registry = HashMap::new();
        registry.insert(
            0x1000,
            VariableInfo {
                var_name: "main_var".to_string(),
                type_name: "i32".to_string(),
                timestamp: 1000,
                size: 4,
                thread_id: 1,
                memory_usage: 4,
            },
        );
        registry.insert(
            0x2000,
            VariableInfo {
                var_name: "test_var".to_string(),
                type_name: "String".to_string(),
                timestamp: 2000,
                size: 24,
                thread_id: 2,
                memory_usage: 24,
            },
        );

        let summary = VariableRegistry::get_scope_summary(&registry);
        // The function may return "user_code_scope" for most variables
        if let Some(obj) = summary.as_object() {
            let total_count: u64 = obj.values().map(|v| v.as_u64().unwrap_or(0)).sum();
            assert!(total_count >= 2); // At least our 2 variables should be counted

            // Check if specific scopes exist or if they're grouped under user_code_scope
            let has_main = obj
                .get("main_function")
                .and_then(|v| v.as_u64())
                .unwrap_or(0)
                >= 1;
            let has_test = obj
                .get("test_function")
                .and_then(|v| v.as_u64())
                .unwrap_or(0)
                >= 1;
            let has_user_code = obj
                .get("user_code_scope")
                .and_then(|v| v.as_u64())
                .unwrap_or(0)
                >= 1;

            assert!(has_main || has_test || has_user_code);
        } else {
            panic!("Expected summary to be a JSON object");
        }
    }

    #[test]
    fn test_variable_info_creation() {
        let info = VariableInfo {
            var_name: "test_var".to_string(),
            type_name: "Vec<u8>".to_string(),
            timestamp: 1234567890,
            size: 1024,
            thread_id: 1,
            memory_usage: 1024,
        };

        assert_eq!(info.var_name, "test_var");
        assert_eq!(info.type_name, "Vec<u8>");
        assert_eq!(info.timestamp, 1234567890);
        assert_eq!(info.size, 1024);
        assert_eq!(info.thread_id, 1);
        assert_eq!(info.memory_usage, 1024);
    }

    #[test]
    fn test_variable_info_debug() {
        let info = VariableInfo {
            var_name: "x".to_string(),
            type_name: "i32".to_string(),
            timestamp: 0,
            size: 4,
            thread_id: 0,
            memory_usage: 4,
        };

        let debug_str = format!("{:?}", info);
        assert!(debug_str.contains("VariableInfo"));
        assert!(debug_str.contains("var_name"));
    }

    #[test]
    fn test_variable_info_clone() {
        let info = VariableInfo {
            var_name: "original".to_string(),
            type_name: "String".to_string(),
            timestamp: 100,
            size: 24,
            thread_id: 1,
            memory_usage: 24,
        };

        let cloned = info.clone();
        assert_eq!(cloned.var_name, info.var_name);
        assert_eq!(cloned.type_name, info.type_name);
    }

    #[test]
    fn test_get_all_variables_empty() {
        let _ = VariableRegistry::clear_registry();
        let vars = VariableRegistry::get_all_variables();
        // May have entries from other tests
        let _ = vars;
    }

    #[test]
    fn test_register_multiple_variables() {
        let _ = VariableRegistry::clear_registry();

        let result1 =
            VariableRegistry::register_variable(0x10001, "a".to_string(), "i32".to_string(), 4);
        let result2 =
            VariableRegistry::register_variable(0x10002, "b".to_string(), "i64".to_string(), 8);
        let result3 =
            VariableRegistry::register_variable(0x10003, "c".to_string(), "String".to_string(), 24);

        assert!(result1.is_ok());
        assert!(result2.is_ok());
        assert!(result3.is_ok());
    }

    #[test]
    fn test_get_variable_info_not_found() {
        let _ = VariableRegistry::clear_registry();
        let info = VariableRegistry::get_variable_info(0xDEADBEEF);
        assert!(info.is_none());
    }

    #[test]
    fn test_lifetime_stats_categories() {
        let lifetimes = vec![0, 1, 2, 10, 20, 100, 200, 1000, 2000];
        let stats = VariableRegistry::calculate_lifetime_stats(&lifetimes);

        assert_eq!(stats["count"], 9);
        // Verify the sum of all categories equals total count
        let very_short = stats["categories"]["very_short"].as_u64().unwrap();
        let short = stats["categories"]["short"].as_u64().unwrap();
        let medium = stats["categories"]["medium"].as_u64().unwrap();
        let long = stats["categories"]["long"].as_u64().unwrap();
        let very_long = stats["categories"]["very_long"].as_u64().unwrap();

        let total = very_short + short + medium + long + very_long;
        assert_eq!(total, 9);
    }

    #[test]
    fn test_lifetime_stats_single_value() {
        let lifetimes = vec![50];
        let stats = VariableRegistry::calculate_lifetime_stats(&lifetimes);

        assert_eq!(stats["count"], 1);
        assert_eq!(stats["categories"]["medium"], 1);
    }

    #[test]
    fn test_enhance_allocations_mixed() {
        let _ = VariableRegistry::clear_registry();

        let alloc1 = create_test_allocation(
            0x80001,
            100,
            Some("user_var".to_string()),
            Some("Vec<u8>".to_string()),
        );
        let alloc2 = create_test_allocation(0x80002, 200, None, None);
        let alloc3 = create_test_allocation(
            0x80003,
            300,
            Some("another".to_string()),
            Some("String".to_string()),
        );

        let allocations = vec![alloc1, alloc2, alloc3];
        let enhanced = VariableRegistry::enhance_allocations_with_registry(&allocations);

        assert_eq!(enhanced.len(), 3);

        let user_count = enhanced
            .iter()
            .filter(|a| a["allocation_source"] == "user")
            .count();
        assert_eq!(user_count, 2);
    }

    #[test]
    fn test_calculate_percentile_empty() {
        let values: Vec<u64> = vec![];
        let result = VariableRegistry::calculate_percentile(&values, 50.0);
        assert_eq!(result, 0);
    }

    #[test]
    fn test_calculate_percentile_single() {
        let values = vec![100];
        let result = VariableRegistry::calculate_percentile(&values, 50.0);
        assert_eq!(result, 100);
    }

    #[test]
    fn test_calculate_percentile_multiple() {
        let values = vec![10, 20, 30, 40, 50];
        let p50 = VariableRegistry::calculate_percentile(&values, 50.0);
        let p90 = VariableRegistry::calculate_percentile(&values, 90.0);

        assert!((20..=40).contains(&p50));
        assert!((40..=50).contains(&p90));
    }

    #[test]
    fn test_get_stats_basic() {
        let _ = VariableRegistry::clear_registry();
        let (total, recent) = VariableRegistry::get_stats();
        let _ = (total, recent);
    }

    #[test]
    fn test_get_stats_with_variables() {
        let _ = VariableRegistry::clear_registry();

        let _ = VariableRegistry::register_variable(
            0x99901,
            "stat_var".to_string(),
            "i32".to_string(),
            4,
        );

        let (total, _recent) = VariableRegistry::get_stats();
        assert!(total <= 1);
    }

    #[test]
    fn test_analyze_lifecycle_statistics() {
        let user_active = vec![serde_json::json!({
            "lifetime_ms": 50,
            "is_active": true,
            "timestamp_dealloc": null
        })];

        let user_history = vec![serde_json::json!({
            "lifetime_ms": 100,
            "is_active": false,
            "timestamp_dealloc": 2000
        })];

        let system_active = vec![serde_json::json!({
            "lifetime_ms": 25,
            "is_active": true,
            "timestamp_dealloc": null
        })];

        let system_history = vec![];

        let result = VariableRegistry::analyze_lifecycle_statistics(
            &user_active,
            &user_history,
            &system_active,
            &system_history,
        );

        assert_eq!(result["user_allocations"]["total_count"], 2);
        assert_eq!(result["system_allocations"]["total_count"], 1);
        assert_eq!(result["user_allocations"]["active_count"], 1);
    }

    #[test]
    fn test_analyze_deallocation_patterns() {
        let user_active = vec![serde_json::json!({
            "timestamp_dealloc": null
        })];

        let user_history = vec![serde_json::json!({
            "timestamp_dealloc": 2000
        })];

        let system_active = vec![];
        let system_history = vec![];

        let result = VariableRegistry::analyze_deallocation_patterns(
            &user_active,
            &user_history,
            &system_active,
            &system_history,
        );

        assert_eq!(result["user_deallocations"]["total_deallocated"], 1);
        assert_eq!(result["user_deallocations"]["still_active"], 1);
    }

    #[test]
    fn test_clear_registry() {
        let _ = VariableRegistry::clear_registry();
        let result = VariableRegistry::register_variable(
            0xABC01,
            "clear_test".to_string(),
            "i32".to_string(),
            4,
        );
        assert!(result.is_ok());

        let clear_result = VariableRegistry::clear_registry();
        assert!(clear_result.is_ok());
    }

    #[test]
    fn test_mark_variable_destroyed() {
        let result = VariableRegistry::mark_variable_destroyed(0x12345, 999999);
        assert!(result.is_ok());
    }

    #[test]
    fn test_extract_function_name_from_backtrace() {
        let line = "test::module::function_name::h12345678";
        let result = VariableRegistry::extract_function_name_from_backtrace(line);
        let _ = result;
    }

    #[test]
    fn test_extract_function_name_system_filter() {
        let line = "std::alloc::alloc::h12345678";
        let result = VariableRegistry::extract_function_name_from_backtrace(line);
        assert!(result.is_none() || !result.unwrap().contains("std"));
    }

    #[test]
    fn test_extract_scope_from_var_name_main() {
        let scope = VariableRegistry::extract_scope_from_var_name("main_buffer");
        assert!(!scope.is_empty());
    }

    #[test]
    fn test_extract_scope_from_var_name_test() {
        let scope = VariableRegistry::extract_scope_from_var_name("test_data");
        assert!(!scope.is_empty());
    }

    #[test]
    fn test_extract_scope_from_var_name_fn() {
        let scope = VariableRegistry::extract_scope_from_var_name("fn_result");
        assert!(!scope.is_empty());
    }

    #[test]
    fn test_extract_scope_from_var_name_vec() {
        let scope = VariableRegistry::extract_scope_from_var_name("my_vec_data");
        assert!(!scope.is_empty());
    }

    #[test]
    fn test_extract_scope_from_var_name_string() {
        let scope = VariableRegistry::extract_scope_from_var_name("my_string_buffer");
        assert!(!scope.is_empty());
    }

    #[test]
    fn test_extract_scope_from_var_name_boxed() {
        let scope = VariableRegistry::extract_scope_from_var_name("boxed_value");
        assert!(!scope.is_empty());
    }

    #[test]
    fn test_extract_scope_from_var_name_rc() {
        let scope = VariableRegistry::extract_scope_from_var_name("rc_pointer");
        assert!(!scope.is_empty());
    }

    #[test]
    fn test_extract_scope_from_var_name_arc() {
        let scope = VariableRegistry::extract_scope_from_var_name("arc_shared");
        assert!(!scope.is_empty());
    }

    #[test]
    fn test_extract_scope_from_var_name_module() {
        let scope = VariableRegistry::extract_scope_from_var_name("mymodule::myvar");
        assert!(!scope.is_empty());
    }

    #[test]
    fn test_extract_scope_from_var_name_default() {
        let scope = VariableRegistry::extract_scope_from_var_name("simple_var");
        assert!(!scope.is_empty());
    }

    #[test]
    fn test_get_current_scope_name() {
        let scope = VariableRegistry::get_current_scope_name();
        let _ = scope;
    }

    #[test]
    fn test_get_scope_from_tracker() {
        let scope = VariableRegistry::get_scope_from_tracker();
        let _ = scope;
    }
}
