//! Process memory usage profiling

use std::fs;
use std::path::Path;

use super::super::error::ProfilingError;

/// Memory usage profile for a process
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct MemoryUsageProfile {
    pub pid: u32,
    pub rss_bytes: u64,
    pub virtual_bytes: u64,
    pub shared_bytes: u64,
    pub peak_rss_bytes: u64,
}

/// Profile memory usage of a process
pub fn profile_memory_usage(pid: u32) -> Result<MemoryUsageProfile, ProfilingError> {
    let status_path_str = format!("/proc/{}/status", pid);
    let status_path = Path::new(&status_path_str);

    if !status_path.exists() {
        return Err(ProfilingError::IoError(format!(
            "Process {} not found",
            pid
        )));
    }

    let status = fs::read_to_string(status_path)
        .map_err(|e| ProfilingError::IoError(format!("Failed to read status: {}", e)))?;

    let mut rss_bytes = 0u64;
    let mut virtual_bytes = 0u64;
    let mut shared_bytes = 0u64;
    let mut peak_rss_bytes = 0u64;

    for line in status.lines() {
        if line.starts_with("VmRSS:") {
            if let Some(value) = parse_status_value(line) {
                rss_bytes = value * 1024; // kB to bytes
            }
        } else if line.starts_with("VmSize:") {
            if let Some(value) = parse_status_value(line) {
                virtual_bytes = value * 1024;
            }
        } else if line.starts_with("VmShared:") {
            if let Some(value) = parse_status_value(line) {
                shared_bytes = value * 1024;
            }
        } else if line.starts_with("VmHWM:") {
            if let Some(value) = parse_status_value(line) {
                peak_rss_bytes = value * 1024;
            }
        }
    }

    Ok(MemoryUsageProfile {
        pid,
        rss_bytes,
        virtual_bytes,
        shared_bytes,
        peak_rss_bytes,
    })
}

fn parse_status_value(line: &str) -> Option<u64> {
    let parts: Vec<&str> = line.split_whitespace().collect();
    if parts.len() >= 2 {
        parts[1].parse().ok()
    } else {
        None
    }
}
