// SPDX-License-Identifier: GPL-3.0-only

#![allow(dead_code)]

#[derive(Debug, Clone)]
pub struct CpuSnapshot {
    pub per_core: Vec<f32>, // 0.0–100.0 per logical core
    pub aggregate: f32,
    pub frequency: Vec<u64>, // MHz per core
    /// CPU brand string, e.g. "Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz"
    pub cpu_brand: String,
    #[cfg(target_os = "linux")]
    pub temperature: Option<f32>, // degrees C
    /// Number of physical (non-hyperthreaded) cores from /proc/cpuinfo
    #[cfg(target_os = "linux")]
    pub physical_core_count: Option<u32>,
    /// Scaling governor from /sys/.../cpufreq/scaling_governor, e.g. "powersave"
    #[cfg(target_os = "linux")]
    pub governor: Option<String>,
}

impl CpuSnapshot {
    pub fn stub() -> Self {
        Self {
            per_core: vec![42.0, 18.0, 75.0, 5.0],
            aggregate: 35.0,
            frequency: vec![3400, 3400, 3400, 3400],
            cpu_brand: "Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz".into(),
            #[cfg(target_os = "linux")]
            temperature: Some(62.0),
            #[cfg(target_os = "linux")]
            physical_core_count: Some(4),
            #[cfg(target_os = "linux")]
            governor: Some("powersave".into()),
        }
    }
}

#[derive(Debug, Clone)]
pub struct MemSnapshot {
    pub ram_used: u64,
    pub ram_total: u64,
    pub swap_used: u64,
    pub swap_total: u64,
    #[cfg(target_os = "linux")]
    pub swap_in_bytes: u64,
    #[cfg(target_os = "linux")]
    pub swap_out_bytes: u64,
}

impl MemSnapshot {
    pub fn stub() -> Self {
        Self {
            ram_used: 6_442_450_944,
            ram_total: 17_179_869_184,
            swap_used: 0,
            swap_total: 4_294_967_296,
            #[cfg(target_os = "linux")]
            swap_in_bytes: 0,
            #[cfg(target_os = "linux")]
            swap_out_bytes: 0,
        }
    }
}

#[derive(Debug, Clone)]
pub struct InterfaceSnapshot {
    pub name: String,
    pub rx_bytes: u64,       // bytes/s since last tick
    pub tx_bytes: u64,       // bytes/s since last tick
    pub rx_packets: u64,     // packets/s since last tick
    pub tx_packets: u64,     // packets/s since last tick
    pub rx_errors: u64,      // errors since last tick
    pub tx_errors: u64,      // errors since last tick
    pub total_rx_bytes: u64, // cumulative since boot
    pub total_tx_bytes: u64, // cumulative since boot
    pub mac_address: String,
    pub ip_addresses: Vec<String>, // e.g. ["192.168.1.1/24", "fe80::1/64"]
    pub mtu: u64,
    #[cfg(target_os = "linux")]
    pub rx_dropped: u64, // cumulative drops from /proc/net/dev
    #[cfg(target_os = "linux")]
    pub tx_dropped: u64,
}

#[derive(Debug, Clone)]
pub struct NetSnapshot {
    pub interfaces: Vec<InterfaceSnapshot>,
}

impl NetSnapshot {
    pub fn stub() -> Self {
        Self {
            interfaces: vec![InterfaceSnapshot {
                name: "eth0".into(),
                rx_bytes: 4_800_000,
                tx_bytes: 1_200_000,
                rx_packets: 3_200,
                tx_packets: 850,
                rx_errors: 0,
                tx_errors: 0,
                total_rx_bytes: 48_318_382_080,
                total_tx_bytes: 12_884_901_888,
                mac_address: "aa:bb:cc:dd:ee:ff".into(),
                ip_addresses: vec!["192.168.1.100/24".into(), "fe80::1/64".into()],
                mtu: 1500,
                #[cfg(target_os = "linux")]
                rx_dropped: 0,
                #[cfg(target_os = "linux")]
                tx_dropped: 0,
            }],
        }
    }
}

#[derive(Debug, Clone)]
pub struct DiskDeviceSnapshot {
    pub name: String,
    pub read_bytes: u64,        // bytes/s since last tick
    pub write_bytes: u64,       // bytes/s since last tick
    pub usage_pct: f32,         // 0.0–100.0
    pub total_read_bytes: u64,  // cumulative since boot
    pub total_write_bytes: u64, // cumulative since boot
    pub kind: String,           // "SSD", "HDD", "Unknown"
    pub file_system: String,    // e.g. "ext4", "btrfs"
    pub mount_point: String,    // e.g. "/", "/boot"
    pub is_removable: bool,
    pub is_read_only: bool,
    pub total_space: u64,     // bytes
    pub available_space: u64, // bytes
}

impl Default for DiskDeviceSnapshot {
    fn default() -> Self {
        Self {
            name: String::new(),
            read_bytes: 0,
            write_bytes: 0,
            usage_pct: 0.0,
            total_read_bytes: 0,
            total_write_bytes: 0,
            kind: String::new(),
            file_system: String::new(),
            mount_point: String::new(),
            is_removable: false,
            is_read_only: false,
            total_space: 0,
            available_space: 0,
        }
    }
}

#[derive(Debug, Clone)]
pub struct DiskSnapshot {
    pub devices: Vec<DiskDeviceSnapshot>,
}

impl DiskSnapshot {
    pub fn stub() -> Self {
        Self {
            devices: vec![DiskDeviceSnapshot {
                name: "sda".into(),
                read_bytes: 0,
                write_bytes: 102_400,
                usage_pct: 45.0,
                total_read_bytes: 1_073_741_824,
                total_write_bytes: 536_870_912,
                kind: "SSD".into(),
                file_system: "ext4".into(),
                mount_point: "/".into(),
                is_removable: false,
                is_read_only: false,
                total_space: 500_107_862_016,
                available_space: 275_059_200_000,
            }],
        }
    }
}

#[derive(Debug, Clone)]
pub struct SysSnapshot {
    pub hostname: String,
    pub uptime: u64,        // seconds
    pub load_avg: [f64; 3], // 1m, 5m, 15m
    pub timestamp: chrono::DateTime<chrono::Local>,
}

impl SysSnapshot {
    pub fn stub() -> Self {
        Self {
            hostname: "dev-box".into(),
            uptime: 273_600,
            load_avg: [1.24, 0.98, 0.87],
            timestamp: chrono::Local::now(),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProcessStatus {
    Running,
    Sleeping,
    Idle,
    Stopped,
    Zombie,
    Dead,
    Unknown,
}

impl std::fmt::Display for ProcessStatus {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ProcessStatus::Running => write!(f, "running"),
            ProcessStatus::Sleeping => write!(f, "sleeping"),
            ProcessStatus::Idle => write!(f, "idle"),
            ProcessStatus::Stopped => write!(f, "stopped"),
            ProcessStatus::Zombie => write!(f, "zombie"),
            ProcessStatus::Dead => write!(f, "dead"),
            ProcessStatus::Unknown => write!(f, "unknown"),
        }
    }
}

#[derive(Debug, Clone)]
pub struct ProcessEntry {
    pub pid: u32,
    pub name: String,
    pub cmd: Vec<String>,
    pub user: String,
    pub cpu_pct: f32,
    pub mem_bytes: u64,
    pub mem_pct: f32,
    pub virt_bytes: u64,
    pub status: ProcessStatus,
    pub start_time: u64, // unix timestamp
    pub run_time: u64,   // seconds
    pub nice: i32,
    pub threads: u32,
    pub read_bytes: u64,
    pub write_bytes: u64,
    pub parent_pid: Option<u32>,
    /// Kernel raw priority from /proc/<pid>/stat field 18.
    /// For normal processes: 0–39 (20 = nice 0). Negative = RT process.
    pub priority: i32,
    /// Shared memory in bytes (SHR) from /proc/<pid>/statm field 3 × page_size.
    pub shr_bytes: u64,
    /// Total CPU time in seconds: (utime + stime) / ticks_per_second.
    pub cpu_time_secs: f64,
}

#[derive(Debug, Clone)]
pub struct ProcSnapshot {
    pub processes: Vec<ProcessEntry>,
}

impl ProcSnapshot {
    pub fn stub() -> Self {
        Self {
            processes: vec![ProcessEntry {
                pid: 12345,
                name: "firefox".into(),
                cmd: vec!["firefox".into()],
                user: "ray".into(),
                cpu_pct: 18.4,
                mem_bytes: 536_870_912,
                mem_pct: 3.2,
                virt_bytes: 2_147_483_648,
                status: ProcessStatus::Running,
                start_time: 0,
                run_time: 3600,
                nice: -5,
                threads: 42,
                read_bytes: 0,
                write_bytes: 0,
                parent_pid: Some(1),
                priority: 15,
                shr_bytes: 134_217_728,
                cpu_time_secs: 123.4,
            }],
        }
    }
}

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

    #[test]
    fn cpu_snapshot_stub_has_expected_shape() {
        let s = CpuSnapshot::stub();
        assert!(!s.per_core.is_empty());
        assert!(s.aggregate >= 0.0 && s.aggregate <= 100.0);
    }

    #[test]
    fn mem_snapshot_used_never_exceeds_total() {
        let s = MemSnapshot::stub();
        assert!(s.ram_used <= s.ram_total);
        assert!(s.swap_used <= s.swap_total);
    }
}
